diff --git a/google/cloud/firestore_admin_v1/gapic_metadata.json b/google/cloud/firestore_admin_v1/gapic_metadata.json index 73f37c4180..f036e7a6c1 100644 --- a/google/cloud/firestore_admin_v1/gapic_metadata.json +++ b/google/cloud/firestore_admin_v1/gapic_metadata.json @@ -10,6 +10,11 @@ "grpc": { "libraryClient": "FirestoreAdminClient", "rpcs": { + "BulkDeleteDocuments": { + "methods": [ + "bulk_delete_documents" + ] + }, "CreateBackupSchedule": { "methods": [ "create_backup_schedule" @@ -130,6 +135,11 @@ "grpc-async": { "libraryClient": "FirestoreAdminAsyncClient", "rpcs": { + "BulkDeleteDocuments": { + "methods": [ + "bulk_delete_documents" + ] + }, "CreateBackupSchedule": { "methods": [ "create_backup_schedule" @@ -250,6 +260,11 @@ "rest": { "libraryClient": "FirestoreAdminClient", "rpcs": { + "BulkDeleteDocuments": { + "methods": [ + "bulk_delete_documents" + ] + }, "CreateBackupSchedule": { "methods": [ "create_backup_schedule" diff --git a/google/cloud/firestore_admin_v1/services/firestore_admin/async_client.py b/google/cloud/firestore_admin_v1/services/firestore_admin/async_client.py index d04c3abb30..34a30d378c 100644 --- a/google/cloud/firestore_admin_v1/services/firestore_admin/async_client.py +++ b/google/cloud/firestore_admin_v1/services/firestore_admin/async_client.py @@ -14,10 +14,10 @@ # limitations under the License. # from collections import OrderedDict -import functools import re from typing import ( Dict, + Callable, Mapping, MutableMapping, MutableSequence, @@ -37,6 +37,7 @@ from google.auth import credentials as ga_credentials # type: ignore from google.oauth2 import service_account # type: ignore + try: OptionalRetry = Union[retries.AsyncRetry, gapic_v1.method._MethodDefault, None] except AttributeError: # pragma: NO COVER @@ -249,15 +250,15 @@ def universe_domain(self) -> str: """ return self._client._universe_domain - get_transport_class = functools.partial( - type(FirestoreAdminClient).get_transport_class, type(FirestoreAdminClient) - ) + get_transport_class = FirestoreAdminClient.get_transport_class def __init__( self, *, credentials: Optional[ga_credentials.Credentials] = None, - transport: Union[str, FirestoreAdminTransport] = "grpc_asyncio", + transport: Optional[ + Union[str, FirestoreAdminTransport, Callable[..., FirestoreAdminTransport]] + ] = "grpc_asyncio", client_options: Optional[ClientOptions] = None, client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, ) -> None: @@ -269,9 +270,11 @@ def __init__( credentials identify the application to the service; if none are specified, the client will attempt to ascertain the credentials from the environment. - transport (Union[str, ~.FirestoreAdminTransport]): The - transport to use. If set to None, a transport is chosen - automatically. + transport (Optional[Union[str,FirestoreAdminTransport,Callable[..., FirestoreAdminTransport]]]): + The transport to use, or a Callable that constructs and returns a new transport to use. + If a Callable is given, it will be called with the same set of initialization + arguments as used in the FirestoreAdminTransport constructor. + If set to None, a transport is chosen automatically. client_options (Optional[Union[google.api_core.client_options.ClientOptions, dict]]): Custom options for the client. @@ -394,8 +397,8 @@ async def sample_create_index(): """ # Create or coerce a protobuf request object. - # Quick check: If we got a request object, we should *not* have - # gotten any keyword arguments that map to the request. + # - Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. has_flattened_params = any([parent, index]) if request is not None and has_flattened_params: raise ValueError( @@ -403,7 +406,10 @@ async def sample_create_index(): "the individual field arguments should be set." ) - request = firestore_admin.CreateIndexRequest(request) + # - Use the request object if provided (there's no risk of modifying the input as + # there are no flattened fields), or create one. + if not isinstance(request, firestore_admin.CreateIndexRequest): + request = firestore_admin.CreateIndexRequest(request) # If we have keyword arguments corresponding to fields on the # request, apply these. @@ -414,11 +420,9 @@ async def sample_create_index(): # Wrap the RPC method; this adds retry and timeout information, # and friendly error handling. - rpc = gapic_v1.method_async.wrap_method( - self._client._transport.create_index, - default_timeout=60.0, - client_info=DEFAULT_CLIENT_INFO, - ) + rpc = self._client._transport._wrapped_methods[ + self._client._transport.create_index + ] # Certain fields should be provided within the metadata header; # add these here. @@ -513,8 +517,8 @@ async def sample_list_indexes(): """ # Create or coerce a protobuf request object. - # Quick check: If we got a request object, we should *not* have - # gotten any keyword arguments that map to the request. + # - Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. has_flattened_params = any([parent]) if request is not None and has_flattened_params: raise ValueError( @@ -522,7 +526,10 @@ async def sample_list_indexes(): "the individual field arguments should be set." ) - request = firestore_admin.ListIndexesRequest(request) + # - Use the request object if provided (there's no risk of modifying the input as + # there are no flattened fields), or create one. + if not isinstance(request, firestore_admin.ListIndexesRequest): + request = firestore_admin.ListIndexesRequest(request) # If we have keyword arguments corresponding to fields on the # request, apply these. @@ -531,22 +538,9 @@ async def sample_list_indexes(): # Wrap the RPC method; this adds retry and timeout information, # and friendly error handling. - rpc = gapic_v1.method_async.wrap_method( - self._client._transport.list_indexes, - default_retry=retries.AsyncRetry( - initial=0.1, - maximum=60.0, - multiplier=1.3, - predicate=retries.if_exception_type( - core_exceptions.DeadlineExceeded, - core_exceptions.InternalServerError, - core_exceptions.ServiceUnavailable, - ), - deadline=60.0, - ), - default_timeout=60.0, - client_info=DEFAULT_CLIENT_INFO, - ) + rpc = self._client._transport._wrapped_methods[ + self._client._transport.list_indexes + ] # Certain fields should be provided within the metadata header; # add these here. @@ -571,6 +565,8 @@ async def sample_list_indexes(): method=rpc, request=request, response=response, + retry=retry, + timeout=timeout, metadata=metadata, ) @@ -639,8 +635,8 @@ async def sample_get_index(): """ # Create or coerce a protobuf request object. - # Quick check: If we got a request object, we should *not* have - # gotten any keyword arguments that map to the request. + # - Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. has_flattened_params = any([name]) if request is not None and has_flattened_params: raise ValueError( @@ -648,7 +644,10 @@ async def sample_get_index(): "the individual field arguments should be set." ) - request = firestore_admin.GetIndexRequest(request) + # - Use the request object if provided (there's no risk of modifying the input as + # there are no flattened fields), or create one. + if not isinstance(request, firestore_admin.GetIndexRequest): + request = firestore_admin.GetIndexRequest(request) # If we have keyword arguments corresponding to fields on the # request, apply these. @@ -657,22 +656,9 @@ async def sample_get_index(): # Wrap the RPC method; this adds retry and timeout information, # and friendly error handling. - rpc = gapic_v1.method_async.wrap_method( - self._client._transport.get_index, - default_retry=retries.AsyncRetry( - initial=0.1, - maximum=60.0, - multiplier=1.3, - predicate=retries.if_exception_type( - core_exceptions.DeadlineExceeded, - core_exceptions.InternalServerError, - core_exceptions.ServiceUnavailable, - ), - deadline=60.0, - ), - default_timeout=60.0, - client_info=DEFAULT_CLIENT_INFO, - ) + rpc = self._client._transport._wrapped_methods[ + self._client._transport.get_index + ] # Certain fields should be provided within the metadata header; # add these here. @@ -746,8 +732,8 @@ async def sample_delete_index(): sent along with the request as metadata. """ # Create or coerce a protobuf request object. - # Quick check: If we got a request object, we should *not* have - # gotten any keyword arguments that map to the request. + # - Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. has_flattened_params = any([name]) if request is not None and has_flattened_params: raise ValueError( @@ -755,7 +741,10 @@ async def sample_delete_index(): "the individual field arguments should be set." ) - request = firestore_admin.DeleteIndexRequest(request) + # - Use the request object if provided (there's no risk of modifying the input as + # there are no flattened fields), or create one. + if not isinstance(request, firestore_admin.DeleteIndexRequest): + request = firestore_admin.DeleteIndexRequest(request) # If we have keyword arguments corresponding to fields on the # request, apply these. @@ -764,22 +753,9 @@ async def sample_delete_index(): # Wrap the RPC method; this adds retry and timeout information, # and friendly error handling. - rpc = gapic_v1.method_async.wrap_method( - self._client._transport.delete_index, - default_retry=retries.AsyncRetry( - initial=0.1, - maximum=60.0, - multiplier=1.3, - predicate=retries.if_exception_type( - core_exceptions.DeadlineExceeded, - core_exceptions.InternalServerError, - core_exceptions.ServiceUnavailable, - ), - deadline=60.0, - ), - default_timeout=60.0, - client_info=DEFAULT_CLIENT_INFO, - ) + rpc = self._client._transport._wrapped_methods[ + self._client._transport.delete_index + ] # Certain fields should be provided within the metadata header; # add these here. @@ -862,8 +838,8 @@ async def sample_get_field(): """ # Create or coerce a protobuf request object. - # Quick check: If we got a request object, we should *not* have - # gotten any keyword arguments that map to the request. + # - Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. has_flattened_params = any([name]) if request is not None and has_flattened_params: raise ValueError( @@ -871,7 +847,10 @@ async def sample_get_field(): "the individual field arguments should be set." ) - request = firestore_admin.GetFieldRequest(request) + # - Use the request object if provided (there's no risk of modifying the input as + # there are no flattened fields), or create one. + if not isinstance(request, firestore_admin.GetFieldRequest): + request = firestore_admin.GetFieldRequest(request) # If we have keyword arguments corresponding to fields on the # request, apply these. @@ -880,22 +859,9 @@ async def sample_get_field(): # Wrap the RPC method; this adds retry and timeout information, # and friendly error handling. - rpc = gapic_v1.method_async.wrap_method( - self._client._transport.get_field, - default_retry=retries.AsyncRetry( - initial=0.1, - maximum=60.0, - multiplier=1.3, - predicate=retries.if_exception_type( - core_exceptions.DeadlineExceeded, - core_exceptions.InternalServerError, - core_exceptions.ServiceUnavailable, - ), - deadline=60.0, - ), - default_timeout=60.0, - client_info=DEFAULT_CLIENT_INFO, - ) + rpc = self._client._transport._wrapped_methods[ + self._client._transport.get_field + ] # Certain fields should be provided within the metadata header; # add these here. @@ -1005,8 +971,8 @@ async def sample_update_field(): """ # Create or coerce a protobuf request object. - # Quick check: If we got a request object, we should *not* have - # gotten any keyword arguments that map to the request. + # - Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. has_flattened_params = any([field]) if request is not None and has_flattened_params: raise ValueError( @@ -1014,7 +980,10 @@ async def sample_update_field(): "the individual field arguments should be set." ) - request = firestore_admin.UpdateFieldRequest(request) + # - Use the request object if provided (there's no risk of modifying the input as + # there are no flattened fields), or create one. + if not isinstance(request, firestore_admin.UpdateFieldRequest): + request = firestore_admin.UpdateFieldRequest(request) # If we have keyword arguments corresponding to fields on the # request, apply these. @@ -1023,11 +992,9 @@ async def sample_update_field(): # Wrap the RPC method; this adds retry and timeout information, # and friendly error handling. - rpc = gapic_v1.method_async.wrap_method( - self._client._transport.update_field, - default_timeout=60.0, - client_info=DEFAULT_CLIENT_INFO, - ) + rpc = self._client._transport._wrapped_methods[ + self._client._transport.update_field + ] # Certain fields should be provided within the metadata header; # add these here. @@ -1132,8 +1099,8 @@ async def sample_list_fields(): """ # Create or coerce a protobuf request object. - # Quick check: If we got a request object, we should *not* have - # gotten any keyword arguments that map to the request. + # - Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. has_flattened_params = any([parent]) if request is not None and has_flattened_params: raise ValueError( @@ -1141,7 +1108,10 @@ async def sample_list_fields(): "the individual field arguments should be set." ) - request = firestore_admin.ListFieldsRequest(request) + # - Use the request object if provided (there's no risk of modifying the input as + # there are no flattened fields), or create one. + if not isinstance(request, firestore_admin.ListFieldsRequest): + request = firestore_admin.ListFieldsRequest(request) # If we have keyword arguments corresponding to fields on the # request, apply these. @@ -1150,22 +1120,9 @@ async def sample_list_fields(): # Wrap the RPC method; this adds retry and timeout information, # and friendly error handling. - rpc = gapic_v1.method_async.wrap_method( - self._client._transport.list_fields, - default_retry=retries.AsyncRetry( - initial=0.1, - maximum=60.0, - multiplier=1.3, - predicate=retries.if_exception_type( - core_exceptions.DeadlineExceeded, - core_exceptions.InternalServerError, - core_exceptions.ServiceUnavailable, - ), - deadline=60.0, - ), - default_timeout=60.0, - client_info=DEFAULT_CLIENT_INFO, - ) + rpc = self._client._transport._wrapped_methods[ + self._client._transport.list_fields + ] # Certain fields should be provided within the metadata header; # add these here. @@ -1190,6 +1147,8 @@ async def sample_list_fields(): method=rpc, request=request, response=response, + retry=retry, + timeout=timeout, metadata=metadata, ) @@ -1277,8 +1236,8 @@ async def sample_export_documents(): """ # Create or coerce a protobuf request object. - # Quick check: If we got a request object, we should *not* have - # gotten any keyword arguments that map to the request. + # - Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. has_flattened_params = any([name]) if request is not None and has_flattened_params: raise ValueError( @@ -1286,7 +1245,10 @@ async def sample_export_documents(): "the individual field arguments should be set." ) - request = firestore_admin.ExportDocumentsRequest(request) + # - Use the request object if provided (there's no risk of modifying the input as + # there are no flattened fields), or create one. + if not isinstance(request, firestore_admin.ExportDocumentsRequest): + request = firestore_admin.ExportDocumentsRequest(request) # If we have keyword arguments corresponding to fields on the # request, apply these. @@ -1295,11 +1257,9 @@ async def sample_export_documents(): # Wrap the RPC method; this adds retry and timeout information, # and friendly error handling. - rpc = gapic_v1.method_async.wrap_method( - self._client._transport.export_documents, - default_timeout=60.0, - client_info=DEFAULT_CLIENT_INFO, - ) + rpc = self._client._transport._wrapped_methods[ + self._client._transport.export_documents + ] # Certain fields should be provided within the metadata header; # add these here. @@ -1410,8 +1370,8 @@ async def sample_import_documents(): """ # Create or coerce a protobuf request object. - # Quick check: If we got a request object, we should *not* have - # gotten any keyword arguments that map to the request. + # - Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. has_flattened_params = any([name]) if request is not None and has_flattened_params: raise ValueError( @@ -1419,7 +1379,10 @@ async def sample_import_documents(): "the individual field arguments should be set." ) - request = firestore_admin.ImportDocumentsRequest(request) + # - Use the request object if provided (there's no risk of modifying the input as + # there are no flattened fields), or create one. + if not isinstance(request, firestore_admin.ImportDocumentsRequest): + request = firestore_admin.ImportDocumentsRequest(request) # If we have keyword arguments corresponding to fields on the # request, apply these. @@ -1428,11 +1391,9 @@ async def sample_import_documents(): # Wrap the RPC method; this adds retry and timeout information, # and friendly error handling. - rpc = gapic_v1.method_async.wrap_method( - self._client._transport.import_documents, - default_timeout=60.0, - client_info=DEFAULT_CLIENT_INFO, - ) + rpc = self._client._transport._wrapped_methods[ + self._client._transport.import_documents + ] # Certain fields should be provided within the metadata header; # add these here. @@ -1462,6 +1423,145 @@ async def sample_import_documents(): # Done; return the response. return response + async def bulk_delete_documents( + self, + request: Optional[ + Union[firestore_admin.BulkDeleteDocumentsRequest, dict] + ] = None, + *, + name: Optional[str] = None, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Union[float, object] = gapic_v1.method.DEFAULT, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operation_async.AsyncOperation: + r"""Bulk deletes a subset of documents from Google Cloud + Firestore. Documents created or updated after the + underlying system starts to process the request will not + be deleted. The bulk delete occurs in the background and + its progress can be monitored and managed via the + Operation resource that is created. + + For more details on bulk delete behavior, refer to: + + https://cloud.google.com/firestore/docs/manage-data/bulk-delete + + .. code-block:: python + + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html + from google.cloud import firestore_admin_v1 + + async def sample_bulk_delete_documents(): + # Create a client + client = firestore_admin_v1.FirestoreAdminAsyncClient() + + # Initialize request argument(s) + request = firestore_admin_v1.BulkDeleteDocumentsRequest( + name="name_value", + ) + + # Make the request + operation = client.bulk_delete_documents(request=request) + + print("Waiting for operation to complete...") + + response = (await operation).result() + + # Handle the response + print(response) + + Args: + request (Optional[Union[google.cloud.firestore_admin_v1.types.BulkDeleteDocumentsRequest, dict]]): + The request object. The request for + [FirestoreAdmin.BulkDeleteDocuments][google.firestore.admin.v1.FirestoreAdmin.BulkDeleteDocuments]. + + When both collection_ids and namespace_ids are set, only + documents satisfying both conditions will be deleted. + + Requests with namespace_ids and collection_ids both + empty will be rejected. Please use + [FirestoreAdmin.DeleteDatabase][google.firestore.admin.v1.FirestoreAdmin.DeleteDatabase] + instead. + name (:class:`str`): + Required. Database to operate. Should be of the form: + ``projects/{project_id}/databases/{database_id}``. + + This corresponds to the ``name`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry_async.AsyncRetry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.api_core.operation_async.AsyncOperation: + An object representing a long-running operation. + + The result type for the operation will be :class:`google.cloud.firestore_admin_v1.types.BulkDeleteDocumentsResponse` The response for + [FirestoreAdmin.BulkDeleteDocuments][google.firestore.admin.v1.FirestoreAdmin.BulkDeleteDocuments]. + + """ + # Create or coerce a protobuf request object. + # - Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([name]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + # - Use the request object if provided (there's no risk of modifying the input as + # there are no flattened fields), or create one. + if not isinstance(request, firestore_admin.BulkDeleteDocumentsRequest): + request = firestore_admin.BulkDeleteDocumentsRequest(request) + + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if name is not None: + request.name = name + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._client._transport._wrapped_methods[ + self._client._transport.bulk_delete_documents + ] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), + ) + + # Validate the universe domain. + self._client._validate_universe_domain() + + # Send the request. + response = await rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Wrap the response in an operation future. + response = operation_async.from_gapic( + response, + self._client._transport.operations_client, + firestore_admin.BulkDeleteDocumentsResponse, + metadata_type=gfa_operation.BulkDeleteDocumentsMetadata, + ) + + # Done; return the response. + return response + async def create_database( self, request: Optional[Union[firestore_admin.CreateDatabaseRequest, dict]] = None, @@ -1553,8 +1653,8 @@ async def sample_create_database(): """ # Create or coerce a protobuf request object. - # Quick check: If we got a request object, we should *not* have - # gotten any keyword arguments that map to the request. + # - Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. has_flattened_params = any([parent, database, database_id]) if request is not None and has_flattened_params: raise ValueError( @@ -1562,7 +1662,10 @@ async def sample_create_database(): "the individual field arguments should be set." ) - request = firestore_admin.CreateDatabaseRequest(request) + # - Use the request object if provided (there's no risk of modifying the input as + # there are no flattened fields), or create one. + if not isinstance(request, firestore_admin.CreateDatabaseRequest): + request = firestore_admin.CreateDatabaseRequest(request) # If we have keyword arguments corresponding to fields on the # request, apply these. @@ -1575,11 +1678,9 @@ async def sample_create_database(): # Wrap the RPC method; this adds retry and timeout information, # and friendly error handling. - rpc = gapic_v1.method_async.wrap_method( - self._client._transport.create_database, - default_timeout=None, - client_info=DEFAULT_CLIENT_INFO, - ) + rpc = self._client._transport._wrapped_methods[ + self._client._transport.create_database + ] # Certain fields should be provided within the metadata header; # add these here. @@ -1668,8 +1769,8 @@ async def sample_get_database(): A Cloud Firestore Database. """ # Create or coerce a protobuf request object. - # Quick check: If we got a request object, we should *not* have - # gotten any keyword arguments that map to the request. + # - Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. has_flattened_params = any([name]) if request is not None and has_flattened_params: raise ValueError( @@ -1677,7 +1778,10 @@ async def sample_get_database(): "the individual field arguments should be set." ) - request = firestore_admin.GetDatabaseRequest(request) + # - Use the request object if provided (there's no risk of modifying the input as + # there are no flattened fields), or create one. + if not isinstance(request, firestore_admin.GetDatabaseRequest): + request = firestore_admin.GetDatabaseRequest(request) # If we have keyword arguments corresponding to fields on the # request, apply these. @@ -1686,11 +1790,9 @@ async def sample_get_database(): # Wrap the RPC method; this adds retry and timeout information, # and friendly error handling. - rpc = gapic_v1.method_async.wrap_method( - self._client._transport.get_database, - default_timeout=None, - client_info=DEFAULT_CLIENT_INFO, - ) + rpc = self._client._transport._wrapped_methods[ + self._client._transport.get_database + ] # Certain fields should be provided within the metadata header; # add these here. @@ -1772,8 +1874,8 @@ async def sample_list_databases(): The list of databases for a project. """ # Create or coerce a protobuf request object. - # Quick check: If we got a request object, we should *not* have - # gotten any keyword arguments that map to the request. + # - Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. has_flattened_params = any([parent]) if request is not None and has_flattened_params: raise ValueError( @@ -1781,7 +1883,10 @@ async def sample_list_databases(): "the individual field arguments should be set." ) - request = firestore_admin.ListDatabasesRequest(request) + # - Use the request object if provided (there's no risk of modifying the input as + # there are no flattened fields), or create one. + if not isinstance(request, firestore_admin.ListDatabasesRequest): + request = firestore_admin.ListDatabasesRequest(request) # If we have keyword arguments corresponding to fields on the # request, apply these. @@ -1790,11 +1895,9 @@ async def sample_list_databases(): # Wrap the RPC method; this adds retry and timeout information, # and friendly error handling. - rpc = gapic_v1.method_async.wrap_method( - self._client._transport.list_databases, - default_timeout=None, - client_info=DEFAULT_CLIENT_INFO, - ) + rpc = self._client._transport._wrapped_methods[ + self._client._transport.list_databases + ] # Certain fields should be provided within the metadata header; # add these here. @@ -1887,8 +1990,8 @@ async def sample_update_database(): """ # Create or coerce a protobuf request object. - # Quick check: If we got a request object, we should *not* have - # gotten any keyword arguments that map to the request. + # - Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. has_flattened_params = any([database, update_mask]) if request is not None and has_flattened_params: raise ValueError( @@ -1896,7 +1999,10 @@ async def sample_update_database(): "the individual field arguments should be set." ) - request = firestore_admin.UpdateDatabaseRequest(request) + # - Use the request object if provided (there's no risk of modifying the input as + # there are no flattened fields), or create one. + if not isinstance(request, firestore_admin.UpdateDatabaseRequest): + request = firestore_admin.UpdateDatabaseRequest(request) # If we have keyword arguments corresponding to fields on the # request, apply these. @@ -1907,11 +2013,9 @@ async def sample_update_database(): # Wrap the RPC method; this adds retry and timeout information, # and friendly error handling. - rpc = gapic_v1.method_async.wrap_method( - self._client._transport.update_database, - default_timeout=None, - client_info=DEFAULT_CLIENT_INFO, - ) + rpc = self._client._transport._wrapped_methods[ + self._client._transport.update_database + ] # Certain fields should be provided within the metadata header; # add these here. @@ -2011,8 +2115,8 @@ async def sample_delete_database(): """ # Create or coerce a protobuf request object. - # Quick check: If we got a request object, we should *not* have - # gotten any keyword arguments that map to the request. + # - Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. has_flattened_params = any([name]) if request is not None and has_flattened_params: raise ValueError( @@ -2020,7 +2124,10 @@ async def sample_delete_database(): "the individual field arguments should be set." ) - request = firestore_admin.DeleteDatabaseRequest(request) + # - Use the request object if provided (there's no risk of modifying the input as + # there are no flattened fields), or create one. + if not isinstance(request, firestore_admin.DeleteDatabaseRequest): + request = firestore_admin.DeleteDatabaseRequest(request) # If we have keyword arguments corresponding to fields on the # request, apply these. @@ -2029,11 +2136,9 @@ async def sample_delete_database(): # Wrap the RPC method; this adds retry and timeout information, # and friendly error handling. - rpc = gapic_v1.method_async.wrap_method( - self._client._transport.delete_database, - default_timeout=None, - client_info=DEFAULT_CLIENT_INFO, - ) + rpc = self._client._transport._wrapped_methods[ + self._client._transport.delete_database + ] # Certain fields should be provided within the metadata header; # add these here. @@ -2129,8 +2234,8 @@ async def sample_get_backup(): """ # Create or coerce a protobuf request object. - # Quick check: If we got a request object, we should *not* have - # gotten any keyword arguments that map to the request. + # - Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. has_flattened_params = any([name]) if request is not None and has_flattened_params: raise ValueError( @@ -2138,7 +2243,10 @@ async def sample_get_backup(): "the individual field arguments should be set." ) - request = firestore_admin.GetBackupRequest(request) + # - Use the request object if provided (there's no risk of modifying the input as + # there are no flattened fields), or create one. + if not isinstance(request, firestore_admin.GetBackupRequest): + request = firestore_admin.GetBackupRequest(request) # If we have keyword arguments corresponding to fields on the # request, apply these. @@ -2147,11 +2255,9 @@ async def sample_get_backup(): # Wrap the RPC method; this adds retry and timeout information, # and friendly error handling. - rpc = gapic_v1.method_async.wrap_method( - self._client._transport.get_backup, - default_timeout=None, - client_info=DEFAULT_CLIENT_INFO, - ) + rpc = self._client._transport._wrapped_methods[ + self._client._transport.get_backup + ] # Certain fields should be provided within the metadata header; # add these here. @@ -2238,8 +2344,8 @@ async def sample_list_backups(): """ # Create or coerce a protobuf request object. - # Quick check: If we got a request object, we should *not* have - # gotten any keyword arguments that map to the request. + # - Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. has_flattened_params = any([parent]) if request is not None and has_flattened_params: raise ValueError( @@ -2247,7 +2353,10 @@ async def sample_list_backups(): "the individual field arguments should be set." ) - request = firestore_admin.ListBackupsRequest(request) + # - Use the request object if provided (there's no risk of modifying the input as + # there are no flattened fields), or create one. + if not isinstance(request, firestore_admin.ListBackupsRequest): + request = firestore_admin.ListBackupsRequest(request) # If we have keyword arguments corresponding to fields on the # request, apply these. @@ -2256,11 +2365,9 @@ async def sample_list_backups(): # Wrap the RPC method; this adds retry and timeout information, # and friendly error handling. - rpc = gapic_v1.method_async.wrap_method( - self._client._transport.list_backups, - default_timeout=None, - client_info=DEFAULT_CLIENT_INFO, - ) + rpc = self._client._transport._wrapped_methods[ + self._client._transport.list_backups + ] # Certain fields should be provided within the metadata header; # add these here. @@ -2336,8 +2443,8 @@ async def sample_delete_backup(): sent along with the request as metadata. """ # Create or coerce a protobuf request object. - # Quick check: If we got a request object, we should *not* have - # gotten any keyword arguments that map to the request. + # - Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. has_flattened_params = any([name]) if request is not None and has_flattened_params: raise ValueError( @@ -2345,7 +2452,10 @@ async def sample_delete_backup(): "the individual field arguments should be set." ) - request = firestore_admin.DeleteBackupRequest(request) + # - Use the request object if provided (there's no risk of modifying the input as + # there are no flattened fields), or create one. + if not isinstance(request, firestore_admin.DeleteBackupRequest): + request = firestore_admin.DeleteBackupRequest(request) # If we have keyword arguments corresponding to fields on the # request, apply these. @@ -2354,11 +2464,9 @@ async def sample_delete_backup(): # Wrap the RPC method; this adds retry and timeout information, # and friendly error handling. - rpc = gapic_v1.method_async.wrap_method( - self._client._transport.delete_backup, - default_timeout=None, - client_info=DEFAULT_CLIENT_INFO, - ) + rpc = self._client._transport._wrapped_methods[ + self._client._transport.delete_backup + ] # Certain fields should be provided within the metadata header; # add these here. @@ -2390,7 +2498,7 @@ async def restore_database( The new database must be in the same cloud region or multi-region location as the existing backup. This behaves similar to - [FirestoreAdmin.CreateDatabase][google.firestore.admin.v1.CreateDatabase] + [FirestoreAdmin.CreateDatabase][google.firestore.admin.v1.FirestoreAdmin.CreateDatabase] except instead of creating a new empty database, a new database is created with the database type, index configuration, and documents from an existing backup. @@ -2457,15 +2565,16 @@ async def sample_restore_database(): """ # Create or coerce a protobuf request object. - request = firestore_admin.RestoreDatabaseRequest(request) + # - Use the request object if provided (there's no risk of modifying the input as + # there are no flattened fields), or create one. + if not isinstance(request, firestore_admin.RestoreDatabaseRequest): + request = firestore_admin.RestoreDatabaseRequest(request) # Wrap the RPC method; this adds retry and timeout information, # and friendly error handling. - rpc = gapic_v1.method_async.wrap_method( - self._client._transport.restore_database, - default_timeout=None, - client_info=DEFAULT_CLIENT_INFO, - ) + rpc = self._client._transport._wrapped_methods[ + self._client._transport.restore_database + ] # Certain fields should be provided within the metadata header; # add these here. @@ -2574,8 +2683,8 @@ async def sample_create_backup_schedule(): """ # Create or coerce a protobuf request object. - # Quick check: If we got a request object, we should *not* have - # gotten any keyword arguments that map to the request. + # - Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. has_flattened_params = any([parent, backup_schedule]) if request is not None and has_flattened_params: raise ValueError( @@ -2583,7 +2692,10 @@ async def sample_create_backup_schedule(): "the individual field arguments should be set." ) - request = firestore_admin.CreateBackupScheduleRequest(request) + # - Use the request object if provided (there's no risk of modifying the input as + # there are no flattened fields), or create one. + if not isinstance(request, firestore_admin.CreateBackupScheduleRequest): + request = firestore_admin.CreateBackupScheduleRequest(request) # If we have keyword arguments corresponding to fields on the # request, apply these. @@ -2594,11 +2706,9 @@ async def sample_create_backup_schedule(): # Wrap the RPC method; this adds retry and timeout information, # and friendly error handling. - rpc = gapic_v1.method_async.wrap_method( - self._client._transport.create_backup_schedule, - default_timeout=None, - client_info=DEFAULT_CLIENT_INFO, - ) + rpc = self._client._transport._wrapped_methods[ + self._client._transport.create_backup_schedule + ] # Certain fields should be provided within the metadata header; # add these here. @@ -2687,8 +2797,8 @@ async def sample_get_backup_schedule(): """ # Create or coerce a protobuf request object. - # Quick check: If we got a request object, we should *not* have - # gotten any keyword arguments that map to the request. + # - Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. has_flattened_params = any([name]) if request is not None and has_flattened_params: raise ValueError( @@ -2696,7 +2806,10 @@ async def sample_get_backup_schedule(): "the individual field arguments should be set." ) - request = firestore_admin.GetBackupScheduleRequest(request) + # - Use the request object if provided (there's no risk of modifying the input as + # there are no flattened fields), or create one. + if not isinstance(request, firestore_admin.GetBackupScheduleRequest): + request = firestore_admin.GetBackupScheduleRequest(request) # If we have keyword arguments corresponding to fields on the # request, apply these. @@ -2705,11 +2818,9 @@ async def sample_get_backup_schedule(): # Wrap the RPC method; this adds retry and timeout information, # and friendly error handling. - rpc = gapic_v1.method_async.wrap_method( - self._client._transport.get_backup_schedule, - default_timeout=None, - client_info=DEFAULT_CLIENT_INFO, - ) + rpc = self._client._transport._wrapped_methods[ + self._client._transport.get_backup_schedule + ] # Certain fields should be provided within the metadata header; # add these here. @@ -2795,8 +2906,8 @@ async def sample_list_backup_schedules(): """ # Create or coerce a protobuf request object. - # Quick check: If we got a request object, we should *not* have - # gotten any keyword arguments that map to the request. + # - Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. has_flattened_params = any([parent]) if request is not None and has_flattened_params: raise ValueError( @@ -2804,7 +2915,10 @@ async def sample_list_backup_schedules(): "the individual field arguments should be set." ) - request = firestore_admin.ListBackupSchedulesRequest(request) + # - Use the request object if provided (there's no risk of modifying the input as + # there are no flattened fields), or create one. + if not isinstance(request, firestore_admin.ListBackupSchedulesRequest): + request = firestore_admin.ListBackupSchedulesRequest(request) # If we have keyword arguments corresponding to fields on the # request, apply these. @@ -2813,11 +2927,9 @@ async def sample_list_backup_schedules(): # Wrap the RPC method; this adds retry and timeout information, # and friendly error handling. - rpc = gapic_v1.method_async.wrap_method( - self._client._transport.list_backup_schedules, - default_timeout=None, - client_info=DEFAULT_CLIENT_INFO, - ) + rpc = self._client._transport._wrapped_methods[ + self._client._transport.list_backup_schedules + ] # Certain fields should be provided within the metadata header; # add these here. @@ -2911,8 +3023,8 @@ async def sample_update_backup_schedule(): """ # Create or coerce a protobuf request object. - # Quick check: If we got a request object, we should *not* have - # gotten any keyword arguments that map to the request. + # - Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. has_flattened_params = any([backup_schedule, update_mask]) if request is not None and has_flattened_params: raise ValueError( @@ -2920,7 +3032,10 @@ async def sample_update_backup_schedule(): "the individual field arguments should be set." ) - request = firestore_admin.UpdateBackupScheduleRequest(request) + # - Use the request object if provided (there's no risk of modifying the input as + # there are no flattened fields), or create one. + if not isinstance(request, firestore_admin.UpdateBackupScheduleRequest): + request = firestore_admin.UpdateBackupScheduleRequest(request) # If we have keyword arguments corresponding to fields on the # request, apply these. @@ -2931,11 +3046,9 @@ async def sample_update_backup_schedule(): # Wrap the RPC method; this adds retry and timeout information, # and friendly error handling. - rpc = gapic_v1.method_async.wrap_method( - self._client._transport.update_backup_schedule, - default_timeout=None, - client_info=DEFAULT_CLIENT_INFO, - ) + rpc = self._client._transport._wrapped_methods[ + self._client._transport.update_backup_schedule + ] # Certain fields should be provided within the metadata header; # add these here. @@ -3015,8 +3128,8 @@ async def sample_delete_backup_schedule(): sent along with the request as metadata. """ # Create or coerce a protobuf request object. - # Quick check: If we got a request object, we should *not* have - # gotten any keyword arguments that map to the request. + # - Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. has_flattened_params = any([name]) if request is not None and has_flattened_params: raise ValueError( @@ -3024,7 +3137,10 @@ async def sample_delete_backup_schedule(): "the individual field arguments should be set." ) - request = firestore_admin.DeleteBackupScheduleRequest(request) + # - Use the request object if provided (there's no risk of modifying the input as + # there are no flattened fields), or create one. + if not isinstance(request, firestore_admin.DeleteBackupScheduleRequest): + request = firestore_admin.DeleteBackupScheduleRequest(request) # If we have keyword arguments corresponding to fields on the # request, apply these. @@ -3033,11 +3149,9 @@ async def sample_delete_backup_schedule(): # Wrap the RPC method; this adds retry and timeout information, # and friendly error handling. - rpc = gapic_v1.method_async.wrap_method( - self._client._transport.delete_backup_schedule, - default_timeout=None, - client_info=DEFAULT_CLIENT_INFO, - ) + rpc = self._client._transport._wrapped_methods[ + self._client._transport.delete_backup_schedule + ] # Certain fields should be provided within the metadata header; # add these here. diff --git a/google/cloud/firestore_admin_v1/services/firestore_admin/client.py b/google/cloud/firestore_admin_v1/services/firestore_admin/client.py index d544c706a4..b7bcfd80a5 100644 --- a/google/cloud/firestore_admin_v1/services/firestore_admin/client.py +++ b/google/cloud/firestore_admin_v1/services/firestore_admin/client.py @@ -18,6 +18,7 @@ import re from typing import ( Dict, + Callable, Mapping, MutableMapping, MutableSequence, @@ -702,7 +703,9 @@ def __init__( self, *, credentials: Optional[ga_credentials.Credentials] = None, - transport: Optional[Union[str, FirestoreAdminTransport]] = None, + transport: Optional[ + Union[str, FirestoreAdminTransport, Callable[..., FirestoreAdminTransport]] + ] = None, client_options: Optional[Union[client_options_lib.ClientOptions, dict]] = None, client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, ) -> None: @@ -714,9 +717,11 @@ def __init__( credentials identify the application to the service; if none are specified, the client will attempt to ascertain the credentials from the environment. - transport (Union[str, FirestoreAdminTransport]): The - transport to use. If set to None, a transport is chosen - automatically. + transport (Optional[Union[str,FirestoreAdminTransport,Callable[..., FirestoreAdminTransport]]]): + The transport to use, or a Callable that constructs and returns a new transport. + If a Callable is given, it will be called with the same set of initialization + arguments as used in the FirestoreAdminTransport constructor. + If set to None, a transport is chosen automatically. client_options (Optional[Union[google.api_core.client_options.ClientOptions, dict]]): Custom options for the client. @@ -825,8 +830,15 @@ def __init__( api_key_value ) - Transport = type(self).get_transport_class(cast(str, transport)) - self._transport = Transport( + transport_init: Union[ + Type[FirestoreAdminTransport], Callable[..., FirestoreAdminTransport] + ] = ( + FirestoreAdminClient.get_transport_class(transport) + if isinstance(transport, str) or transport is None + else cast(Callable[..., FirestoreAdminTransport], transport) + ) + # initialize with the provided callable or the passed in class + self._transport = transport_init( credentials=credentials, credentials_file=self._client_options.credentials_file, host=self._api_endpoint, @@ -917,8 +929,8 @@ def sample_create_index(): """ # Create or coerce a protobuf request object. - # Quick check: If we got a request object, we should *not* have - # gotten any keyword arguments that map to the request. + # - Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. has_flattened_params = any([parent, index]) if request is not None and has_flattened_params: raise ValueError( @@ -926,10 +938,8 @@ def sample_create_index(): "the individual field arguments should be set." ) - # Minor optimization to avoid making a copy if the user passes - # in a firestore_admin.CreateIndexRequest. - # There's no risk of modifying the input as we've already verified - # there are no flattened fields. + # - Use the request object if provided (there's no risk of modifying the input as + # there are no flattened fields), or create one. if not isinstance(request, firestore_admin.CreateIndexRequest): request = firestore_admin.CreateIndexRequest(request) # If we have keyword arguments corresponding to fields on the @@ -1036,8 +1046,8 @@ def sample_list_indexes(): """ # Create or coerce a protobuf request object. - # Quick check: If we got a request object, we should *not* have - # gotten any keyword arguments that map to the request. + # - Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. has_flattened_params = any([parent]) if request is not None and has_flattened_params: raise ValueError( @@ -1045,10 +1055,8 @@ def sample_list_indexes(): "the individual field arguments should be set." ) - # Minor optimization to avoid making a copy if the user passes - # in a firestore_admin.ListIndexesRequest. - # There's no risk of modifying the input as we've already verified - # there are no flattened fields. + # - Use the request object if provided (there's no risk of modifying the input as + # there are no flattened fields), or create one. if not isinstance(request, firestore_admin.ListIndexesRequest): request = firestore_admin.ListIndexesRequest(request) # If we have keyword arguments corresponding to fields on the @@ -1083,6 +1091,8 @@ def sample_list_indexes(): method=rpc, request=request, response=response, + retry=retry, + timeout=timeout, metadata=metadata, ) @@ -1151,8 +1161,8 @@ def sample_get_index(): """ # Create or coerce a protobuf request object. - # Quick check: If we got a request object, we should *not* have - # gotten any keyword arguments that map to the request. + # - Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. has_flattened_params = any([name]) if request is not None and has_flattened_params: raise ValueError( @@ -1160,10 +1170,8 @@ def sample_get_index(): "the individual field arguments should be set." ) - # Minor optimization to avoid making a copy if the user passes - # in a firestore_admin.GetIndexRequest. - # There's no risk of modifying the input as we've already verified - # there are no flattened fields. + # - Use the request object if provided (there's no risk of modifying the input as + # there are no flattened fields), or create one. if not isinstance(request, firestore_admin.GetIndexRequest): request = firestore_admin.GetIndexRequest(request) # If we have keyword arguments corresponding to fields on the @@ -1247,8 +1255,8 @@ def sample_delete_index(): sent along with the request as metadata. """ # Create or coerce a protobuf request object. - # Quick check: If we got a request object, we should *not* have - # gotten any keyword arguments that map to the request. + # - Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. has_flattened_params = any([name]) if request is not None and has_flattened_params: raise ValueError( @@ -1256,10 +1264,8 @@ def sample_delete_index(): "the individual field arguments should be set." ) - # Minor optimization to avoid making a copy if the user passes - # in a firestore_admin.DeleteIndexRequest. - # There's no risk of modifying the input as we've already verified - # there are no flattened fields. + # - Use the request object if provided (there's no risk of modifying the input as + # there are no flattened fields), or create one. if not isinstance(request, firestore_admin.DeleteIndexRequest): request = firestore_admin.DeleteIndexRequest(request) # If we have keyword arguments corresponding to fields on the @@ -1352,8 +1358,8 @@ def sample_get_field(): """ # Create or coerce a protobuf request object. - # Quick check: If we got a request object, we should *not* have - # gotten any keyword arguments that map to the request. + # - Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. has_flattened_params = any([name]) if request is not None and has_flattened_params: raise ValueError( @@ -1361,10 +1367,8 @@ def sample_get_field(): "the individual field arguments should be set." ) - # Minor optimization to avoid making a copy if the user passes - # in a firestore_admin.GetFieldRequest. - # There's no risk of modifying the input as we've already verified - # there are no flattened fields. + # - Use the request object if provided (there's no risk of modifying the input as + # there are no flattened fields), or create one. if not isinstance(request, firestore_admin.GetFieldRequest): request = firestore_admin.GetFieldRequest(request) # If we have keyword arguments corresponding to fields on the @@ -1484,8 +1488,8 @@ def sample_update_field(): """ # Create or coerce a protobuf request object. - # Quick check: If we got a request object, we should *not* have - # gotten any keyword arguments that map to the request. + # - Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. has_flattened_params = any([field]) if request is not None and has_flattened_params: raise ValueError( @@ -1493,10 +1497,8 @@ def sample_update_field(): "the individual field arguments should be set." ) - # Minor optimization to avoid making a copy if the user passes - # in a firestore_admin.UpdateFieldRequest. - # There's no risk of modifying the input as we've already verified - # there are no flattened fields. + # - Use the request object if provided (there's no risk of modifying the input as + # there are no flattened fields), or create one. if not isinstance(request, firestore_admin.UpdateFieldRequest): request = firestore_admin.UpdateFieldRequest(request) # If we have keyword arguments corresponding to fields on the @@ -1611,8 +1613,8 @@ def sample_list_fields(): """ # Create or coerce a protobuf request object. - # Quick check: If we got a request object, we should *not* have - # gotten any keyword arguments that map to the request. + # - Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. has_flattened_params = any([parent]) if request is not None and has_flattened_params: raise ValueError( @@ -1620,10 +1622,8 @@ def sample_list_fields(): "the individual field arguments should be set." ) - # Minor optimization to avoid making a copy if the user passes - # in a firestore_admin.ListFieldsRequest. - # There's no risk of modifying the input as we've already verified - # there are no flattened fields. + # - Use the request object if provided (there's no risk of modifying the input as + # there are no flattened fields), or create one. if not isinstance(request, firestore_admin.ListFieldsRequest): request = firestore_admin.ListFieldsRequest(request) # If we have keyword arguments corresponding to fields on the @@ -1658,6 +1658,8 @@ def sample_list_fields(): method=rpc, request=request, response=response, + retry=retry, + timeout=timeout, metadata=metadata, ) @@ -1745,8 +1747,8 @@ def sample_export_documents(): """ # Create or coerce a protobuf request object. - # Quick check: If we got a request object, we should *not* have - # gotten any keyword arguments that map to the request. + # - Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. has_flattened_params = any([name]) if request is not None and has_flattened_params: raise ValueError( @@ -1754,10 +1756,8 @@ def sample_export_documents(): "the individual field arguments should be set." ) - # Minor optimization to avoid making a copy if the user passes - # in a firestore_admin.ExportDocumentsRequest. - # There's no risk of modifying the input as we've already verified - # there are no flattened fields. + # - Use the request object if provided (there's no risk of modifying the input as + # there are no flattened fields), or create one. if not isinstance(request, firestore_admin.ExportDocumentsRequest): request = firestore_admin.ExportDocumentsRequest(request) # If we have keyword arguments corresponding to fields on the @@ -1878,8 +1878,8 @@ def sample_import_documents(): """ # Create or coerce a protobuf request object. - # Quick check: If we got a request object, we should *not* have - # gotten any keyword arguments that map to the request. + # - Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. has_flattened_params = any([name]) if request is not None and has_flattened_params: raise ValueError( @@ -1887,10 +1887,8 @@ def sample_import_documents(): "the individual field arguments should be set." ) - # Minor optimization to avoid making a copy if the user passes - # in a firestore_admin.ImportDocumentsRequest. - # There's no risk of modifying the input as we've already verified - # there are no flattened fields. + # - Use the request object if provided (there's no risk of modifying the input as + # there are no flattened fields), or create one. if not isinstance(request, firestore_admin.ImportDocumentsRequest): request = firestore_admin.ImportDocumentsRequest(request) # If we have keyword arguments corresponding to fields on the @@ -1930,6 +1928,142 @@ def sample_import_documents(): # Done; return the response. return response + def bulk_delete_documents( + self, + request: Optional[ + Union[firestore_admin.BulkDeleteDocumentsRequest, dict] + ] = None, + *, + name: Optional[str] = None, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Union[float, object] = gapic_v1.method.DEFAULT, + metadata: Sequence[Tuple[str, str]] = (), + ) -> gac_operation.Operation: + r"""Bulk deletes a subset of documents from Google Cloud + Firestore. Documents created or updated after the + underlying system starts to process the request will not + be deleted. The bulk delete occurs in the background and + its progress can be monitored and managed via the + Operation resource that is created. + + For more details on bulk delete behavior, refer to: + + https://cloud.google.com/firestore/docs/manage-data/bulk-delete + + .. code-block:: python + + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html + from google.cloud import firestore_admin_v1 + + def sample_bulk_delete_documents(): + # Create a client + client = firestore_admin_v1.FirestoreAdminClient() + + # Initialize request argument(s) + request = firestore_admin_v1.BulkDeleteDocumentsRequest( + name="name_value", + ) + + # Make the request + operation = client.bulk_delete_documents(request=request) + + print("Waiting for operation to complete...") + + response = operation.result() + + # Handle the response + print(response) + + Args: + request (Union[google.cloud.firestore_admin_v1.types.BulkDeleteDocumentsRequest, dict]): + The request object. The request for + [FirestoreAdmin.BulkDeleteDocuments][google.firestore.admin.v1.FirestoreAdmin.BulkDeleteDocuments]. + + When both collection_ids and namespace_ids are set, only + documents satisfying both conditions will be deleted. + + Requests with namespace_ids and collection_ids both + empty will be rejected. Please use + [FirestoreAdmin.DeleteDatabase][google.firestore.admin.v1.FirestoreAdmin.DeleteDatabase] + instead. + name (str): + Required. Database to operate. Should be of the form: + ``projects/{project_id}/databases/{database_id}``. + + This corresponds to the ``name`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + google.api_core.operation.Operation: + An object representing a long-running operation. + + The result type for the operation will be :class:`google.cloud.firestore_admin_v1.types.BulkDeleteDocumentsResponse` The response for + [FirestoreAdmin.BulkDeleteDocuments][google.firestore.admin.v1.FirestoreAdmin.BulkDeleteDocuments]. + + """ + # Create or coerce a protobuf request object. + # - Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + has_flattened_params = any([name]) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + # - Use the request object if provided (there's no risk of modifying the input as + # there are no flattened fields), or create one. + if not isinstance(request, firestore_admin.BulkDeleteDocumentsRequest): + request = firestore_admin.BulkDeleteDocumentsRequest(request) + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if name is not None: + request.name = name + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.bulk_delete_documents] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata((("name", request.name),)), + ) + + # Validate the universe domain. + self._validate_universe_domain() + + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Wrap the response in an operation future. + response = gac_operation.from_gapic( + response, + self._transport.operations_client, + firestore_admin.BulkDeleteDocumentsResponse, + metadata_type=gfa_operation.BulkDeleteDocumentsMetadata, + ) + + # Done; return the response. + return response + def create_database( self, request: Optional[Union[firestore_admin.CreateDatabaseRequest, dict]] = None, @@ -2021,8 +2155,8 @@ def sample_create_database(): """ # Create or coerce a protobuf request object. - # Quick check: If we got a request object, we should *not* have - # gotten any keyword arguments that map to the request. + # - Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. has_flattened_params = any([parent, database, database_id]) if request is not None and has_flattened_params: raise ValueError( @@ -2030,10 +2164,8 @@ def sample_create_database(): "the individual field arguments should be set." ) - # Minor optimization to avoid making a copy if the user passes - # in a firestore_admin.CreateDatabaseRequest. - # There's no risk of modifying the input as we've already verified - # there are no flattened fields. + # - Use the request object if provided (there's no risk of modifying the input as + # there are no flattened fields), or create one. if not isinstance(request, firestore_admin.CreateDatabaseRequest): request = firestore_admin.CreateDatabaseRequest(request) # If we have keyword arguments corresponding to fields on the @@ -2136,8 +2268,8 @@ def sample_get_database(): A Cloud Firestore Database. """ # Create or coerce a protobuf request object. - # Quick check: If we got a request object, we should *not* have - # gotten any keyword arguments that map to the request. + # - Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. has_flattened_params = any([name]) if request is not None and has_flattened_params: raise ValueError( @@ -2145,10 +2277,8 @@ def sample_get_database(): "the individual field arguments should be set." ) - # Minor optimization to avoid making a copy if the user passes - # in a firestore_admin.GetDatabaseRequest. - # There's no risk of modifying the input as we've already verified - # there are no flattened fields. + # - Use the request object if provided (there's no risk of modifying the input as + # there are no flattened fields), or create one. if not isinstance(request, firestore_admin.GetDatabaseRequest): request = firestore_admin.GetDatabaseRequest(request) # If we have keyword arguments corresponding to fields on the @@ -2240,8 +2370,8 @@ def sample_list_databases(): The list of databases for a project. """ # Create or coerce a protobuf request object. - # Quick check: If we got a request object, we should *not* have - # gotten any keyword arguments that map to the request. + # - Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. has_flattened_params = any([parent]) if request is not None and has_flattened_params: raise ValueError( @@ -2249,10 +2379,8 @@ def sample_list_databases(): "the individual field arguments should be set." ) - # Minor optimization to avoid making a copy if the user passes - # in a firestore_admin.ListDatabasesRequest. - # There's no risk of modifying the input as we've already verified - # there are no flattened fields. + # - Use the request object if provided (there's no risk of modifying the input as + # there are no flattened fields), or create one. if not isinstance(request, firestore_admin.ListDatabasesRequest): request = firestore_admin.ListDatabasesRequest(request) # If we have keyword arguments corresponding to fields on the @@ -2355,8 +2483,8 @@ def sample_update_database(): """ # Create or coerce a protobuf request object. - # Quick check: If we got a request object, we should *not* have - # gotten any keyword arguments that map to the request. + # - Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. has_flattened_params = any([database, update_mask]) if request is not None and has_flattened_params: raise ValueError( @@ -2364,10 +2492,8 @@ def sample_update_database(): "the individual field arguments should be set." ) - # Minor optimization to avoid making a copy if the user passes - # in a firestore_admin.UpdateDatabaseRequest. - # There's no risk of modifying the input as we've already verified - # there are no flattened fields. + # - Use the request object if provided (there's no risk of modifying the input as + # there are no flattened fields), or create one. if not isinstance(request, firestore_admin.UpdateDatabaseRequest): request = firestore_admin.UpdateDatabaseRequest(request) # If we have keyword arguments corresponding to fields on the @@ -2479,8 +2605,8 @@ def sample_delete_database(): """ # Create or coerce a protobuf request object. - # Quick check: If we got a request object, we should *not* have - # gotten any keyword arguments that map to the request. + # - Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. has_flattened_params = any([name]) if request is not None and has_flattened_params: raise ValueError( @@ -2488,10 +2614,8 @@ def sample_delete_database(): "the individual field arguments should be set." ) - # Minor optimization to avoid making a copy if the user passes - # in a firestore_admin.DeleteDatabaseRequest. - # There's no risk of modifying the input as we've already verified - # there are no flattened fields. + # - Use the request object if provided (there's no risk of modifying the input as + # there are no flattened fields), or create one. if not isinstance(request, firestore_admin.DeleteDatabaseRequest): request = firestore_admin.DeleteDatabaseRequest(request) # If we have keyword arguments corresponding to fields on the @@ -2597,8 +2721,8 @@ def sample_get_backup(): """ # Create or coerce a protobuf request object. - # Quick check: If we got a request object, we should *not* have - # gotten any keyword arguments that map to the request. + # - Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. has_flattened_params = any([name]) if request is not None and has_flattened_params: raise ValueError( @@ -2606,10 +2730,8 @@ def sample_get_backup(): "the individual field arguments should be set." ) - # Minor optimization to avoid making a copy if the user passes - # in a firestore_admin.GetBackupRequest. - # There's no risk of modifying the input as we've already verified - # there are no flattened fields. + # - Use the request object if provided (there's no risk of modifying the input as + # there are no flattened fields), or create one. if not isinstance(request, firestore_admin.GetBackupRequest): request = firestore_admin.GetBackupRequest(request) # If we have keyword arguments corresponding to fields on the @@ -2706,8 +2828,8 @@ def sample_list_backups(): """ # Create or coerce a protobuf request object. - # Quick check: If we got a request object, we should *not* have - # gotten any keyword arguments that map to the request. + # - Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. has_flattened_params = any([parent]) if request is not None and has_flattened_params: raise ValueError( @@ -2715,10 +2837,8 @@ def sample_list_backups(): "the individual field arguments should be set." ) - # Minor optimization to avoid making a copy if the user passes - # in a firestore_admin.ListBackupsRequest. - # There's no risk of modifying the input as we've already verified - # there are no flattened fields. + # - Use the request object if provided (there's no risk of modifying the input as + # there are no flattened fields), or create one. if not isinstance(request, firestore_admin.ListBackupsRequest): request = firestore_admin.ListBackupsRequest(request) # If we have keyword arguments corresponding to fields on the @@ -2804,8 +2924,8 @@ def sample_delete_backup(): sent along with the request as metadata. """ # Create or coerce a protobuf request object. - # Quick check: If we got a request object, we should *not* have - # gotten any keyword arguments that map to the request. + # - Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. has_flattened_params = any([name]) if request is not None and has_flattened_params: raise ValueError( @@ -2813,10 +2933,8 @@ def sample_delete_backup(): "the individual field arguments should be set." ) - # Minor optimization to avoid making a copy if the user passes - # in a firestore_admin.DeleteBackupRequest. - # There's no risk of modifying the input as we've already verified - # there are no flattened fields. + # - Use the request object if provided (there's no risk of modifying the input as + # there are no flattened fields), or create one. if not isinstance(request, firestore_admin.DeleteBackupRequest): request = firestore_admin.DeleteBackupRequest(request) # If we have keyword arguments corresponding to fields on the @@ -2858,7 +2976,7 @@ def restore_database( The new database must be in the same cloud region or multi-region location as the existing backup. This behaves similar to - [FirestoreAdmin.CreateDatabase][google.firestore.admin.v1.CreateDatabase] + [FirestoreAdmin.CreateDatabase][google.firestore.admin.v1.FirestoreAdmin.CreateDatabase] except instead of creating a new empty database, a new database is created with the database type, index configuration, and documents from an existing backup. @@ -2925,10 +3043,8 @@ def sample_restore_database(): """ # Create or coerce a protobuf request object. - # Minor optimization to avoid making a copy if the user passes - # in a firestore_admin.RestoreDatabaseRequest. - # There's no risk of modifying the input as we've already verified - # there are no flattened fields. + # - Use the request object if provided (there's no risk of modifying the input as + # there are no flattened fields), or create one. if not isinstance(request, firestore_admin.RestoreDatabaseRequest): request = firestore_admin.RestoreDatabaseRequest(request) @@ -3043,8 +3159,8 @@ def sample_create_backup_schedule(): """ # Create or coerce a protobuf request object. - # Quick check: If we got a request object, we should *not* have - # gotten any keyword arguments that map to the request. + # - Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. has_flattened_params = any([parent, backup_schedule]) if request is not None and has_flattened_params: raise ValueError( @@ -3052,10 +3168,8 @@ def sample_create_backup_schedule(): "the individual field arguments should be set." ) - # Minor optimization to avoid making a copy if the user passes - # in a firestore_admin.CreateBackupScheduleRequest. - # There's no risk of modifying the input as we've already verified - # there are no flattened fields. + # - Use the request object if provided (there's no risk of modifying the input as + # there are no flattened fields), or create one. if not isinstance(request, firestore_admin.CreateBackupScheduleRequest): request = firestore_admin.CreateBackupScheduleRequest(request) # If we have keyword arguments corresponding to fields on the @@ -3156,8 +3270,8 @@ def sample_get_backup_schedule(): """ # Create or coerce a protobuf request object. - # Quick check: If we got a request object, we should *not* have - # gotten any keyword arguments that map to the request. + # - Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. has_flattened_params = any([name]) if request is not None and has_flattened_params: raise ValueError( @@ -3165,10 +3279,8 @@ def sample_get_backup_schedule(): "the individual field arguments should be set." ) - # Minor optimization to avoid making a copy if the user passes - # in a firestore_admin.GetBackupScheduleRequest. - # There's no risk of modifying the input as we've already verified - # there are no flattened fields. + # - Use the request object if provided (there's no risk of modifying the input as + # there are no flattened fields), or create one. if not isinstance(request, firestore_admin.GetBackupScheduleRequest): request = firestore_admin.GetBackupScheduleRequest(request) # If we have keyword arguments corresponding to fields on the @@ -3264,8 +3376,8 @@ def sample_list_backup_schedules(): """ # Create or coerce a protobuf request object. - # Quick check: If we got a request object, we should *not* have - # gotten any keyword arguments that map to the request. + # - Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. has_flattened_params = any([parent]) if request is not None and has_flattened_params: raise ValueError( @@ -3273,10 +3385,8 @@ def sample_list_backup_schedules(): "the individual field arguments should be set." ) - # Minor optimization to avoid making a copy if the user passes - # in a firestore_admin.ListBackupSchedulesRequest. - # There's no risk of modifying the input as we've already verified - # there are no flattened fields. + # - Use the request object if provided (there's no risk of modifying the input as + # there are no flattened fields), or create one. if not isinstance(request, firestore_admin.ListBackupSchedulesRequest): request = firestore_admin.ListBackupSchedulesRequest(request) # If we have keyword arguments corresponding to fields on the @@ -3380,8 +3490,8 @@ def sample_update_backup_schedule(): """ # Create or coerce a protobuf request object. - # Quick check: If we got a request object, we should *not* have - # gotten any keyword arguments that map to the request. + # - Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. has_flattened_params = any([backup_schedule, update_mask]) if request is not None and has_flattened_params: raise ValueError( @@ -3389,10 +3499,8 @@ def sample_update_backup_schedule(): "the individual field arguments should be set." ) - # Minor optimization to avoid making a copy if the user passes - # in a firestore_admin.UpdateBackupScheduleRequest. - # There's no risk of modifying the input as we've already verified - # there are no flattened fields. + # - Use the request object if provided (there's no risk of modifying the input as + # there are no flattened fields), or create one. if not isinstance(request, firestore_admin.UpdateBackupScheduleRequest): request = firestore_admin.UpdateBackupScheduleRequest(request) # If we have keyword arguments corresponding to fields on the @@ -3484,8 +3592,8 @@ def sample_delete_backup_schedule(): sent along with the request as metadata. """ # Create or coerce a protobuf request object. - # Quick check: If we got a request object, we should *not* have - # gotten any keyword arguments that map to the request. + # - Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. has_flattened_params = any([name]) if request is not None and has_flattened_params: raise ValueError( @@ -3493,10 +3601,8 @@ def sample_delete_backup_schedule(): "the individual field arguments should be set." ) - # Minor optimization to avoid making a copy if the user passes - # in a firestore_admin.DeleteBackupScheduleRequest. - # There's no risk of modifying the input as we've already verified - # there are no flattened fields. + # - Use the request object if provided (there's no risk of modifying the input as + # there are no flattened fields), or create one. if not isinstance(request, firestore_admin.DeleteBackupScheduleRequest): request = firestore_admin.DeleteBackupScheduleRequest(request) # If we have keyword arguments corresponding to fields on the diff --git a/google/cloud/firestore_admin_v1/services/firestore_admin/pagers.py b/google/cloud/firestore_admin_v1/services/firestore_admin/pagers.py index 75d90ce3ea..423c43d9f3 100644 --- a/google/cloud/firestore_admin_v1/services/firestore_admin/pagers.py +++ b/google/cloud/firestore_admin_v1/services/firestore_admin/pagers.py @@ -13,6 +13,9 @@ # See the License for the specific language governing permissions and # limitations under the License. # +from google.api_core import gapic_v1 +from google.api_core import retry as retries +from google.api_core import retry_async as retries_async from typing import ( Any, AsyncIterator, @@ -22,8 +25,18 @@ Tuple, Optional, Iterator, + Union, ) +try: + OptionalRetry = Union[retries.Retry, gapic_v1.method._MethodDefault, None] + OptionalAsyncRetry = Union[ + retries_async.AsyncRetry, gapic_v1.method._MethodDefault, None + ] +except AttributeError: # pragma: NO COVER + OptionalRetry = Union[retries.Retry, object, None] # type: ignore + OptionalAsyncRetry = Union[retries_async.AsyncRetry, object, None] # type: ignore + from google.cloud.firestore_admin_v1.types import field from google.cloud.firestore_admin_v1.types import firestore_admin from google.cloud.firestore_admin_v1.types import index @@ -53,6 +66,8 @@ def __init__( request: firestore_admin.ListIndexesRequest, response: firestore_admin.ListIndexesResponse, *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Union[float, object] = gapic_v1.method.DEFAULT, metadata: Sequence[Tuple[str, str]] = () ): """Instantiate the pager. @@ -64,12 +79,17 @@ def __init__( The initial request object. response (google.cloud.firestore_admin_v1.types.ListIndexesResponse): The initial response object. + retry (google.api_core.retry.Retry): Designation of what errors, + if any, should be retried. + timeout (float): The timeout for this request. metadata (Sequence[Tuple[str, str]]): Strings which should be sent along with the request as metadata. """ self._method = method self._request = firestore_admin.ListIndexesRequest(request) self._response = response + self._retry = retry + self._timeout = timeout self._metadata = metadata def __getattr__(self, name: str) -> Any: @@ -80,7 +100,12 @@ def pages(self) -> Iterator[firestore_admin.ListIndexesResponse]: yield self._response while self._response.next_page_token: self._request.page_token = self._response.next_page_token - self._response = self._method(self._request, metadata=self._metadata) + self._response = self._method( + self._request, + retry=self._retry, + timeout=self._timeout, + metadata=self._metadata, + ) yield self._response def __iter__(self) -> Iterator[index.Index]: @@ -115,6 +140,8 @@ def __init__( request: firestore_admin.ListIndexesRequest, response: firestore_admin.ListIndexesResponse, *, + retry: OptionalAsyncRetry = gapic_v1.method.DEFAULT, + timeout: Union[float, object] = gapic_v1.method.DEFAULT, metadata: Sequence[Tuple[str, str]] = () ): """Instantiates the pager. @@ -126,12 +153,17 @@ def __init__( The initial request object. response (google.cloud.firestore_admin_v1.types.ListIndexesResponse): The initial response object. + retry (google.api_core.retry.AsyncRetry): Designation of what errors, + if any, should be retried. + timeout (float): The timeout for this request. metadata (Sequence[Tuple[str, str]]): Strings which should be sent along with the request as metadata. """ self._method = method self._request = firestore_admin.ListIndexesRequest(request) self._response = response + self._retry = retry + self._timeout = timeout self._metadata = metadata def __getattr__(self, name: str) -> Any: @@ -142,7 +174,12 @@ async def pages(self) -> AsyncIterator[firestore_admin.ListIndexesResponse]: yield self._response while self._response.next_page_token: self._request.page_token = self._response.next_page_token - self._response = await self._method(self._request, metadata=self._metadata) + self._response = await self._method( + self._request, + retry=self._retry, + timeout=self._timeout, + metadata=self._metadata, + ) yield self._response def __aiter__(self) -> AsyncIterator[index.Index]: @@ -181,6 +218,8 @@ def __init__( request: firestore_admin.ListFieldsRequest, response: firestore_admin.ListFieldsResponse, *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Union[float, object] = gapic_v1.method.DEFAULT, metadata: Sequence[Tuple[str, str]] = () ): """Instantiate the pager. @@ -192,12 +231,17 @@ def __init__( The initial request object. response (google.cloud.firestore_admin_v1.types.ListFieldsResponse): The initial response object. + retry (google.api_core.retry.Retry): Designation of what errors, + if any, should be retried. + timeout (float): The timeout for this request. metadata (Sequence[Tuple[str, str]]): Strings which should be sent along with the request as metadata. """ self._method = method self._request = firestore_admin.ListFieldsRequest(request) self._response = response + self._retry = retry + self._timeout = timeout self._metadata = metadata def __getattr__(self, name: str) -> Any: @@ -208,7 +252,12 @@ def pages(self) -> Iterator[firestore_admin.ListFieldsResponse]: yield self._response while self._response.next_page_token: self._request.page_token = self._response.next_page_token - self._response = self._method(self._request, metadata=self._metadata) + self._response = self._method( + self._request, + retry=self._retry, + timeout=self._timeout, + metadata=self._metadata, + ) yield self._response def __iter__(self) -> Iterator[field.Field]: @@ -243,6 +292,8 @@ def __init__( request: firestore_admin.ListFieldsRequest, response: firestore_admin.ListFieldsResponse, *, + retry: OptionalAsyncRetry = gapic_v1.method.DEFAULT, + timeout: Union[float, object] = gapic_v1.method.DEFAULT, metadata: Sequence[Tuple[str, str]] = () ): """Instantiates the pager. @@ -254,12 +305,17 @@ def __init__( The initial request object. response (google.cloud.firestore_admin_v1.types.ListFieldsResponse): The initial response object. + retry (google.api_core.retry.AsyncRetry): Designation of what errors, + if any, should be retried. + timeout (float): The timeout for this request. metadata (Sequence[Tuple[str, str]]): Strings which should be sent along with the request as metadata. """ self._method = method self._request = firestore_admin.ListFieldsRequest(request) self._response = response + self._retry = retry + self._timeout = timeout self._metadata = metadata def __getattr__(self, name: str) -> Any: @@ -270,7 +326,12 @@ async def pages(self) -> AsyncIterator[firestore_admin.ListFieldsResponse]: yield self._response while self._response.next_page_token: self._request.page_token = self._response.next_page_token - self._response = await self._method(self._request, metadata=self._metadata) + self._response = await self._method( + self._request, + retry=self._retry, + timeout=self._timeout, + metadata=self._metadata, + ) yield self._response def __aiter__(self) -> AsyncIterator[field.Field]: diff --git a/google/cloud/firestore_admin_v1/services/firestore_admin/transports/base.py b/google/cloud/firestore_admin_v1/services/firestore_admin/transports/base.py index 9ebcdad6f1..0bbbf2381c 100644 --- a/google/cloud/firestore_admin_v1/services/firestore_admin/transports/base.py +++ b/google/cloud/firestore_admin_v1/services/firestore_admin/transports/base.py @@ -94,6 +94,8 @@ def __init__( # Save the scopes. self._scopes = scopes + if not hasattr(self, "_ignore_credentials"): + self._ignore_credentials: bool = False # If no credentials are provided, then determine the appropriate # defaults. @@ -106,7 +108,7 @@ def __init__( credentials, _ = google.auth.load_credentials_from_file( credentials_file, **scopes_kwargs, quota_project_id=quota_project_id ) - elif credentials is None: + elif credentials is None and not self._ignore_credentials: credentials, _ = google.auth.default( **scopes_kwargs, quota_project_id=quota_project_id ) @@ -239,6 +241,11 @@ def _prep_wrapped_messages(self, client_info): default_timeout=60.0, client_info=client_info, ), + self.bulk_delete_documents: gapic_v1.method.wrap_method( + self.bulk_delete_documents, + default_timeout=60.0, + client_info=client_info, + ), self.create_database: gapic_v1.method.wrap_method( self.create_database, default_timeout=None, @@ -410,6 +417,15 @@ def import_documents( ]: raise NotImplementedError() + @property + def bulk_delete_documents( + self, + ) -> Callable[ + [firestore_admin.BulkDeleteDocumentsRequest], + Union[operations_pb2.Operation, Awaitable[operations_pb2.Operation]], + ]: + raise NotImplementedError() + @property def create_database( self, diff --git a/google/cloud/firestore_admin_v1/services/firestore_admin/transports/grpc.py b/google/cloud/firestore_admin_v1/services/firestore_admin/transports/grpc.py index cb0e076df4..c53adc1315 100644 --- a/google/cloud/firestore_admin_v1/services/firestore_admin/transports/grpc.py +++ b/google/cloud/firestore_admin_v1/services/firestore_admin/transports/grpc.py @@ -89,7 +89,7 @@ def __init__( credentials: Optional[ga_credentials.Credentials] = None, credentials_file: Optional[str] = None, scopes: Optional[Sequence[str]] = None, - channel: Optional[grpc.Channel] = None, + channel: Optional[Union[grpc.Channel, Callable[..., grpc.Channel]]] = None, api_mtls_endpoint: Optional[str] = None, client_cert_source: Optional[Callable[[], Tuple[bytes, bytes]]] = None, ssl_channel_credentials: Optional[grpc.ChannelCredentials] = None, @@ -109,14 +109,17 @@ def __init__( credentials identify the application to the service; if none are specified, the client will attempt to ascertain the credentials from the environment. - This argument is ignored if ``channel`` is provided. + This argument is ignored if a ``channel`` instance is provided. 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. + This argument is ignored if a ``channel`` instance is provided. scopes (Optional(Sequence[str])): A list of scopes. This argument is - ignored if ``channel`` is provided. - channel (Optional[grpc.Channel]): A ``Channel`` instance through - which to make calls. + ignored if a ``channel`` instance is provided. + channel (Optional[Union[grpc.Channel, Callable[..., grpc.Channel]]]): + A ``Channel`` instance through which to make calls, or a Callable + that constructs and returns one. If set to None, ``self.create_channel`` + is used to create the channel. If a Callable is given, it will be called + with the same arguments as used in ``self.create_channel``. api_mtls_endpoint (Optional[str]): Deprecated. The mutual TLS endpoint. If provided, it overrides the ``host`` argument and tries to create a mutual TLS channel with client SSL credentials from @@ -126,11 +129,11 @@ def __init__( private key bytes, both in PEM format. It is ignored if ``api_mtls_endpoint`` is None. ssl_channel_credentials (grpc.ChannelCredentials): SSL credentials - for the grpc channel. It is ignored if ``channel`` is provided. + for the grpc channel. It is ignored if a ``channel`` instance is provided. client_cert_source_for_mtls (Optional[Callable[[], Tuple[bytes, bytes]]]): A callback to provide client certificate bytes and private key bytes, both in PEM format. It is used to configure a mutual TLS channel. It is - ignored if ``channel`` or ``ssl_channel_credentials`` is provided. + ignored if a ``channel`` instance or ``ssl_channel_credentials`` is provided. quota_project_id (Optional[str]): An optional project to use for billing and quota. client_info (google.api_core.gapic_v1.client_info.ClientInfo): @@ -157,9 +160,10 @@ def __init__( if client_cert_source: warnings.warn("client_cert_source is deprecated", DeprecationWarning) - if channel: + if isinstance(channel, grpc.Channel): # Ignore credentials if a channel was passed. - credentials = False + credentials = None + self._ignore_credentials = True # If a channel was explicitly provided, set it. self._grpc_channel = channel self._ssl_channel_credentials = None @@ -198,7 +202,9 @@ def __init__( ) if not self._grpc_channel: - self._grpc_channel = type(self).create_channel( + # initialize with the provided callable or the default channel + channel_init = channel or type(self).create_channel + self._grpc_channel = channel_init( self._host, # use the credentials which are saved credentials=self._credentials, @@ -564,6 +570,43 @@ def import_documents( ) return self._stubs["import_documents"] + @property + def bulk_delete_documents( + self, + ) -> Callable[ + [firestore_admin.BulkDeleteDocumentsRequest], operations_pb2.Operation + ]: + r"""Return a callable for the bulk delete documents method over gRPC. + + Bulk deletes a subset of documents from Google Cloud + Firestore. Documents created or updated after the + underlying system starts to process the request will not + be deleted. The bulk delete occurs in the background and + its progress can be monitored and managed via the + Operation resource that is created. + + For more details on bulk delete behavior, refer to: + + https://cloud.google.com/firestore/docs/manage-data/bulk-delete + + Returns: + Callable[[~.BulkDeleteDocumentsRequest], + ~.Operation]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "bulk_delete_documents" not in self._stubs: + self._stubs["bulk_delete_documents"] = self.grpc_channel.unary_unary( + "/google.firestore.admin.v1.FirestoreAdmin/BulkDeleteDocuments", + request_serializer=firestore_admin.BulkDeleteDocumentsRequest.serialize, + response_deserializer=operations_pb2.Operation.FromString, + ) + return self._stubs["bulk_delete_documents"] + @property def create_database( self, @@ -785,7 +828,7 @@ def restore_database( The new database must be in the same cloud region or multi-region location as the existing backup. This behaves similar to - [FirestoreAdmin.CreateDatabase][google.firestore.admin.v1.CreateDatabase] + [FirestoreAdmin.CreateDatabase][google.firestore.admin.v1.FirestoreAdmin.CreateDatabase] except instead of creating a new empty database, a new database is created with the database type, index configuration, and documents from an existing backup. diff --git a/google/cloud/firestore_admin_v1/services/firestore_admin/transports/grpc_asyncio.py b/google/cloud/firestore_admin_v1/services/firestore_admin/transports/grpc_asyncio.py index 35710e628d..31593beb5e 100644 --- a/google/cloud/firestore_admin_v1/services/firestore_admin/transports/grpc_asyncio.py +++ b/google/cloud/firestore_admin_v1/services/firestore_admin/transports/grpc_asyncio.py @@ -18,6 +18,8 @@ from google.api_core import gapic_v1 from google.api_core import grpc_helpers_async +from google.api_core import exceptions as core_exceptions +from google.api_core import retry_async as retries from google.api_core import operations_v1 from google.auth import credentials as ga_credentials # type: ignore from google.auth.transport.grpc import SslCredentials # type: ignore @@ -104,7 +106,6 @@ def create_channel( 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 optional list of scopes needed for this service. These are only used when credentials are not specified and are passed to :func:`google.auth.default`. @@ -134,7 +135,7 @@ def __init__( credentials: Optional[ga_credentials.Credentials] = None, credentials_file: Optional[str] = None, scopes: Optional[Sequence[str]] = None, - channel: Optional[aio.Channel] = None, + channel: Optional[Union[aio.Channel, Callable[..., aio.Channel]]] = None, api_mtls_endpoint: Optional[str] = None, client_cert_source: Optional[Callable[[], Tuple[bytes, bytes]]] = None, ssl_channel_credentials: Optional[grpc.ChannelCredentials] = None, @@ -154,15 +155,18 @@ def __init__( credentials identify the application to the service; if none are specified, the client will attempt to ascertain the credentials from the environment. - This argument is ignored if ``channel`` is provided. + This argument is ignored if a ``channel`` instance is provided. 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. + This argument is ignored if a ``channel`` instance is provided. scopes (Optional[Sequence[str]]): A optional list of scopes needed for this service. These are only used when credentials are not specified and are passed to :func:`google.auth.default`. - channel (Optional[aio.Channel]): A ``Channel`` instance through - which to make calls. + channel (Optional[Union[aio.Channel, Callable[..., aio.Channel]]]): + A ``Channel`` instance through which to make calls, or a Callable + that constructs and returns one. If set to None, ``self.create_channel`` + is used to create the channel. If a Callable is given, it will be called + with the same arguments as used in ``self.create_channel``. api_mtls_endpoint (Optional[str]): Deprecated. The mutual TLS endpoint. If provided, it overrides the ``host`` argument and tries to create a mutual TLS channel with client SSL credentials from @@ -172,11 +176,11 @@ def __init__( private key bytes, both in PEM format. It is ignored if ``api_mtls_endpoint`` is None. ssl_channel_credentials (grpc.ChannelCredentials): SSL credentials - for the grpc channel. It is ignored if ``channel`` is provided. + for the grpc channel. It is ignored if a ``channel`` instance is provided. client_cert_source_for_mtls (Optional[Callable[[], Tuple[bytes, bytes]]]): A callback to provide client certificate bytes and private key bytes, both in PEM format. It is used to configure a mutual TLS channel. It is - ignored if ``channel`` or ``ssl_channel_credentials`` is provided. + ignored if a ``channel`` instance or ``ssl_channel_credentials`` is provided. quota_project_id (Optional[str]): An optional project to use for billing and quota. client_info (google.api_core.gapic_v1.client_info.ClientInfo): @@ -203,9 +207,10 @@ def __init__( if client_cert_source: warnings.warn("client_cert_source is deprecated", DeprecationWarning) - if channel: + if isinstance(channel, aio.Channel): # Ignore credentials if a channel was passed. - credentials = False + credentials = None + self._ignore_credentials = True # If a channel was explicitly provided, set it. self._grpc_channel = channel self._ssl_channel_credentials = None @@ -243,7 +248,9 @@ def __init__( ) if not self._grpc_channel: - self._grpc_channel = type(self).create_channel( + # initialize with the provided callable or the default channel + channel_init = channel or type(self).create_channel + self._grpc_channel = channel_init( self._host, # use the credentials which are saved credentials=self._credentials, @@ -583,6 +590,44 @@ def import_documents( ) return self._stubs["import_documents"] + @property + def bulk_delete_documents( + self, + ) -> Callable[ + [firestore_admin.BulkDeleteDocumentsRequest], + Awaitable[operations_pb2.Operation], + ]: + r"""Return a callable for the bulk delete documents method over gRPC. + + Bulk deletes a subset of documents from Google Cloud + Firestore. Documents created or updated after the + underlying system starts to process the request will not + be deleted. The bulk delete occurs in the background and + its progress can be monitored and managed via the + Operation resource that is created. + + For more details on bulk delete behavior, refer to: + + https://cloud.google.com/firestore/docs/manage-data/bulk-delete + + Returns: + Callable[[~.BulkDeleteDocumentsRequest], + Awaitable[~.Operation]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "bulk_delete_documents" not in self._stubs: + self._stubs["bulk_delete_documents"] = self.grpc_channel.unary_unary( + "/google.firestore.admin.v1.FirestoreAdmin/BulkDeleteDocuments", + request_serializer=firestore_admin.BulkDeleteDocumentsRequest.serialize, + response_deserializer=operations_pb2.Operation.FromString, + ) + return self._stubs["bulk_delete_documents"] + @property def create_database( self, @@ -816,7 +861,7 @@ def restore_database( The new database must be in the same cloud region or multi-region location as the existing backup. This behaves similar to - [FirestoreAdmin.CreateDatabase][google.firestore.admin.v1.CreateDatabase] + [FirestoreAdmin.CreateDatabase][google.firestore.admin.v1.FirestoreAdmin.CreateDatabase] except instead of creating a new empty database, a new database is created with the database type, index configuration, and documents from an existing backup. @@ -995,6 +1040,186 @@ def delete_backup_schedule( ) return self._stubs["delete_backup_schedule"] + def _prep_wrapped_messages(self, client_info): + """Precompute the wrapped methods, overriding the base class method to use async wrappers.""" + self._wrapped_methods = { + self.create_index: gapic_v1.method_async.wrap_method( + self.create_index, + default_timeout=60.0, + client_info=client_info, + ), + self.list_indexes: gapic_v1.method_async.wrap_method( + self.list_indexes, + default_retry=retries.AsyncRetry( + initial=0.1, + maximum=60.0, + multiplier=1.3, + predicate=retries.if_exception_type( + core_exceptions.DeadlineExceeded, + core_exceptions.InternalServerError, + core_exceptions.ServiceUnavailable, + ), + deadline=60.0, + ), + default_timeout=60.0, + client_info=client_info, + ), + self.get_index: gapic_v1.method_async.wrap_method( + self.get_index, + default_retry=retries.AsyncRetry( + initial=0.1, + maximum=60.0, + multiplier=1.3, + predicate=retries.if_exception_type( + core_exceptions.DeadlineExceeded, + core_exceptions.InternalServerError, + core_exceptions.ServiceUnavailable, + ), + deadline=60.0, + ), + default_timeout=60.0, + client_info=client_info, + ), + self.delete_index: gapic_v1.method_async.wrap_method( + self.delete_index, + default_retry=retries.AsyncRetry( + initial=0.1, + maximum=60.0, + multiplier=1.3, + predicate=retries.if_exception_type( + core_exceptions.DeadlineExceeded, + core_exceptions.InternalServerError, + core_exceptions.ServiceUnavailable, + ), + deadline=60.0, + ), + default_timeout=60.0, + client_info=client_info, + ), + self.get_field: gapic_v1.method_async.wrap_method( + self.get_field, + default_retry=retries.AsyncRetry( + initial=0.1, + maximum=60.0, + multiplier=1.3, + predicate=retries.if_exception_type( + core_exceptions.DeadlineExceeded, + core_exceptions.InternalServerError, + core_exceptions.ServiceUnavailable, + ), + deadline=60.0, + ), + default_timeout=60.0, + client_info=client_info, + ), + self.update_field: gapic_v1.method_async.wrap_method( + self.update_field, + default_timeout=60.0, + client_info=client_info, + ), + self.list_fields: gapic_v1.method_async.wrap_method( + self.list_fields, + default_retry=retries.AsyncRetry( + initial=0.1, + maximum=60.0, + multiplier=1.3, + predicate=retries.if_exception_type( + core_exceptions.DeadlineExceeded, + core_exceptions.InternalServerError, + core_exceptions.ServiceUnavailable, + ), + deadline=60.0, + ), + default_timeout=60.0, + client_info=client_info, + ), + self.export_documents: gapic_v1.method_async.wrap_method( + self.export_documents, + default_timeout=60.0, + client_info=client_info, + ), + self.import_documents: gapic_v1.method_async.wrap_method( + self.import_documents, + default_timeout=60.0, + client_info=client_info, + ), + self.bulk_delete_documents: gapic_v1.method_async.wrap_method( + self.bulk_delete_documents, + default_timeout=60.0, + client_info=client_info, + ), + self.create_database: gapic_v1.method_async.wrap_method( + self.create_database, + default_timeout=None, + client_info=client_info, + ), + self.get_database: gapic_v1.method_async.wrap_method( + self.get_database, + default_timeout=None, + client_info=client_info, + ), + self.list_databases: gapic_v1.method_async.wrap_method( + self.list_databases, + default_timeout=None, + client_info=client_info, + ), + self.update_database: gapic_v1.method_async.wrap_method( + self.update_database, + default_timeout=None, + client_info=client_info, + ), + self.delete_database: gapic_v1.method_async.wrap_method( + self.delete_database, + default_timeout=None, + client_info=client_info, + ), + self.get_backup: gapic_v1.method_async.wrap_method( + self.get_backup, + default_timeout=None, + client_info=client_info, + ), + self.list_backups: gapic_v1.method_async.wrap_method( + self.list_backups, + default_timeout=None, + client_info=client_info, + ), + self.delete_backup: gapic_v1.method_async.wrap_method( + self.delete_backup, + default_timeout=None, + client_info=client_info, + ), + self.restore_database: gapic_v1.method_async.wrap_method( + self.restore_database, + default_timeout=None, + client_info=client_info, + ), + self.create_backup_schedule: gapic_v1.method_async.wrap_method( + self.create_backup_schedule, + default_timeout=None, + client_info=client_info, + ), + self.get_backup_schedule: gapic_v1.method_async.wrap_method( + self.get_backup_schedule, + default_timeout=None, + client_info=client_info, + ), + self.list_backup_schedules: gapic_v1.method_async.wrap_method( + self.list_backup_schedules, + default_timeout=None, + client_info=client_info, + ), + self.update_backup_schedule: gapic_v1.method_async.wrap_method( + self.update_backup_schedule, + default_timeout=None, + client_info=client_info, + ), + self.delete_backup_schedule: gapic_v1.method_async.wrap_method( + self.delete_backup_schedule, + default_timeout=None, + client_info=client_info, + ), + } + def close(self): return self.grpc_channel.close() diff --git a/google/cloud/firestore_admin_v1/services/firestore_admin/transports/rest.py b/google/cloud/firestore_admin_v1/services/firestore_admin/transports/rest.py index b77cce9293..0003a5c13a 100644 --- a/google/cloud/firestore_admin_v1/services/firestore_admin/transports/rest.py +++ b/google/cloud/firestore_admin_v1/services/firestore_admin/transports/rest.py @@ -78,6 +78,14 @@ class FirestoreAdminRestInterceptor: .. code-block:: python class MyCustomFirestoreAdminInterceptor(FirestoreAdminRestInterceptor): + def pre_bulk_delete_documents(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_bulk_delete_documents(self, response): + logging.log(f"Received response: {response}") + return response + def pre_create_backup_schedule(self, request, metadata): logging.log(f"Received request: {request}") return request, metadata @@ -256,6 +264,29 @@ def post_update_field(self, response): """ + def pre_bulk_delete_documents( + self, + request: firestore_admin.BulkDeleteDocumentsRequest, + metadata: Sequence[Tuple[str, str]], + ) -> Tuple[firestore_admin.BulkDeleteDocumentsRequest, Sequence[Tuple[str, str]]]: + """Pre-rpc interceptor for bulk_delete_documents + + Override in a subclass to manipulate the request or metadata + before they are sent to the FirestoreAdmin server. + """ + return request, metadata + + def post_bulk_delete_documents( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for bulk_delete_documents + + Override in a subclass to manipulate the response + after it is returned by the FirestoreAdmin server but before + it is returned to user code. + """ + return response + def pre_create_backup_schedule( self, request: firestore_admin.CreateBackupScheduleRequest, @@ -1013,6 +1044,110 @@ def operations_client(self) -> operations_v1.AbstractOperationsClient: # Return the client from cache. return self._operations_client + class _BulkDeleteDocuments(FirestoreAdminRestStub): + def __hash__(self): + return hash("BulkDeleteDocuments") + + __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: firestore_admin.BulkDeleteDocumentsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, str]] = (), + ) -> operations_pb2.Operation: + r"""Call the bulk delete documents method over HTTP. + + Args: + request (~.firestore_admin.BulkDeleteDocumentsRequest): + The request object. The request for + [FirestoreAdmin.BulkDeleteDocuments][google.firestore.admin.v1.FirestoreAdmin.BulkDeleteDocuments]. + + When both collection_ids and namespace_ids are set, only + documents satisfying both conditions will be deleted. + + Requests with namespace_ids and collection_ids both + empty will be rejected. Please use + [FirestoreAdmin.DeleteDatabase][google.firestore.admin.v1.FirestoreAdmin.DeleteDatabase] + instead. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, str]]): Strings which should be + sent along with the request as metadata. + + Returns: + ~.operations_pb2.Operation: + This resource represents a + long-running operation that is the + result of a network API call. + + """ + + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v1/{name=projects/*/databases/*}:bulkDeleteDocuments", + "body": "*", + }, + ] + request, metadata = self._interceptor.pre_bulk_delete_documents( + request, metadata + ) + pb_request = firestore_admin.BulkDeleteDocumentsRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], 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"], + 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_bulk_delete_documents(resp) + return resp + class _CreateBackupSchedule(FirestoreAdminRestStub): def __hash__(self): return hash("CreateBackupSchedule") @@ -3084,6 +3219,16 @@ def __call__( resp = self._interceptor.post_update_field(resp) return resp + @property + def bulk_delete_documents( + self, + ) -> Callable[ + [firestore_admin.BulkDeleteDocumentsRequest], 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._BulkDeleteDocuments(self._session, self._host, self._interceptor) # type: ignore + @property def create_backup_schedule( self, diff --git a/google/cloud/firestore_admin_v1/types/__init__.py b/google/cloud/firestore_admin_v1/types/__init__.py index 0405a9481a..c1ae35fbf0 100644 --- a/google/cloud/firestore_admin_v1/types/__init__.py +++ b/google/cloud/firestore_admin_v1/types/__init__.py @@ -23,6 +23,8 @@ Field, ) from .firestore_admin import ( + BulkDeleteDocumentsRequest, + BulkDeleteDocumentsResponse, CreateBackupScheduleRequest, CreateDatabaseMetadata, CreateDatabaseRequest, @@ -62,6 +64,7 @@ LocationMetadata, ) from .operation import ( + BulkDeleteDocumentsMetadata, ExportDocumentsMetadata, ExportDocumentsResponse, FieldOperationMetadata, @@ -81,6 +84,8 @@ "Backup", "Database", "Field", + "BulkDeleteDocumentsRequest", + "BulkDeleteDocumentsResponse", "CreateBackupScheduleRequest", "CreateDatabaseMetadata", "CreateDatabaseRequest", @@ -114,6 +119,7 @@ "UpdateFieldRequest", "Index", "LocationMetadata", + "BulkDeleteDocumentsMetadata", "ExportDocumentsMetadata", "ExportDocumentsResponse", "FieldOperationMetadata", diff --git a/google/cloud/firestore_admin_v1/types/field.py b/google/cloud/firestore_admin_v1/types/field.py index 2fce123ff3..31be5fc17a 100644 --- a/google/cloud/firestore_admin_v1/types/field.py +++ b/google/cloud/firestore_admin_v1/types/field.py @@ -38,23 +38,25 @@ class Field(proto.Message): Attributes: name (str): - Required. A field name of the form + Required. A field name of the form: ``projects/{project_id}/databases/{database_id}/collectionGroups/{collection_id}/fields/{field_path}`` - A field path may be a simple field name, e.g. ``address`` or - a path to fields within map_value , e.g. ``address.city``, - or a special field path. The only valid special field is - ``*``, which represents any field. + A field path can be a simple field name, e.g. ``address`` or + a path to fields within ``map_value`` , e.g. + ``address.city``, or a special field path. The only valid + special field is ``*``, which represents any field. - Field paths may be quoted using - ``(backtick). The only character that needs to be escaped within a quoted field path is the backtick character itself, escaped using a backslash. Special characters in field paths that must be quoted include:``\ \*\ ``,``.\ :literal:`, ``` (backtick),`\ [``,``]`, - as well as any ascii symbolic characters. + Field paths can be quoted using :literal:`\`` (backtick). + The only character that must be escaped within a quoted + field path is the backtick character itself, escaped using a + backslash. Special characters in field paths that must be + quoted include: ``*``, ``.``, :literal:`\`` (backtick), + ``[``, ``]``, as well as any ascii symbolic characters. - Examples: (Note: Comments here are written in markdown - syntax, so there is an additional layer of backticks to - represent a code block) - ``\``\ address.city\`\ ``represents a field named``\ address.city\ ``, not the map key``\ city\ ``in the field``\ address\ ``.``\ \`\ *\`\ ``represents a field named``*\ \`, - not any field. + Examples: :literal:`\`address.city\`` represents a field + named ``address.city``, not the map key ``city`` in the + field ``address``. :literal:`\`*\`` represents a field named + ``*``, not any field. A special ``Field`` contains the default indexing settings for all fields. This field's resource name is: @@ -120,10 +122,13 @@ class IndexConfig(proto.Message): class TtlConfig(proto.Message): r"""The TTL (time-to-live) configuration for documents that have this - ``Field`` set. Storing a timestamp value into a TTL-enabled field - will be treated as the document's absolute expiration time. Using - any other data type or leaving the field absent will disable the TTL - for the individual document. + ``Field`` set. + + Storing a timestamp value into a TTL-enabled field will be treated + as the document's absolute expiration time. Timestamp values in the + past indicate that the document is eligible for immediate + expiration. Using any other data type or leaving the field absent + will disable expiration for the individual document. Attributes: state (google.cloud.firestore_admin_v1.types.Field.TtlConfig.State): diff --git a/google/cloud/firestore_admin_v1/types/firestore_admin.py b/google/cloud/firestore_admin_v1/types/firestore_admin.py index e0e37b3478..17c25a854a 100644 --- a/google/cloud/firestore_admin_v1/types/firestore_admin.py +++ b/google/cloud/firestore_admin_v1/types/firestore_admin.py @@ -57,6 +57,8 @@ "ListFieldsResponse", "ExportDocumentsRequest", "ImportDocumentsRequest", + "BulkDeleteDocumentsRequest", + "BulkDeleteDocumentsResponse", "GetBackupRequest", "ListBackupsRequest", "ListBackupsResponse", @@ -74,12 +76,18 @@ class ListDatabasesRequest(proto.Message): parent (str): Required. A parent name of the form ``projects/{project_id}`` + show_deleted (bool): + If true, also returns deleted resources. """ parent: str = proto.Field( proto.STRING, number=1, ) + show_deleted: bool = proto.Field( + proto.BOOL, + number=4, + ) class CreateDatabaseRequest(proto.Message): @@ -516,7 +524,7 @@ class ListFieldsRequest(proto.Message): overridden. To issue this query, call [FirestoreAdmin.ListFields][google.firestore.admin.v1.FirestoreAdmin.ListFields] with a filter that includes - ``indexConfig.usesAncestorConfig:false`` . + ``indexConfig.usesAncestorConfig:false`` or ``ttlConfig:*``. page_size (int): The number of results to return. page_token (str): @@ -581,7 +589,8 @@ class ExportDocumentsRequest(proto.Message): ``projects/{project_id}/databases/{database_id}``. collection_ids (MutableSequence[str]): Which collection ids to export. Unspecified - means all collections. + means all collections. Each collection id in + this list must be unique. output_uri_prefix (str): The output URI. Currently only supports Google Cloud Storage URIs of the form: ``gs://BUCKET_NAME[/NAMESPACE_PATH]``, @@ -647,6 +656,7 @@ class ImportDocumentsRequest(proto.Message): collection_ids (MutableSequence[str]): Which collection ids to import. Unspecified means all collections included in the import. + Each collection id in this list must be unique. input_uri_prefix (str): Location of the exported files. This must match the output_uri_prefix of an ExportDocumentsResponse from an @@ -682,6 +692,64 @@ class ImportDocumentsRequest(proto.Message): ) +class BulkDeleteDocumentsRequest(proto.Message): + r"""The request for + [FirestoreAdmin.BulkDeleteDocuments][google.firestore.admin.v1.FirestoreAdmin.BulkDeleteDocuments]. + + When both collection_ids and namespace_ids are set, only documents + satisfying both conditions will be deleted. + + Requests with namespace_ids and collection_ids both empty will be + rejected. Please use + [FirestoreAdmin.DeleteDatabase][google.firestore.admin.v1.FirestoreAdmin.DeleteDatabase] + instead. + + Attributes: + name (str): + Required. Database to operate. Should be of the form: + ``projects/{project_id}/databases/{database_id}``. + collection_ids (MutableSequence[str]): + Optional. IDs of the collection groups to + delete. Unspecified means all collection groups. + + Each collection group in this list must be + unique. + namespace_ids (MutableSequence[str]): + Optional. Namespaces to delete. + + An empty list means all namespaces. This is the + recommended usage for databases that don't use + namespaces. + + An empty string element represents the default + namespace. This should be used if the database + has data in non-default namespaces, but doesn't + want to delete from them. + + Each namespace in this list must be unique. + """ + + name: str = proto.Field( + proto.STRING, + number=1, + ) + collection_ids: MutableSequence[str] = proto.RepeatedField( + proto.STRING, + number=2, + ) + namespace_ids: MutableSequence[str] = proto.RepeatedField( + proto.STRING, + number=3, + ) + + +class BulkDeleteDocumentsResponse(proto.Message): + r"""The response for + [FirestoreAdmin.BulkDeleteDocuments][google.firestore.admin.v1.FirestoreAdmin.BulkDeleteDocuments]. + + """ + + class GetBackupRequest(proto.Message): r"""The request for [FirestoreAdmin.GetBackup][google.firestore.admin.v1.FirestoreAdmin.GetBackup]. diff --git a/google/cloud/firestore_admin_v1/types/index.py b/google/cloud/firestore_admin_v1/types/index.py index dcfd791e6d..b9739d429e 100644 --- a/google/cloud/firestore_admin_v1/types/index.py +++ b/google/cloud/firestore_admin_v1/types/index.py @@ -180,7 +180,7 @@ class IndexField(proto.Message): This field is a member of `oneof`_ ``value_mode``. vector_config (google.cloud.firestore_admin_v1.types.Index.IndexField.VectorConfig): Indicates that this field supports nearest - neighbors and distance operations on vector. + neighbor and distance operations on vector. This field is a member of `oneof`_ ``value_mode``. """ diff --git a/google/cloud/firestore_admin_v1/types/operation.py b/google/cloud/firestore_admin_v1/types/operation.py index 407e778544..bb817e9053 100644 --- a/google/cloud/firestore_admin_v1/types/operation.py +++ b/google/cloud/firestore_admin_v1/types/operation.py @@ -31,6 +31,7 @@ "FieldOperationMetadata", "ExportDocumentsMetadata", "ImportDocumentsMetadata", + "BulkDeleteDocumentsMetadata", "ExportDocumentsResponse", "RestoreDatabaseMetadata", "Progress", @@ -412,6 +413,79 @@ class ImportDocumentsMetadata(proto.Message): ) +class BulkDeleteDocumentsMetadata(proto.Message): + r"""Metadata for + [google.longrunning.Operation][google.longrunning.Operation] results + from + [FirestoreAdmin.BulkDeleteDocuments][google.firestore.admin.v1.FirestoreAdmin.BulkDeleteDocuments]. + + Attributes: + start_time (google.protobuf.timestamp_pb2.Timestamp): + The time this operation started. + end_time (google.protobuf.timestamp_pb2.Timestamp): + The time this operation completed. Will be + unset if operation still in progress. + operation_state (google.cloud.firestore_admin_v1.types.OperationState): + The state of the operation. + progress_documents (google.cloud.firestore_admin_v1.types.Progress): + The progress, in documents, of this + operation. + progress_bytes (google.cloud.firestore_admin_v1.types.Progress): + The progress, in bytes, of this operation. + collection_ids (MutableSequence[str]): + The ids of the collection groups that are + being deleted. + namespace_ids (MutableSequence[str]): + Which namespace ids are being deleted. + snapshot_time (google.protobuf.timestamp_pb2.Timestamp): + The timestamp that corresponds to the version + of the database that is being read to get the + list of documents to delete. This time can also + be used as the timestamp of PITR in case of + disaster recovery (subject to PITR window + limit). + """ + + start_time: timestamp_pb2.Timestamp = proto.Field( + proto.MESSAGE, + number=1, + message=timestamp_pb2.Timestamp, + ) + end_time: timestamp_pb2.Timestamp = proto.Field( + proto.MESSAGE, + number=2, + message=timestamp_pb2.Timestamp, + ) + operation_state: "OperationState" = proto.Field( + proto.ENUM, + number=3, + enum="OperationState", + ) + progress_documents: "Progress" = proto.Field( + proto.MESSAGE, + number=4, + message="Progress", + ) + progress_bytes: "Progress" = proto.Field( + proto.MESSAGE, + number=5, + message="Progress", + ) + collection_ids: MutableSequence[str] = proto.RepeatedField( + proto.STRING, + number=6, + ) + namespace_ids: MutableSequence[str] = proto.RepeatedField( + proto.STRING, + number=7, + ) + snapshot_time: timestamp_pb2.Timestamp = proto.Field( + proto.MESSAGE, + number=8, + message=timestamp_pb2.Timestamp, + ) + + class ExportDocumentsResponse(proto.Message): r"""Returned in the [google.longrunning.Operation][google.longrunning.Operation] diff --git a/google/cloud/firestore_v1/services/firestore/async_client.py b/google/cloud/firestore_v1/services/firestore/async_client.py index ecf9baea42..ec1d55e76f 100644 --- a/google/cloud/firestore_v1/services/firestore/async_client.py +++ b/google/cloud/firestore_v1/services/firestore/async_client.py @@ -14,10 +14,10 @@ # limitations under the License. # from collections import OrderedDict -import functools import re from typing import ( Dict, + Callable, Mapping, MutableMapping, MutableSequence, @@ -40,6 +40,7 @@ from google.auth import credentials as ga_credentials # type: ignore from google.oauth2 import service_account # type: ignore + try: OptionalRetry = Union[retries.AsyncRetry, gapic_v1.method._MethodDefault, None] except AttributeError: # pragma: NO COVER @@ -200,15 +201,15 @@ def universe_domain(self) -> str: """ return self._client._universe_domain - get_transport_class = functools.partial( - type(FirestoreClient).get_transport_class, type(FirestoreClient) - ) + get_transport_class = FirestoreClient.get_transport_class def __init__( self, *, credentials: Optional[ga_credentials.Credentials] = None, - transport: Union[str, FirestoreTransport] = "grpc_asyncio", + transport: Optional[ + Union[str, FirestoreTransport, Callable[..., FirestoreTransport]] + ] = "grpc_asyncio", client_options: Optional[ClientOptions] = None, client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, ) -> None: @@ -220,9 +221,11 @@ def __init__( credentials identify the application to the service; if none are specified, the client will attempt to ascertain the credentials from the environment. - transport (Union[str, ~.FirestoreTransport]): The - transport to use. If set to None, a transport is chosen - automatically. + transport (Optional[Union[str,FirestoreTransport,Callable[..., FirestoreTransport]]]): + The transport to use, or a Callable that constructs and returns a new transport to use. + If a Callable is given, it will be called with the same set of initialization + arguments as used in the FirestoreTransport constructor. + If set to None, a transport is chosen automatically. client_options (Optional[Union[google.api_core.client_options.ClientOptions, dict]]): Custom options for the client. @@ -321,27 +324,16 @@ async def sample_get_document(): """ # Create or coerce a protobuf request object. - request = firestore.GetDocumentRequest(request) + # - Use the request object if provided (there's no risk of modifying the input as + # there are no flattened fields), or create one. + if not isinstance(request, firestore.GetDocumentRequest): + request = firestore.GetDocumentRequest(request) # Wrap the RPC method; this adds retry and timeout information, # and friendly error handling. - rpc = gapic_v1.method_async.wrap_method( - self._client._transport.get_document, - default_retry=retries.AsyncRetry( - initial=0.1, - maximum=60.0, - multiplier=1.3, - predicate=retries.if_exception_type( - core_exceptions.DeadlineExceeded, - core_exceptions.InternalServerError, - core_exceptions.ResourceExhausted, - core_exceptions.ServiceUnavailable, - ), - deadline=60.0, - ), - default_timeout=60.0, - client_info=DEFAULT_CLIENT_INFO, - ) + rpc = self._client._transport._wrapped_methods[ + self._client._transport.get_document + ] # Certain fields should be provided within the metadata header; # add these here. @@ -421,27 +413,16 @@ async def sample_list_documents(): """ # Create or coerce a protobuf request object. - request = firestore.ListDocumentsRequest(request) + # - Use the request object if provided (there's no risk of modifying the input as + # there are no flattened fields), or create one. + if not isinstance(request, firestore.ListDocumentsRequest): + request = firestore.ListDocumentsRequest(request) # Wrap the RPC method; this adds retry and timeout information, # and friendly error handling. - rpc = gapic_v1.method_async.wrap_method( - self._client._transport.list_documents, - default_retry=retries.AsyncRetry( - initial=0.1, - maximum=60.0, - multiplier=1.3, - predicate=retries.if_exception_type( - core_exceptions.DeadlineExceeded, - core_exceptions.InternalServerError, - core_exceptions.ResourceExhausted, - core_exceptions.ServiceUnavailable, - ), - deadline=60.0, - ), - default_timeout=60.0, - client_info=DEFAULT_CLIENT_INFO, - ) + rpc = self._client._transport._wrapped_methods[ + self._client._transport.list_documents + ] # Certain fields should be provided within the metadata header; # add these here. @@ -471,6 +452,8 @@ async def sample_list_documents(): method=rpc, request=request, response=response, + retry=retry, + timeout=timeout, metadata=metadata, ) @@ -555,8 +538,8 @@ async def sample_update_document(): """ # Create or coerce a protobuf request object. - # Quick check: If we got a request object, we should *not* have - # gotten any keyword arguments that map to the request. + # - Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. has_flattened_params = any([document, update_mask]) if request is not None and has_flattened_params: raise ValueError( @@ -564,7 +547,10 @@ async def sample_update_document(): "the individual field arguments should be set." ) - request = firestore.UpdateDocumentRequest(request) + # - Use the request object if provided (there's no risk of modifying the input as + # there are no flattened fields), or create one. + if not isinstance(request, firestore.UpdateDocumentRequest): + request = firestore.UpdateDocumentRequest(request) # If we have keyword arguments corresponding to fields on the # request, apply these. @@ -575,21 +561,9 @@ async def sample_update_document(): # Wrap the RPC method; this adds retry and timeout information, # and friendly error handling. - rpc = gapic_v1.method_async.wrap_method( - self._client._transport.update_document, - default_retry=retries.AsyncRetry( - initial=0.1, - maximum=60.0, - multiplier=1.3, - predicate=retries.if_exception_type( - core_exceptions.ResourceExhausted, - core_exceptions.ServiceUnavailable, - ), - deadline=60.0, - ), - default_timeout=60.0, - client_info=DEFAULT_CLIENT_INFO, - ) + rpc = self._client._transport._wrapped_methods[ + self._client._transport.update_document + ] # Certain fields should be provided within the metadata header; # add these here. @@ -666,8 +640,8 @@ async def sample_delete_document(): sent along with the request as metadata. """ # Create or coerce a protobuf request object. - # Quick check: If we got a request object, we should *not* have - # gotten any keyword arguments that map to the request. + # - Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. has_flattened_params = any([name]) if request is not None and has_flattened_params: raise ValueError( @@ -675,7 +649,10 @@ async def sample_delete_document(): "the individual field arguments should be set." ) - request = firestore.DeleteDocumentRequest(request) + # - Use the request object if provided (there's no risk of modifying the input as + # there are no flattened fields), or create one. + if not isinstance(request, firestore.DeleteDocumentRequest): + request = firestore.DeleteDocumentRequest(request) # If we have keyword arguments corresponding to fields on the # request, apply these. @@ -684,23 +661,9 @@ async def sample_delete_document(): # Wrap the RPC method; this adds retry and timeout information, # and friendly error handling. - rpc = gapic_v1.method_async.wrap_method( - self._client._transport.delete_document, - default_retry=retries.AsyncRetry( - initial=0.1, - maximum=60.0, - multiplier=1.3, - predicate=retries.if_exception_type( - core_exceptions.DeadlineExceeded, - core_exceptions.InternalServerError, - core_exceptions.ResourceExhausted, - core_exceptions.ServiceUnavailable, - ), - deadline=60.0, - ), - default_timeout=60.0, - client_info=DEFAULT_CLIENT_INFO, - ) + rpc = self._client._transport._wrapped_methods[ + self._client._transport.delete_document + ] # Certain fields should be provided within the metadata header; # add these here. @@ -777,27 +740,16 @@ async def sample_batch_get_documents(): """ # Create or coerce a protobuf request object. - request = firestore.BatchGetDocumentsRequest(request) + # - Use the request object if provided (there's no risk of modifying the input as + # there are no flattened fields), or create one. + if not isinstance(request, firestore.BatchGetDocumentsRequest): + request = firestore.BatchGetDocumentsRequest(request) # Wrap the RPC method; this adds retry and timeout information, # and friendly error handling. - rpc = gapic_v1.method_async.wrap_method( - self._client._transport.batch_get_documents, - default_retry=retries.AsyncRetry( - initial=0.1, - maximum=60.0, - multiplier=1.3, - predicate=retries.if_exception_type( - core_exceptions.DeadlineExceeded, - core_exceptions.InternalServerError, - core_exceptions.ResourceExhausted, - core_exceptions.ServiceUnavailable, - ), - deadline=300.0, - ), - default_timeout=300.0, - client_info=DEFAULT_CLIENT_INFO, - ) + rpc = self._client._transport._wrapped_methods[ + self._client._transport.batch_get_documents + ] # Certain fields should be provided within the metadata header; # add these here. @@ -880,8 +832,8 @@ async def sample_begin_transaction(): """ # Create or coerce a protobuf request object. - # Quick check: If we got a request object, we should *not* have - # gotten any keyword arguments that map to the request. + # - Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. has_flattened_params = any([database]) if request is not None and has_flattened_params: raise ValueError( @@ -889,7 +841,10 @@ async def sample_begin_transaction(): "the individual field arguments should be set." ) - request = firestore.BeginTransactionRequest(request) + # - Use the request object if provided (there's no risk of modifying the input as + # there are no flattened fields), or create one. + if not isinstance(request, firestore.BeginTransactionRequest): + request = firestore.BeginTransactionRequest(request) # If we have keyword arguments corresponding to fields on the # request, apply these. @@ -898,23 +853,9 @@ async def sample_begin_transaction(): # Wrap the RPC method; this adds retry and timeout information, # and friendly error handling. - rpc = gapic_v1.method_async.wrap_method( - self._client._transport.begin_transaction, - default_retry=retries.AsyncRetry( - initial=0.1, - maximum=60.0, - multiplier=1.3, - predicate=retries.if_exception_type( - core_exceptions.DeadlineExceeded, - core_exceptions.InternalServerError, - core_exceptions.ResourceExhausted, - core_exceptions.ServiceUnavailable, - ), - deadline=60.0, - ), - default_timeout=60.0, - client_info=DEFAULT_CLIENT_INFO, - ) + rpc = self._client._transport._wrapped_methods[ + self._client._transport.begin_transaction + ] # Certain fields should be provided within the metadata header; # add these here. @@ -1007,8 +948,8 @@ async def sample_commit(): """ # Create or coerce a protobuf request object. - # Quick check: If we got a request object, we should *not* have - # gotten any keyword arguments that map to the request. + # - Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. has_flattened_params = any([database, writes]) if request is not None and has_flattened_params: raise ValueError( @@ -1016,7 +957,10 @@ async def sample_commit(): "the individual field arguments should be set." ) - request = firestore.CommitRequest(request) + # - Use the request object if provided (there's no risk of modifying the input as + # there are no flattened fields), or create one. + if not isinstance(request, firestore.CommitRequest): + request = firestore.CommitRequest(request) # If we have keyword arguments corresponding to fields on the # request, apply these. @@ -1027,21 +971,7 @@ async def sample_commit(): # Wrap the RPC method; this adds retry and timeout information, # and friendly error handling. - rpc = gapic_v1.method_async.wrap_method( - self._client._transport.commit, - default_retry=retries.AsyncRetry( - initial=0.1, - maximum=60.0, - multiplier=1.3, - predicate=retries.if_exception_type( - core_exceptions.ResourceExhausted, - core_exceptions.ServiceUnavailable, - ), - deadline=60.0, - ), - default_timeout=60.0, - client_info=DEFAULT_CLIENT_INFO, - ) + rpc = self._client._transport._wrapped_methods[self._client._transport.commit] # Certain fields should be provided within the metadata header; # add these here. @@ -1124,8 +1054,8 @@ async def sample_rollback(): sent along with the request as metadata. """ # Create or coerce a protobuf request object. - # Quick check: If we got a request object, we should *not* have - # gotten any keyword arguments that map to the request. + # - Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. has_flattened_params = any([database, transaction]) if request is not None and has_flattened_params: raise ValueError( @@ -1133,7 +1063,10 @@ async def sample_rollback(): "the individual field arguments should be set." ) - request = firestore.RollbackRequest(request) + # - Use the request object if provided (there's no risk of modifying the input as + # there are no flattened fields), or create one. + if not isinstance(request, firestore.RollbackRequest): + request = firestore.RollbackRequest(request) # If we have keyword arguments corresponding to fields on the # request, apply these. @@ -1144,23 +1077,7 @@ async def sample_rollback(): # Wrap the RPC method; this adds retry and timeout information, # and friendly error handling. - rpc = gapic_v1.method_async.wrap_method( - self._client._transport.rollback, - default_retry=retries.AsyncRetry( - initial=0.1, - maximum=60.0, - multiplier=1.3, - predicate=retries.if_exception_type( - core_exceptions.DeadlineExceeded, - core_exceptions.InternalServerError, - core_exceptions.ResourceExhausted, - core_exceptions.ServiceUnavailable, - ), - deadline=60.0, - ), - default_timeout=60.0, - client_info=DEFAULT_CLIENT_INFO, - ) + rpc = self._client._transport._wrapped_methods[self._client._transport.rollback] # Certain fields should be provided within the metadata header; # add these here. @@ -1234,27 +1151,16 @@ async def sample_run_query(): """ # Create or coerce a protobuf request object. - request = firestore.RunQueryRequest(request) + # - Use the request object if provided (there's no risk of modifying the input as + # there are no flattened fields), or create one. + if not isinstance(request, firestore.RunQueryRequest): + request = firestore.RunQueryRequest(request) # Wrap the RPC method; this adds retry and timeout information, # and friendly error handling. - rpc = gapic_v1.method_async.wrap_method( - self._client._transport.run_query, - default_retry=retries.AsyncRetry( - initial=0.1, - maximum=60.0, - multiplier=1.3, - predicate=retries.if_exception_type( - core_exceptions.DeadlineExceeded, - core_exceptions.InternalServerError, - core_exceptions.ResourceExhausted, - core_exceptions.ServiceUnavailable, - ), - deadline=300.0, - ), - default_timeout=300.0, - client_info=DEFAULT_CLIENT_INFO, - ) + rpc = self._client._transport._wrapped_methods[ + self._client._transport.run_query + ] # Certain fields should be provided within the metadata header; # add these here. @@ -1345,27 +1251,16 @@ async def sample_run_aggregation_query(): """ # Create or coerce a protobuf request object. - request = firestore.RunAggregationQueryRequest(request) + # - Use the request object if provided (there's no risk of modifying the input as + # there are no flattened fields), or create one. + if not isinstance(request, firestore.RunAggregationQueryRequest): + request = firestore.RunAggregationQueryRequest(request) # Wrap the RPC method; this adds retry and timeout information, # and friendly error handling. - rpc = gapic_v1.method_async.wrap_method( - self._client._transport.run_aggregation_query, - default_retry=retries.AsyncRetry( - initial=0.1, - maximum=60.0, - multiplier=1.3, - predicate=retries.if_exception_type( - core_exceptions.DeadlineExceeded, - core_exceptions.InternalServerError, - core_exceptions.ResourceExhausted, - core_exceptions.ServiceUnavailable, - ), - deadline=300.0, - ), - default_timeout=300.0, - client_info=DEFAULT_CLIENT_INFO, - ) + rpc = self._client._transport._wrapped_methods[ + self._client._transport.run_aggregation_query + ] # Certain fields should be provided within the metadata header; # add these here. @@ -1448,27 +1343,16 @@ async def sample_partition_query(): """ # Create or coerce a protobuf request object. - request = firestore.PartitionQueryRequest(request) + # - Use the request object if provided (there's no risk of modifying the input as + # there are no flattened fields), or create one. + if not isinstance(request, firestore.PartitionQueryRequest): + request = firestore.PartitionQueryRequest(request) # Wrap the RPC method; this adds retry and timeout information, # and friendly error handling. - rpc = gapic_v1.method_async.wrap_method( - self._client._transport.partition_query, - default_retry=retries.AsyncRetry( - initial=0.1, - maximum=60.0, - multiplier=1.3, - predicate=retries.if_exception_type( - core_exceptions.DeadlineExceeded, - core_exceptions.InternalServerError, - core_exceptions.ResourceExhausted, - core_exceptions.ServiceUnavailable, - ), - deadline=300.0, - ), - default_timeout=300.0, - client_info=DEFAULT_CLIENT_INFO, - ) + rpc = self._client._transport._wrapped_methods[ + self._client._transport.partition_query + ] # Certain fields should be provided within the metadata header; # add these here. @@ -1493,6 +1377,8 @@ async def sample_partition_query(): method=rpc, request=request, response=response, + retry=retry, + timeout=timeout, metadata=metadata, ) @@ -1579,11 +1465,7 @@ def request_generator(): # Wrap the RPC method; this adds retry and timeout information, # and friendly error handling. - rpc = gapic_v1.method_async.wrap_method( - self._client._transport.write, - default_timeout=86400.0, - client_info=DEFAULT_CLIENT_INFO, - ) + rpc = self._client._transport._wrapped_methods[self._client._transport.write] # Certain fields should be provided within the metadata header; # add these here. @@ -1674,23 +1556,7 @@ def request_generator(): # Wrap the RPC method; this adds retry and timeout information, # and friendly error handling. - rpc = gapic_v1.method_async.wrap_method( - self._client._transport.listen, - default_retry=retries.AsyncRetry( - initial=0.1, - maximum=60.0, - multiplier=1.3, - predicate=retries.if_exception_type( - core_exceptions.DeadlineExceeded, - core_exceptions.InternalServerError, - core_exceptions.ResourceExhausted, - core_exceptions.ServiceUnavailable, - ), - deadline=86400.0, - ), - default_timeout=86400.0, - client_info=DEFAULT_CLIENT_INFO, - ) + rpc = self._client._transport._wrapped_methods[self._client._transport.listen] # Certain fields should be provided within the metadata header; # add these here. @@ -1777,8 +1643,8 @@ async def sample_list_collection_ids(): """ # Create or coerce a protobuf request object. - # Quick check: If we got a request object, we should *not* have - # gotten any keyword arguments that map to the request. + # - Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. has_flattened_params = any([parent]) if request is not None and has_flattened_params: raise ValueError( @@ -1786,7 +1652,10 @@ async def sample_list_collection_ids(): "the individual field arguments should be set." ) - request = firestore.ListCollectionIdsRequest(request) + # - Use the request object if provided (there's no risk of modifying the input as + # there are no flattened fields), or create one. + if not isinstance(request, firestore.ListCollectionIdsRequest): + request = firestore.ListCollectionIdsRequest(request) # If we have keyword arguments corresponding to fields on the # request, apply these. @@ -1795,23 +1664,9 @@ async def sample_list_collection_ids(): # Wrap the RPC method; this adds retry and timeout information, # and friendly error handling. - rpc = gapic_v1.method_async.wrap_method( - self._client._transport.list_collection_ids, - default_retry=retries.AsyncRetry( - initial=0.1, - maximum=60.0, - multiplier=1.3, - predicate=retries.if_exception_type( - core_exceptions.DeadlineExceeded, - core_exceptions.InternalServerError, - core_exceptions.ResourceExhausted, - core_exceptions.ServiceUnavailable, - ), - deadline=60.0, - ), - default_timeout=60.0, - client_info=DEFAULT_CLIENT_INFO, - ) + rpc = self._client._transport._wrapped_methods[ + self._client._transport.list_collection_ids + ] # Certain fields should be provided within the metadata header; # add these here. @@ -1836,6 +1691,8 @@ async def sample_list_collection_ids(): method=rpc, request=request, response=response, + retry=retry, + timeout=timeout, metadata=metadata, ) @@ -1905,26 +1762,16 @@ async def sample_batch_write(): """ # Create or coerce a protobuf request object. - request = firestore.BatchWriteRequest(request) + # - Use the request object if provided (there's no risk of modifying the input as + # there are no flattened fields), or create one. + if not isinstance(request, firestore.BatchWriteRequest): + request = firestore.BatchWriteRequest(request) # Wrap the RPC method; this adds retry and timeout information, # and friendly error handling. - rpc = gapic_v1.method_async.wrap_method( - self._client._transport.batch_write, - default_retry=retries.AsyncRetry( - initial=0.1, - maximum=60.0, - multiplier=1.3, - predicate=retries.if_exception_type( - core_exceptions.Aborted, - core_exceptions.ResourceExhausted, - core_exceptions.ServiceUnavailable, - ), - deadline=60.0, - ), - default_timeout=60.0, - client_info=DEFAULT_CLIENT_INFO, - ) + rpc = self._client._transport._wrapped_methods[ + self._client._transport.batch_write + ] # Certain fields should be provided within the metadata header; # add these here. @@ -2001,25 +1848,16 @@ async def sample_create_document(): """ # Create or coerce a protobuf request object. - request = firestore.CreateDocumentRequest(request) + # - Use the request object if provided (there's no risk of modifying the input as + # there are no flattened fields), or create one. + if not isinstance(request, firestore.CreateDocumentRequest): + request = firestore.CreateDocumentRequest(request) # Wrap the RPC method; this adds retry and timeout information, # and friendly error handling. - rpc = gapic_v1.method_async.wrap_method( - self._client._transport.create_document, - default_retry=retries.AsyncRetry( - initial=0.1, - maximum=60.0, - multiplier=1.3, - predicate=retries.if_exception_type( - core_exceptions.ResourceExhausted, - core_exceptions.ServiceUnavailable, - ), - deadline=60.0, - ), - default_timeout=60.0, - client_info=DEFAULT_CLIENT_INFO, - ) + rpc = self._client._transport._wrapped_methods[ + self._client._transport.create_document + ] # Certain fields should be provided within the metadata header; # add these here. diff --git a/google/cloud/firestore_v1/services/firestore/client.py b/google/cloud/firestore_v1/services/firestore/client.py index ab8e766108..888c88e809 100644 --- a/google/cloud/firestore_v1/services/firestore/client.py +++ b/google/cloud/firestore_v1/services/firestore/client.py @@ -18,6 +18,7 @@ import re from typing import ( Dict, + Callable, Mapping, MutableMapping, MutableSequence, @@ -526,7 +527,9 @@ def __init__( self, *, credentials: Optional[ga_credentials.Credentials] = None, - transport: Optional[Union[str, FirestoreTransport]] = None, + transport: Optional[ + Union[str, FirestoreTransport, Callable[..., FirestoreTransport]] + ] = None, client_options: Optional[Union[client_options_lib.ClientOptions, dict]] = None, client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, ) -> None: @@ -538,9 +541,11 @@ def __init__( credentials identify the application to the service; if none are specified, the client will attempt to ascertain the credentials from the environment. - transport (Union[str, FirestoreTransport]): The - transport to use. If set to None, a transport is chosen - automatically. + transport (Optional[Union[str,FirestoreTransport,Callable[..., FirestoreTransport]]]): + The transport to use, or a Callable that constructs and returns a new transport. + If a Callable is given, it will be called with the same set of initialization + arguments as used in the FirestoreTransport constructor. + If set to None, a transport is chosen automatically. client_options (Optional[Union[google.api_core.client_options.ClientOptions, dict]]): Custom options for the client. @@ -646,8 +651,15 @@ def __init__( api_key_value ) - Transport = type(self).get_transport_class(cast(str, transport)) - self._transport = Transport( + transport_init: Union[ + Type[FirestoreTransport], Callable[..., FirestoreTransport] + ] = ( + FirestoreClient.get_transport_class(transport) + if isinstance(transport, str) or transport is None + else cast(Callable[..., FirestoreTransport], transport) + ) + # initialize with the provided callable or the passed in class + self._transport = transport_init( credentials=credentials, credentials_file=self._client_options.credentials_file, host=self._api_endpoint, @@ -714,10 +726,8 @@ def sample_get_document(): """ # Create or coerce a protobuf request object. - # Minor optimization to avoid making a copy if the user passes - # in a firestore.GetDocumentRequest. - # There's no risk of modifying the input as we've already verified - # there are no flattened fields. + # - Use the request object if provided (there's no risk of modifying the input as + # there are no flattened fields), or create one. if not isinstance(request, firestore.GetDocumentRequest): request = firestore.GetDocumentRequest(request) @@ -803,10 +813,8 @@ def sample_list_documents(): """ # Create or coerce a protobuf request object. - # Minor optimization to avoid making a copy if the user passes - # in a firestore.ListDocumentsRequest. - # There's no risk of modifying the input as we've already verified - # there are no flattened fields. + # - Use the request object if provided (there's no risk of modifying the input as + # there are no flattened fields), or create one. if not isinstance(request, firestore.ListDocumentsRequest): request = firestore.ListDocumentsRequest(request) @@ -842,6 +850,8 @@ def sample_list_documents(): method=rpc, request=request, response=response, + retry=retry, + timeout=timeout, metadata=metadata, ) @@ -926,8 +936,8 @@ def sample_update_document(): """ # Create or coerce a protobuf request object. - # Quick check: If we got a request object, we should *not* have - # gotten any keyword arguments that map to the request. + # - Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. has_flattened_params = any([document, update_mask]) if request is not None and has_flattened_params: raise ValueError( @@ -935,10 +945,8 @@ def sample_update_document(): "the individual field arguments should be set." ) - # Minor optimization to avoid making a copy if the user passes - # in a firestore.UpdateDocumentRequest. - # There's no risk of modifying the input as we've already verified - # there are no flattened fields. + # - Use the request object if provided (there's no risk of modifying the input as + # there are no flattened fields), or create one. if not isinstance(request, firestore.UpdateDocumentRequest): request = firestore.UpdateDocumentRequest(request) # If we have keyword arguments corresponding to fields on the @@ -1027,8 +1035,8 @@ def sample_delete_document(): sent along with the request as metadata. """ # Create or coerce a protobuf request object. - # Quick check: If we got a request object, we should *not* have - # gotten any keyword arguments that map to the request. + # - Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. has_flattened_params = any([name]) if request is not None and has_flattened_params: raise ValueError( @@ -1036,10 +1044,8 @@ def sample_delete_document(): "the individual field arguments should be set." ) - # Minor optimization to avoid making a copy if the user passes - # in a firestore.DeleteDocumentRequest. - # There's no risk of modifying the input as we've already verified - # there are no flattened fields. + # - Use the request object if provided (there's no risk of modifying the input as + # there are no flattened fields), or create one. if not isinstance(request, firestore.DeleteDocumentRequest): request = firestore.DeleteDocumentRequest(request) # If we have keyword arguments corresponding to fields on the @@ -1126,10 +1132,8 @@ def sample_batch_get_documents(): """ # Create or coerce a protobuf request object. - # Minor optimization to avoid making a copy if the user passes - # in a firestore.BatchGetDocumentsRequest. - # There's no risk of modifying the input as we've already verified - # there are no flattened fields. + # - Use the request object if provided (there's no risk of modifying the input as + # there are no flattened fields), or create one. if not isinstance(request, firestore.BatchGetDocumentsRequest): request = firestore.BatchGetDocumentsRequest(request) @@ -1218,8 +1222,8 @@ def sample_begin_transaction(): """ # Create or coerce a protobuf request object. - # Quick check: If we got a request object, we should *not* have - # gotten any keyword arguments that map to the request. + # - Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. has_flattened_params = any([database]) if request is not None and has_flattened_params: raise ValueError( @@ -1227,10 +1231,8 @@ def sample_begin_transaction(): "the individual field arguments should be set." ) - # Minor optimization to avoid making a copy if the user passes - # in a firestore.BeginTransactionRequest. - # There's no risk of modifying the input as we've already verified - # there are no flattened fields. + # - Use the request object if provided (there's no risk of modifying the input as + # there are no flattened fields), or create one. if not isinstance(request, firestore.BeginTransactionRequest): request = firestore.BeginTransactionRequest(request) # If we have keyword arguments corresponding to fields on the @@ -1333,8 +1335,8 @@ def sample_commit(): """ # Create or coerce a protobuf request object. - # Quick check: If we got a request object, we should *not* have - # gotten any keyword arguments that map to the request. + # - Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. has_flattened_params = any([database, writes]) if request is not None and has_flattened_params: raise ValueError( @@ -1342,10 +1344,8 @@ def sample_commit(): "the individual field arguments should be set." ) - # Minor optimization to avoid making a copy if the user passes - # in a firestore.CommitRequest. - # There's no risk of modifying the input as we've already verified - # there are no flattened fields. + # - Use the request object if provided (there's no risk of modifying the input as + # there are no flattened fields), or create one. if not isinstance(request, firestore.CommitRequest): request = firestore.CommitRequest(request) # If we have keyword arguments corresponding to fields on the @@ -1440,8 +1440,8 @@ def sample_rollback(): sent along with the request as metadata. """ # Create or coerce a protobuf request object. - # Quick check: If we got a request object, we should *not* have - # gotten any keyword arguments that map to the request. + # - Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. has_flattened_params = any([database, transaction]) if request is not None and has_flattened_params: raise ValueError( @@ -1449,10 +1449,8 @@ def sample_rollback(): "the individual field arguments should be set." ) - # Minor optimization to avoid making a copy if the user passes - # in a firestore.RollbackRequest. - # There's no risk of modifying the input as we've already verified - # there are no flattened fields. + # - Use the request object if provided (there's no risk of modifying the input as + # there are no flattened fields), or create one. if not isinstance(request, firestore.RollbackRequest): request = firestore.RollbackRequest(request) # If we have keyword arguments corresponding to fields on the @@ -1538,10 +1536,8 @@ def sample_run_query(): """ # Create or coerce a protobuf request object. - # Minor optimization to avoid making a copy if the user passes - # in a firestore.RunQueryRequest. - # There's no risk of modifying the input as we've already verified - # there are no flattened fields. + # - Use the request object if provided (there's no risk of modifying the input as + # there are no flattened fields), or create one. if not isinstance(request, firestore.RunQueryRequest): request = firestore.RunQueryRequest(request) @@ -1638,10 +1634,8 @@ def sample_run_aggregation_query(): """ # Create or coerce a protobuf request object. - # Minor optimization to avoid making a copy if the user passes - # in a firestore.RunAggregationQueryRequest. - # There's no risk of modifying the input as we've already verified - # there are no flattened fields. + # - Use the request object if provided (there's no risk of modifying the input as + # there are no flattened fields), or create one. if not isinstance(request, firestore.RunAggregationQueryRequest): request = firestore.RunAggregationQueryRequest(request) @@ -1730,10 +1724,8 @@ def sample_partition_query(): """ # Create or coerce a protobuf request object. - # Minor optimization to avoid making a copy if the user passes - # in a firestore.PartitionQueryRequest. - # There's no risk of modifying the input as we've already verified - # there are no flattened fields. + # - Use the request object if provided (there's no risk of modifying the input as + # there are no flattened fields), or create one. if not isinstance(request, firestore.PartitionQueryRequest): request = firestore.PartitionQueryRequest(request) @@ -1764,6 +1756,8 @@ def sample_partition_query(): method=rpc, request=request, response=response, + retry=retry, + timeout=timeout, metadata=metadata, ) @@ -2028,8 +2022,8 @@ def sample_list_collection_ids(): """ # Create or coerce a protobuf request object. - # Quick check: If we got a request object, we should *not* have - # gotten any keyword arguments that map to the request. + # - Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. has_flattened_params = any([parent]) if request is not None and has_flattened_params: raise ValueError( @@ -2037,10 +2031,8 @@ def sample_list_collection_ids(): "the individual field arguments should be set." ) - # Minor optimization to avoid making a copy if the user passes - # in a firestore.ListCollectionIdsRequest. - # There's no risk of modifying the input as we've already verified - # there are no flattened fields. + # - Use the request object if provided (there's no risk of modifying the input as + # there are no flattened fields), or create one. if not isinstance(request, firestore.ListCollectionIdsRequest): request = firestore.ListCollectionIdsRequest(request) # If we have keyword arguments corresponding to fields on the @@ -2075,6 +2067,8 @@ def sample_list_collection_ids(): method=rpc, request=request, response=response, + retry=retry, + timeout=timeout, metadata=metadata, ) @@ -2144,10 +2138,8 @@ def sample_batch_write(): """ # Create or coerce a protobuf request object. - # Minor optimization to avoid making a copy if the user passes - # in a firestore.BatchWriteRequest. - # There's no risk of modifying the input as we've already verified - # there are no flattened fields. + # - Use the request object if provided (there's no risk of modifying the input as + # there are no flattened fields), or create one. if not isinstance(request, firestore.BatchWriteRequest): request = firestore.BatchWriteRequest(request) @@ -2230,10 +2222,8 @@ def sample_create_document(): """ # Create or coerce a protobuf request object. - # Minor optimization to avoid making a copy if the user passes - # in a firestore.CreateDocumentRequest. - # There's no risk of modifying the input as we've already verified - # there are no flattened fields. + # - Use the request object if provided (there's no risk of modifying the input as + # there are no flattened fields), or create one. if not isinstance(request, firestore.CreateDocumentRequest): request = firestore.CreateDocumentRequest(request) diff --git a/google/cloud/firestore_v1/services/firestore/pagers.py b/google/cloud/firestore_v1/services/firestore/pagers.py index 8fe67b56d6..71ebf18fb9 100644 --- a/google/cloud/firestore_v1/services/firestore/pagers.py +++ b/google/cloud/firestore_v1/services/firestore/pagers.py @@ -13,6 +13,9 @@ # See the License for the specific language governing permissions and # limitations under the License. # +from google.api_core import gapic_v1 +from google.api_core import retry as retries +from google.api_core import retry_async as retries_async from typing import ( Any, AsyncIterator, @@ -22,8 +25,18 @@ Tuple, Optional, Iterator, + Union, ) +try: + OptionalRetry = Union[retries.Retry, gapic_v1.method._MethodDefault, None] + OptionalAsyncRetry = Union[ + retries_async.AsyncRetry, gapic_v1.method._MethodDefault, None + ] +except AttributeError: # pragma: NO COVER + OptionalRetry = Union[retries.Retry, object, None] # type: ignore + OptionalAsyncRetry = Union[retries_async.AsyncRetry, object, None] # type: ignore + from google.cloud.firestore_v1.types import document from google.cloud.firestore_v1.types import firestore from google.cloud.firestore_v1.types import query @@ -53,6 +66,8 @@ def __init__( request: firestore.ListDocumentsRequest, response: firestore.ListDocumentsResponse, *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Union[float, object] = gapic_v1.method.DEFAULT, metadata: Sequence[Tuple[str, str]] = () ): """Instantiate the pager. @@ -64,12 +79,17 @@ def __init__( The initial request object. response (google.cloud.firestore_v1.types.ListDocumentsResponse): The initial response object. + retry (google.api_core.retry.Retry): Designation of what errors, + if any, should be retried. + timeout (float): The timeout for this request. metadata (Sequence[Tuple[str, str]]): Strings which should be sent along with the request as metadata. """ self._method = method self._request = firestore.ListDocumentsRequest(request) self._response = response + self._retry = retry + self._timeout = timeout self._metadata = metadata def __getattr__(self, name: str) -> Any: @@ -80,7 +100,12 @@ def pages(self) -> Iterator[firestore.ListDocumentsResponse]: yield self._response while self._response.next_page_token: self._request.page_token = self._response.next_page_token - self._response = self._method(self._request, metadata=self._metadata) + self._response = self._method( + self._request, + retry=self._retry, + timeout=self._timeout, + metadata=self._metadata, + ) yield self._response def __iter__(self) -> Iterator[document.Document]: @@ -115,6 +140,8 @@ def __init__( request: firestore.ListDocumentsRequest, response: firestore.ListDocumentsResponse, *, + retry: OptionalAsyncRetry = gapic_v1.method.DEFAULT, + timeout: Union[float, object] = gapic_v1.method.DEFAULT, metadata: Sequence[Tuple[str, str]] = () ): """Instantiates the pager. @@ -126,12 +153,17 @@ def __init__( The initial request object. response (google.cloud.firestore_v1.types.ListDocumentsResponse): The initial response object. + retry (google.api_core.retry.AsyncRetry): Designation of what errors, + if any, should be retried. + timeout (float): The timeout for this request. metadata (Sequence[Tuple[str, str]]): Strings which should be sent along with the request as metadata. """ self._method = method self._request = firestore.ListDocumentsRequest(request) self._response = response + self._retry = retry + self._timeout = timeout self._metadata = metadata def __getattr__(self, name: str) -> Any: @@ -142,7 +174,12 @@ async def pages(self) -> AsyncIterator[firestore.ListDocumentsResponse]: yield self._response while self._response.next_page_token: self._request.page_token = self._response.next_page_token - self._response = await self._method(self._request, metadata=self._metadata) + self._response = await self._method( + self._request, + retry=self._retry, + timeout=self._timeout, + metadata=self._metadata, + ) yield self._response def __aiter__(self) -> AsyncIterator[document.Document]: @@ -181,6 +218,8 @@ def __init__( request: firestore.PartitionQueryRequest, response: firestore.PartitionQueryResponse, *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Union[float, object] = gapic_v1.method.DEFAULT, metadata: Sequence[Tuple[str, str]] = () ): """Instantiate the pager. @@ -192,12 +231,17 @@ def __init__( The initial request object. response (google.cloud.firestore_v1.types.PartitionQueryResponse): The initial response object. + retry (google.api_core.retry.Retry): Designation of what errors, + if any, should be retried. + timeout (float): The timeout for this request. metadata (Sequence[Tuple[str, str]]): Strings which should be sent along with the request as metadata. """ self._method = method self._request = firestore.PartitionQueryRequest(request) self._response = response + self._retry = retry + self._timeout = timeout self._metadata = metadata def __getattr__(self, name: str) -> Any: @@ -208,7 +252,12 @@ def pages(self) -> Iterator[firestore.PartitionQueryResponse]: yield self._response while self._response.next_page_token: self._request.page_token = self._response.next_page_token - self._response = self._method(self._request, metadata=self._metadata) + self._response = self._method( + self._request, + retry=self._retry, + timeout=self._timeout, + metadata=self._metadata, + ) yield self._response def __iter__(self) -> Iterator[query.Cursor]: @@ -243,6 +292,8 @@ def __init__( request: firestore.PartitionQueryRequest, response: firestore.PartitionQueryResponse, *, + retry: OptionalAsyncRetry = gapic_v1.method.DEFAULT, + timeout: Union[float, object] = gapic_v1.method.DEFAULT, metadata: Sequence[Tuple[str, str]] = () ): """Instantiates the pager. @@ -254,12 +305,17 @@ def __init__( The initial request object. response (google.cloud.firestore_v1.types.PartitionQueryResponse): The initial response object. + retry (google.api_core.retry.AsyncRetry): Designation of what errors, + if any, should be retried. + timeout (float): The timeout for this request. metadata (Sequence[Tuple[str, str]]): Strings which should be sent along with the request as metadata. """ self._method = method self._request = firestore.PartitionQueryRequest(request) self._response = response + self._retry = retry + self._timeout = timeout self._metadata = metadata def __getattr__(self, name: str) -> Any: @@ -270,7 +326,12 @@ async def pages(self) -> AsyncIterator[firestore.PartitionQueryResponse]: yield self._response while self._response.next_page_token: self._request.page_token = self._response.next_page_token - self._response = await self._method(self._request, metadata=self._metadata) + self._response = await self._method( + self._request, + retry=self._retry, + timeout=self._timeout, + metadata=self._metadata, + ) yield self._response def __aiter__(self) -> AsyncIterator[query.Cursor]: @@ -309,6 +370,8 @@ def __init__( request: firestore.ListCollectionIdsRequest, response: firestore.ListCollectionIdsResponse, *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Union[float, object] = gapic_v1.method.DEFAULT, metadata: Sequence[Tuple[str, str]] = () ): """Instantiate the pager. @@ -320,12 +383,17 @@ def __init__( The initial request object. response (google.cloud.firestore_v1.types.ListCollectionIdsResponse): The initial response object. + retry (google.api_core.retry.Retry): Designation of what errors, + if any, should be retried. + timeout (float): The timeout for this request. metadata (Sequence[Tuple[str, str]]): Strings which should be sent along with the request as metadata. """ self._method = method self._request = firestore.ListCollectionIdsRequest(request) self._response = response + self._retry = retry + self._timeout = timeout self._metadata = metadata def __getattr__(self, name: str) -> Any: @@ -336,7 +404,12 @@ def pages(self) -> Iterator[firestore.ListCollectionIdsResponse]: yield self._response while self._response.next_page_token: self._request.page_token = self._response.next_page_token - self._response = self._method(self._request, metadata=self._metadata) + self._response = self._method( + self._request, + retry=self._retry, + timeout=self._timeout, + metadata=self._metadata, + ) yield self._response def __iter__(self) -> Iterator[str]: @@ -371,6 +444,8 @@ def __init__( request: firestore.ListCollectionIdsRequest, response: firestore.ListCollectionIdsResponse, *, + retry: OptionalAsyncRetry = gapic_v1.method.DEFAULT, + timeout: Union[float, object] = gapic_v1.method.DEFAULT, metadata: Sequence[Tuple[str, str]] = () ): """Instantiates the pager. @@ -382,12 +457,17 @@ def __init__( The initial request object. response (google.cloud.firestore_v1.types.ListCollectionIdsResponse): The initial response object. + retry (google.api_core.retry.AsyncRetry): Designation of what errors, + if any, should be retried. + timeout (float): The timeout for this request. metadata (Sequence[Tuple[str, str]]): Strings which should be sent along with the request as metadata. """ self._method = method self._request = firestore.ListCollectionIdsRequest(request) self._response = response + self._retry = retry + self._timeout = timeout self._metadata = metadata def __getattr__(self, name: str) -> Any: @@ -398,7 +478,12 @@ async def pages(self) -> AsyncIterator[firestore.ListCollectionIdsResponse]: yield self._response while self._response.next_page_token: self._request.page_token = self._response.next_page_token - self._response = await self._method(self._request, metadata=self._metadata) + self._response = await self._method( + self._request, + retry=self._retry, + timeout=self._timeout, + metadata=self._metadata, + ) yield self._response def __aiter__(self) -> AsyncIterator[str]: diff --git a/google/cloud/firestore_v1/services/firestore/transports/base.py b/google/cloud/firestore_v1/services/firestore/transports/base.py index ebb1ceea02..d22e6ce3ba 100644 --- a/google/cloud/firestore_v1/services/firestore/transports/base.py +++ b/google/cloud/firestore_v1/services/firestore/transports/base.py @@ -90,6 +90,8 @@ def __init__( # Save the scopes. self._scopes = scopes + if not hasattr(self, "_ignore_credentials"): + self._ignore_credentials: bool = False # If no credentials are provided, then determine the appropriate # defaults. @@ -102,7 +104,7 @@ def __init__( credentials, _ = google.auth.load_credentials_from_file( credentials_file, **scopes_kwargs, quota_project_id=quota_project_id ) - elif credentials is None: + elif credentials is None and not self._ignore_credentials: credentials, _ = google.auth.default( **scopes_kwargs, quota_project_id=quota_project_id ) diff --git a/google/cloud/firestore_v1/services/firestore/transports/grpc.py b/google/cloud/firestore_v1/services/firestore/transports/grpc.py index 4b0be5eadf..7d334a5394 100644 --- a/google/cloud/firestore_v1/services/firestore/transports/grpc.py +++ b/google/cloud/firestore_v1/services/firestore/transports/grpc.py @@ -63,7 +63,7 @@ def __init__( credentials: Optional[ga_credentials.Credentials] = None, credentials_file: Optional[str] = None, scopes: Optional[Sequence[str]] = None, - channel: Optional[grpc.Channel] = None, + channel: Optional[Union[grpc.Channel, Callable[..., grpc.Channel]]] = None, api_mtls_endpoint: Optional[str] = None, client_cert_source: Optional[Callable[[], Tuple[bytes, bytes]]] = None, ssl_channel_credentials: Optional[grpc.ChannelCredentials] = None, @@ -83,14 +83,17 @@ def __init__( credentials identify the application to the service; if none are specified, the client will attempt to ascertain the credentials from the environment. - This argument is ignored if ``channel`` is provided. + This argument is ignored if a ``channel`` instance is provided. 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. + This argument is ignored if a ``channel`` instance is provided. scopes (Optional(Sequence[str])): A list of scopes. This argument is - ignored if ``channel`` is provided. - channel (Optional[grpc.Channel]): A ``Channel`` instance through - which to make calls. + ignored if a ``channel`` instance is provided. + channel (Optional[Union[grpc.Channel, Callable[..., grpc.Channel]]]): + A ``Channel`` instance through which to make calls, or a Callable + that constructs and returns one. If set to None, ``self.create_channel`` + is used to create the channel. If a Callable is given, it will be called + with the same arguments as used in ``self.create_channel``. api_mtls_endpoint (Optional[str]): Deprecated. The mutual TLS endpoint. If provided, it overrides the ``host`` argument and tries to create a mutual TLS channel with client SSL credentials from @@ -100,11 +103,11 @@ def __init__( private key bytes, both in PEM format. It is ignored if ``api_mtls_endpoint`` is None. ssl_channel_credentials (grpc.ChannelCredentials): SSL credentials - for the grpc channel. It is ignored if ``channel`` is provided. + for the grpc channel. It is ignored if a ``channel`` instance is provided. client_cert_source_for_mtls (Optional[Callable[[], Tuple[bytes, bytes]]]): A callback to provide client certificate bytes and private key bytes, both in PEM format. It is used to configure a mutual TLS channel. It is - ignored if ``channel`` or ``ssl_channel_credentials`` is provided. + ignored if a ``channel`` instance or ``ssl_channel_credentials`` is provided. quota_project_id (Optional[str]): An optional project to use for billing and quota. client_info (google.api_core.gapic_v1.client_info.ClientInfo): @@ -130,9 +133,10 @@ def __init__( if client_cert_source: warnings.warn("client_cert_source is deprecated", DeprecationWarning) - if channel: + if isinstance(channel, grpc.Channel): # Ignore credentials if a channel was passed. - credentials = False + credentials = None + self._ignore_credentials = True # If a channel was explicitly provided, set it. self._grpc_channel = channel self._ssl_channel_credentials = None @@ -171,7 +175,9 @@ def __init__( ) if not self._grpc_channel: - self._grpc_channel = type(self).create_channel( + # initialize with the provided callable or the default channel + channel_init = channel or type(self).create_channel + self._grpc_channel = channel_init( self._host, # use the credentials which are saved credentials=self._credentials, diff --git a/google/cloud/firestore_v1/services/firestore/transports/grpc_asyncio.py b/google/cloud/firestore_v1/services/firestore/transports/grpc_asyncio.py index 5199970ce3..c8eaab433a 100644 --- a/google/cloud/firestore_v1/services/firestore/transports/grpc_asyncio.py +++ b/google/cloud/firestore_v1/services/firestore/transports/grpc_asyncio.py @@ -18,6 +18,8 @@ from google.api_core import gapic_v1 from google.api_core import grpc_helpers_async +from google.api_core import exceptions as core_exceptions +from google.api_core import retry_async as retries from google.auth import credentials as ga_credentials # type: ignore from google.auth.transport.grpc import SslCredentials # type: ignore @@ -78,7 +80,6 @@ def create_channel( 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 optional list of scopes needed for this service. These are only used when credentials are not specified and are passed to :func:`google.auth.default`. @@ -108,7 +109,7 @@ def __init__( credentials: Optional[ga_credentials.Credentials] = None, credentials_file: Optional[str] = None, scopes: Optional[Sequence[str]] = None, - channel: Optional[aio.Channel] = None, + channel: Optional[Union[aio.Channel, Callable[..., aio.Channel]]] = None, api_mtls_endpoint: Optional[str] = None, client_cert_source: Optional[Callable[[], Tuple[bytes, bytes]]] = None, ssl_channel_credentials: Optional[grpc.ChannelCredentials] = None, @@ -128,15 +129,18 @@ def __init__( credentials identify the application to the service; if none are specified, the client will attempt to ascertain the credentials from the environment. - This argument is ignored if ``channel`` is provided. + This argument is ignored if a ``channel`` instance is provided. 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. + This argument is ignored if a ``channel`` instance is provided. scopes (Optional[Sequence[str]]): A optional list of scopes needed for this service. These are only used when credentials are not specified and are passed to :func:`google.auth.default`. - channel (Optional[aio.Channel]): A ``Channel`` instance through - which to make calls. + channel (Optional[Union[aio.Channel, Callable[..., aio.Channel]]]): + A ``Channel`` instance through which to make calls, or a Callable + that constructs and returns one. If set to None, ``self.create_channel`` + is used to create the channel. If a Callable is given, it will be called + with the same arguments as used in ``self.create_channel``. api_mtls_endpoint (Optional[str]): Deprecated. The mutual TLS endpoint. If provided, it overrides the ``host`` argument and tries to create a mutual TLS channel with client SSL credentials from @@ -146,11 +150,11 @@ def __init__( private key bytes, both in PEM format. It is ignored if ``api_mtls_endpoint`` is None. ssl_channel_credentials (grpc.ChannelCredentials): SSL credentials - for the grpc channel. It is ignored if ``channel`` is provided. + for the grpc channel. It is ignored if a ``channel`` instance is provided. client_cert_source_for_mtls (Optional[Callable[[], Tuple[bytes, bytes]]]): A callback to provide client certificate bytes and private key bytes, both in PEM format. It is used to configure a mutual TLS channel. It is - ignored if ``channel`` or ``ssl_channel_credentials`` is provided. + ignored if a ``channel`` instance or ``ssl_channel_credentials`` is provided. quota_project_id (Optional[str]): An optional project to use for billing and quota. client_info (google.api_core.gapic_v1.client_info.ClientInfo): @@ -176,9 +180,10 @@ def __init__( if client_cert_source: warnings.warn("client_cert_source is deprecated", DeprecationWarning) - if channel: + if isinstance(channel, aio.Channel): # Ignore credentials if a channel was passed. - credentials = False + credentials = None + self._ignore_credentials = True # If a channel was explicitly provided, set it. self._grpc_channel = channel self._ssl_channel_credentials = None @@ -216,7 +221,9 @@ def __init__( ) if not self._grpc_channel: - self._grpc_channel = type(self).create_channel( + # initialize with the provided callable or the default channel + channel_init = channel or type(self).create_channel + self._grpc_channel = channel_init( self._host, # use the credentials which are saved credentials=self._credentials, @@ -714,6 +721,264 @@ def create_document( ) return self._stubs["create_document"] + def _prep_wrapped_messages(self, client_info): + """Precompute the wrapped methods, overriding the base class method to use async wrappers.""" + self._wrapped_methods = { + self.get_document: gapic_v1.method_async.wrap_method( + self.get_document, + default_retry=retries.AsyncRetry( + initial=0.1, + maximum=60.0, + multiplier=1.3, + predicate=retries.if_exception_type( + core_exceptions.DeadlineExceeded, + core_exceptions.InternalServerError, + core_exceptions.ResourceExhausted, + core_exceptions.ServiceUnavailable, + ), + deadline=60.0, + ), + default_timeout=60.0, + client_info=client_info, + ), + self.list_documents: gapic_v1.method_async.wrap_method( + self.list_documents, + default_retry=retries.AsyncRetry( + initial=0.1, + maximum=60.0, + multiplier=1.3, + predicate=retries.if_exception_type( + core_exceptions.DeadlineExceeded, + core_exceptions.InternalServerError, + core_exceptions.ResourceExhausted, + core_exceptions.ServiceUnavailable, + ), + deadline=60.0, + ), + default_timeout=60.0, + client_info=client_info, + ), + self.update_document: gapic_v1.method_async.wrap_method( + self.update_document, + default_retry=retries.AsyncRetry( + initial=0.1, + maximum=60.0, + multiplier=1.3, + predicate=retries.if_exception_type( + core_exceptions.ResourceExhausted, + core_exceptions.ServiceUnavailable, + ), + deadline=60.0, + ), + default_timeout=60.0, + client_info=client_info, + ), + self.delete_document: gapic_v1.method_async.wrap_method( + self.delete_document, + default_retry=retries.AsyncRetry( + initial=0.1, + maximum=60.0, + multiplier=1.3, + predicate=retries.if_exception_type( + core_exceptions.DeadlineExceeded, + core_exceptions.InternalServerError, + core_exceptions.ResourceExhausted, + core_exceptions.ServiceUnavailable, + ), + deadline=60.0, + ), + default_timeout=60.0, + client_info=client_info, + ), + self.batch_get_documents: gapic_v1.method_async.wrap_method( + self.batch_get_documents, + default_retry=retries.AsyncRetry( + initial=0.1, + maximum=60.0, + multiplier=1.3, + predicate=retries.if_exception_type( + core_exceptions.DeadlineExceeded, + core_exceptions.InternalServerError, + core_exceptions.ResourceExhausted, + core_exceptions.ServiceUnavailable, + ), + deadline=300.0, + ), + default_timeout=300.0, + client_info=client_info, + ), + self.begin_transaction: gapic_v1.method_async.wrap_method( + self.begin_transaction, + default_retry=retries.AsyncRetry( + initial=0.1, + maximum=60.0, + multiplier=1.3, + predicate=retries.if_exception_type( + core_exceptions.DeadlineExceeded, + core_exceptions.InternalServerError, + core_exceptions.ResourceExhausted, + core_exceptions.ServiceUnavailable, + ), + deadline=60.0, + ), + default_timeout=60.0, + client_info=client_info, + ), + self.commit: gapic_v1.method_async.wrap_method( + self.commit, + default_retry=retries.AsyncRetry( + initial=0.1, + maximum=60.0, + multiplier=1.3, + predicate=retries.if_exception_type( + core_exceptions.ResourceExhausted, + core_exceptions.ServiceUnavailable, + ), + deadline=60.0, + ), + default_timeout=60.0, + client_info=client_info, + ), + self.rollback: gapic_v1.method_async.wrap_method( + self.rollback, + default_retry=retries.AsyncRetry( + initial=0.1, + maximum=60.0, + multiplier=1.3, + predicate=retries.if_exception_type( + core_exceptions.DeadlineExceeded, + core_exceptions.InternalServerError, + core_exceptions.ResourceExhausted, + core_exceptions.ServiceUnavailable, + ), + deadline=60.0, + ), + default_timeout=60.0, + client_info=client_info, + ), + self.run_query: gapic_v1.method_async.wrap_method( + self.run_query, + default_retry=retries.AsyncRetry( + initial=0.1, + maximum=60.0, + multiplier=1.3, + predicate=retries.if_exception_type( + core_exceptions.DeadlineExceeded, + core_exceptions.InternalServerError, + core_exceptions.ResourceExhausted, + core_exceptions.ServiceUnavailable, + ), + deadline=300.0, + ), + default_timeout=300.0, + client_info=client_info, + ), + self.run_aggregation_query: gapic_v1.method_async.wrap_method( + self.run_aggregation_query, + default_retry=retries.AsyncRetry( + initial=0.1, + maximum=60.0, + multiplier=1.3, + predicate=retries.if_exception_type( + core_exceptions.DeadlineExceeded, + core_exceptions.InternalServerError, + core_exceptions.ResourceExhausted, + core_exceptions.ServiceUnavailable, + ), + deadline=300.0, + ), + default_timeout=300.0, + client_info=client_info, + ), + self.partition_query: gapic_v1.method_async.wrap_method( + self.partition_query, + default_retry=retries.AsyncRetry( + initial=0.1, + maximum=60.0, + multiplier=1.3, + predicate=retries.if_exception_type( + core_exceptions.DeadlineExceeded, + core_exceptions.InternalServerError, + core_exceptions.ResourceExhausted, + core_exceptions.ServiceUnavailable, + ), + deadline=300.0, + ), + default_timeout=300.0, + client_info=client_info, + ), + self.write: gapic_v1.method_async.wrap_method( + self.write, + default_timeout=86400.0, + client_info=client_info, + ), + self.listen: gapic_v1.method_async.wrap_method( + self.listen, + default_retry=retries.AsyncRetry( + initial=0.1, + maximum=60.0, + multiplier=1.3, + predicate=retries.if_exception_type( + core_exceptions.DeadlineExceeded, + core_exceptions.InternalServerError, + core_exceptions.ResourceExhausted, + core_exceptions.ServiceUnavailable, + ), + deadline=86400.0, + ), + default_timeout=86400.0, + client_info=client_info, + ), + self.list_collection_ids: gapic_v1.method_async.wrap_method( + self.list_collection_ids, + default_retry=retries.AsyncRetry( + initial=0.1, + maximum=60.0, + multiplier=1.3, + predicate=retries.if_exception_type( + core_exceptions.DeadlineExceeded, + core_exceptions.InternalServerError, + core_exceptions.ResourceExhausted, + core_exceptions.ServiceUnavailable, + ), + deadline=60.0, + ), + default_timeout=60.0, + client_info=client_info, + ), + self.batch_write: gapic_v1.method_async.wrap_method( + self.batch_write, + default_retry=retries.AsyncRetry( + initial=0.1, + maximum=60.0, + multiplier=1.3, + predicate=retries.if_exception_type( + core_exceptions.Aborted, + core_exceptions.ResourceExhausted, + core_exceptions.ServiceUnavailable, + ), + deadline=60.0, + ), + default_timeout=60.0, + client_info=client_info, + ), + self.create_document: gapic_v1.method_async.wrap_method( + self.create_document, + default_retry=retries.AsyncRetry( + initial=0.1, + maximum=60.0, + multiplier=1.3, + predicate=retries.if_exception_type( + core_exceptions.ResourceExhausted, + core_exceptions.ServiceUnavailable, + ), + deadline=60.0, + ), + default_timeout=60.0, + client_info=client_info, + ), + } + def close(self): return self.grpc_channel.close() diff --git a/google/cloud/firestore_v1/types/document.py b/google/cloud/firestore_v1/types/document.py index 972eb14768..4def67f9a2 100644 --- a/google/cloud/firestore_v1/types/document.py +++ b/google/cloud/firestore_v1/types/document.py @@ -176,7 +176,7 @@ class Value(proto.Message): An array value. Cannot directly contain another array value, - though can contain an map which contains another + though can contain a map which contains another array. This field is a member of `oneof`_ ``value_type``. diff --git a/google/cloud/firestore_v1/types/query.py b/google/cloud/firestore_v1/types/query.py index b6a5949e4b..2fda44ebe3 100644 --- a/google/cloud/firestore_v1/types/query.py +++ b/google/cloud/firestore_v1/types/query.py @@ -153,8 +153,8 @@ class StructuredQuery(proto.Message): - The value must be greater than or equal to zero if specified. find_nearest (google.cloud.firestore_v1.types.StructuredQuery.FindNearest): - Optional. A potential Nearest Neighbors - Search. + Optional. A potential nearest neighbors + search. Applies after all other filters and ordering. Finds the closest vector embeddings to the given @@ -520,7 +520,10 @@ class Projection(proto.Message): ) class FindNearest(proto.Message): - r"""Nearest Neighbors search config. + r"""Nearest Neighbors search config. The ordering provided by + FindNearest supersedes the order_by stage. If multiple documents + have the same vector distance, the returned document order is not + guaranteed to be stable between queries. Attributes: vector_field (google.cloud.firestore_v1.types.StructuredQuery.FieldReference): @@ -532,12 +535,27 @@ class FindNearest(proto.Message): searching on. Must be a vector of no more than 2048 dimensions. distance_measure (google.cloud.firestore_v1.types.StructuredQuery.FindNearest.DistanceMeasure): - Required. The Distance Measure to use, + Required. The distance measure to use, required. limit (google.protobuf.wrappers_pb2.Int32Value): Required. The number of nearest neighbors to return. Must be a positive integer of no more than 1000. + distance_result_field (str): + Optional. Optional name of the field to output the result of + the vector distance calculation. Must conform to [document + field name][google.firestore.v1.Document.fields] + limitations. + distance_threshold (google.protobuf.wrappers_pb2.DoubleValue): + Optional. Option to specify a threshold for which no less + similar documents will be returned. The behavior of the + specified ``distance_measure`` will affect the meaning of + the distance threshold. Since DOT_PRODUCT distances increase + when the vectors are more similar, the comparison is + inverted. + + For EUCLIDEAN, COSINE: WHERE distance <= distance_threshold + For DOT_PRODUCT: WHERE distance >= distance_threshold """ class DistanceMeasure(proto.Enum): @@ -549,21 +567,25 @@ class DistanceMeasure(proto.Enum): EUCLIDEAN (1): Measures the EUCLIDEAN distance between the vectors. See `Euclidean `__ - to learn more + to learn more. The resulting distance decreases the more + similar two vectors are. COSINE (2): - Compares vectors based on the angle between them, which - allows you to measure similarity that isn't based on the - vectors magnitude. We recommend using DOT_PRODUCT with unit - normalized vectors instead of COSINE distance, which is - mathematically equivalent with better performance. See - `Cosine + COSINE distance compares vectors based on the angle between + them, which allows you to measure similarity that isn't + based on the vectors magnitude. We recommend using + DOT_PRODUCT with unit normalized vectors instead of COSINE + distance, which is mathematically equivalent with better + performance. See `Cosine Similarity `__ - to learn more. + to learn more about COSINE similarity and COSINE distance. + The resulting COSINE distance decreases the more similar two + vectors are. DOT_PRODUCT (3): Similar to cosine but is affected by the magnitude of the vectors. See `Dot Product `__ to - learn more. + learn more. The resulting distance increases the more + similar two vectors are. """ DISTANCE_MEASURE_UNSPECIFIED = 0 EUCLIDEAN = 1 @@ -590,6 +612,15 @@ class DistanceMeasure(proto.Enum): number=4, message=wrappers_pb2.Int32Value, ) + distance_result_field: str = proto.Field( + proto.STRING, + number=5, + ) + distance_threshold: wrappers_pb2.DoubleValue = proto.Field( + proto.MESSAGE, + number=6, + message=wrappers_pb2.DoubleValue, + ) select: Projection = proto.Field( proto.MESSAGE, diff --git a/scripts/fixup_firestore_admin_v1_keywords.py b/scripts/fixup_firestore_admin_v1_keywords.py index 85cad9a310..9bc2afbcd0 100644 --- a/scripts/fixup_firestore_admin_v1_keywords.py +++ b/scripts/fixup_firestore_admin_v1_keywords.py @@ -45,6 +45,7 @@ def partition( class firestore_adminCallTransformer(cst.CSTTransformer): CTRL_PARAMS: Tuple[str] = ('retry', 'timeout', 'metadata') METHOD_TO_PARAMS: Dict[str, Tuple[str]] = { + 'bulk_delete_documents': ('name', 'collection_ids', 'namespace_ids', ), 'create_backup_schedule': ('parent', 'backup_schedule', ), 'create_database': ('parent', 'database', 'database_id', ), 'create_index': ('parent', 'index', ), @@ -61,7 +62,7 @@ class firestore_adminCallTransformer(cst.CSTTransformer): 'import_documents': ('name', 'collection_ids', 'input_uri_prefix', 'namespace_ids', ), 'list_backups': ('parent', ), 'list_backup_schedules': ('parent', ), - 'list_databases': ('parent', ), + 'list_databases': ('parent', 'show_deleted', ), 'list_fields': ('parent', 'filter', 'page_size', 'page_token', ), 'list_indexes': ('parent', 'filter', 'page_size', 'page_token', ), 'restore_database': ('parent', 'database_id', 'backup', ), diff --git a/tests/unit/gapic/firestore_admin_v1/test_firestore_admin.py b/tests/unit/gapic/firestore_admin_v1/test_firestore_admin.py index 9564476625..07d4c09d52 100644 --- a/tests/unit/gapic/firestore_admin_v1/test_firestore_admin.py +++ b/tests/unit/gapic/firestore_admin_v1/test_firestore_admin.py @@ -22,48 +22,42 @@ except ImportError: # pragma: NO COVER import mock +import grpc +from grpc.experimental import aio +from collections.abc import Iterable +from google.protobuf import json_format import json import math -from collections.abc import Iterable - -import google.auth -import grpc import pytest -from google.api_core import operation_async # type: ignore -from google.api_core import api_core_version, client_options -from google.api_core import exceptions as core_exceptions -from google.api_core import ( - future, - gapic_v1, - grpc_helpers, - grpc_helpers_async, - operation, - operations_v1, - path_template, -) -from google.auth import credentials as ga_credentials -from google.auth.exceptions import MutualTLSChannelError -from google.cloud.location import locations_pb2 -from google.longrunning import operations_pb2 # type: ignore -from google.oauth2 import service_account -from google.protobuf import duration_pb2 # type: ignore -from google.protobuf import empty_pb2 # type: ignore -from google.protobuf import field_mask_pb2 # type: ignore -from google.protobuf import timestamp_pb2 # type: ignore -from google.protobuf import json_format -from google.type import dayofweek_pb2 # type: ignore -from grpc.experimental import aio -from proto.marshal.rules import wrappers +from google.api_core import api_core_version from proto.marshal.rules.dates import DurationRule, TimestampRule -from requests import PreparedRequest, Request, Response +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 +from google.api_core import future +from google.api_core import gapic_v1 +from google.api_core import grpc_helpers +from google.api_core import grpc_helpers_async +from google.api_core import operation +from google.api_core import operation_async # type: ignore +from google.api_core import operations_v1 +from google.api_core import path_template +from google.api_core import retry as retries +from google.auth import credentials as ga_credentials +from google.auth.exceptions import MutualTLSChannelError from google.cloud.firestore_admin_v1.services.firestore_admin import ( FirestoreAdminAsyncClient, +) +from google.cloud.firestore_admin_v1.services.firestore_admin import ( FirestoreAdminClient, - pagers, - transports, ) +from google.cloud.firestore_admin_v1.services.firestore_admin import pagers +from google.cloud.firestore_admin_v1.services.firestore_admin import transports from google.cloud.firestore_admin_v1.types import backup from google.cloud.firestore_admin_v1.types import database from google.cloud.firestore_admin_v1.types import database as gfa_database @@ -74,6 +68,15 @@ from google.cloud.firestore_admin_v1.types import index as gfa_index from google.cloud.firestore_admin_v1.types import operation as gfa_operation from google.cloud.firestore_admin_v1.types import schedule +from google.cloud.location import locations_pb2 +from google.longrunning import operations_pb2 # type: ignore +from google.oauth2 import service_account +from google.protobuf import duration_pb2 # type: ignore +from google.protobuf import empty_pb2 # type: ignore +from google.protobuf import field_mask_pb2 # type: ignore +from google.protobuf import timestamp_pb2 # type: ignore +from google.type import dayofweek_pb2 # type: ignore +import google.auth def client_cert_source_callback(): @@ -1187,6 +1190,9 @@ def test_create_index_empty_call(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.create_index), "__call__") as call: + call.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) client.create_index() call.assert_called() _, args, _ = call.mock_calls[0] @@ -1210,6 +1216,9 @@ def test_create_index_non_empty_request_with_auto_populated_field(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.create_index), "__call__") as call: + call.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) client.create_index(request=request) call.assert_called() _, args, _ = call.mock_calls[0] @@ -1218,6 +1227,46 @@ def test_create_index_non_empty_request_with_auto_populated_field(): ) +def test_create_index_use_cached_wrapped_rpc(): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method.wrap_method") as wrapper_fn: + client = FirestoreAdminClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="grpc", + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert client._transport.create_index in client._transport._wrapped_methods + + # Replace cached wrapped function with mock + mock_rpc = mock.Mock() + mock_rpc.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) + client._transport._wrapped_methods[client._transport.create_index] = mock_rpc + request = {} + client.create_index(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + # Operation methods call wrapper_fn to build a cached + # client._transport.operations_client instance on first rpc call. + # Subsequent calls should use the cached wrapper + wrapper_fn.reset_mock() + + client.create_index(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 + + @pytest.mark.asyncio async def test_create_index_empty_call_async(): # This test is a coverage failsafe to make sure that totally empty calls, @@ -1239,6 +1288,53 @@ async def test_create_index_empty_call_async(): assert args[0] == firestore_admin.CreateIndexRequest() +@pytest.mark.asyncio +async def test_create_index_async_use_cached_wrapped_rpc( + transport: str = "grpc_asyncio", +): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method_async.wrap_method") as wrapper_fn: + client = FirestoreAdminAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert ( + client._client._transport.create_index + in client._client._transport._wrapped_methods + ) + + # Replace cached wrapped function with mock + mock_rpc = mock.AsyncMock() + mock_rpc.return_value = mock.Mock() + client._client._transport._wrapped_methods[ + client._client._transport.create_index + ] = mock_rpc + + request = {} + await client.create_index(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + # Operation methods call wrapper_fn to build a cached + # client._transport.operations_client instance on first rpc call. + # Subsequent calls should use the cached wrapper + wrapper_fn.reset_mock() + + await client.create_index(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 + + @pytest.mark.asyncio async def test_create_index_async( transport: str = "grpc_asyncio", request_type=firestore_admin.CreateIndexRequest @@ -1474,6 +1570,9 @@ def test_list_indexes_empty_call(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.list_indexes), "__call__") as call: + call.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) client.list_indexes() call.assert_called() _, args, _ = call.mock_calls[0] @@ -1499,6 +1598,9 @@ def test_list_indexes_non_empty_request_with_auto_populated_field(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.list_indexes), "__call__") as call: + call.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) client.list_indexes(request=request) call.assert_called() _, args, _ = call.mock_calls[0] @@ -1509,6 +1611,41 @@ def test_list_indexes_non_empty_request_with_auto_populated_field(): ) +def test_list_indexes_use_cached_wrapped_rpc(): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method.wrap_method") as wrapper_fn: + client = FirestoreAdminClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="grpc", + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert client._transport.list_indexes in client._transport._wrapped_methods + + # Replace cached wrapped function with mock + mock_rpc = mock.Mock() + mock_rpc.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) + client._transport._wrapped_methods[client._transport.list_indexes] = mock_rpc + request = {} + client.list_indexes(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + client.list_indexes(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 + + @pytest.mark.asyncio async def test_list_indexes_empty_call_async(): # This test is a coverage failsafe to make sure that totally empty calls, @@ -1532,6 +1669,48 @@ async def test_list_indexes_empty_call_async(): assert args[0] == firestore_admin.ListIndexesRequest() +@pytest.mark.asyncio +async def test_list_indexes_async_use_cached_wrapped_rpc( + transport: str = "grpc_asyncio", +): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method_async.wrap_method") as wrapper_fn: + client = FirestoreAdminAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert ( + client._client._transport.list_indexes + in client._client._transport._wrapped_methods + ) + + # Replace cached wrapped function with mock + mock_rpc = mock.AsyncMock() + mock_rpc.return_value = mock.Mock() + client._client._transport._wrapped_methods[ + client._client._transport.list_indexes + ] = mock_rpc + + request = {} + await client.list_indexes(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + await client.list_indexes(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 + + @pytest.mark.asyncio async def test_list_indexes_async( transport: str = "grpc_asyncio", request_type=firestore_admin.ListIndexesRequest @@ -1751,13 +1930,17 @@ def test_list_indexes_pager(transport_name: str = "grpc"): RuntimeError, ) - metadata = () - metadata = tuple(metadata) + ( + expected_metadata = () + retry = retries.Retry() + timeout = 5 + expected_metadata = tuple(expected_metadata) + ( gapic_v1.routing_header.to_grpc_metadata((("parent", ""),)), ) - pager = client.list_indexes(request={}) + pager = client.list_indexes(request={}, retry=retry, timeout=timeout) - assert pager._metadata == metadata + assert pager._metadata == expected_metadata + assert pager._retry == retry + assert pager._timeout == timeout results = list(pager) assert len(results) == 6 @@ -1956,6 +2139,9 @@ def test_get_index_empty_call(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.get_index), "__call__") as call: + call.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) client.get_index() call.assert_called() _, args, _ = call.mock_calls[0] @@ -1979,6 +2165,9 @@ def test_get_index_non_empty_request_with_auto_populated_field(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.get_index), "__call__") as call: + call.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) client.get_index(request=request) call.assert_called() _, args, _ = call.mock_calls[0] @@ -1987,6 +2176,41 @@ def test_get_index_non_empty_request_with_auto_populated_field(): ) +def test_get_index_use_cached_wrapped_rpc(): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method.wrap_method") as wrapper_fn: + client = FirestoreAdminClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="grpc", + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert client._transport.get_index in client._transport._wrapped_methods + + # Replace cached wrapped function with mock + mock_rpc = mock.Mock() + mock_rpc.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) + client._transport._wrapped_methods[client._transport.get_index] = mock_rpc + request = {} + client.get_index(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + client.get_index(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 + + @pytest.mark.asyncio async def test_get_index_empty_call_async(): # This test is a coverage failsafe to make sure that totally empty calls, @@ -2013,6 +2237,46 @@ async def test_get_index_empty_call_async(): assert args[0] == firestore_admin.GetIndexRequest() +@pytest.mark.asyncio +async def test_get_index_async_use_cached_wrapped_rpc(transport: str = "grpc_asyncio"): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method_async.wrap_method") as wrapper_fn: + client = FirestoreAdminAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert ( + client._client._transport.get_index + in client._client._transport._wrapped_methods + ) + + # Replace cached wrapped function with mock + mock_rpc = mock.AsyncMock() + mock_rpc.return_value = mock.Mock() + client._client._transport._wrapped_methods[ + client._client._transport.get_index + ] = mock_rpc + + request = {} + await client.get_index(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + await client.get_index(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 + + @pytest.mark.asyncio async def test_get_index_async( transport: str = "grpc_asyncio", request_type=firestore_admin.GetIndexRequest @@ -2240,6 +2504,9 @@ def test_delete_index_empty_call(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.delete_index), "__call__") as call: + call.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) client.delete_index() call.assert_called() _, args, _ = call.mock_calls[0] @@ -2263,6 +2530,9 @@ def test_delete_index_non_empty_request_with_auto_populated_field(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.delete_index), "__call__") as call: + call.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) client.delete_index(request=request) call.assert_called() _, args, _ = call.mock_calls[0] @@ -2271,6 +2541,41 @@ def test_delete_index_non_empty_request_with_auto_populated_field(): ) +def test_delete_index_use_cached_wrapped_rpc(): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method.wrap_method") as wrapper_fn: + client = FirestoreAdminClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="grpc", + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert client._transport.delete_index in client._transport._wrapped_methods + + # Replace cached wrapped function with mock + mock_rpc = mock.Mock() + mock_rpc.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) + client._transport._wrapped_methods[client._transport.delete_index] = mock_rpc + request = {} + client.delete_index(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + client.delete_index(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 + + @pytest.mark.asyncio async def test_delete_index_empty_call_async(): # This test is a coverage failsafe to make sure that totally empty calls, @@ -2290,6 +2595,48 @@ async def test_delete_index_empty_call_async(): assert args[0] == firestore_admin.DeleteIndexRequest() +@pytest.mark.asyncio +async def test_delete_index_async_use_cached_wrapped_rpc( + transport: str = "grpc_asyncio", +): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method_async.wrap_method") as wrapper_fn: + client = FirestoreAdminAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert ( + client._client._transport.delete_index + in client._client._transport._wrapped_methods + ) + + # Replace cached wrapped function with mock + mock_rpc = mock.AsyncMock() + mock_rpc.return_value = mock.Mock() + client._client._transport._wrapped_methods[ + client._client._transport.delete_index + ] = mock_rpc + + request = {} + await client.delete_index(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + await client.delete_index(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 + + @pytest.mark.asyncio async def test_delete_index_async( transport: str = "grpc_asyncio", request_type=firestore_admin.DeleteIndexRequest @@ -2509,6 +2856,9 @@ def test_get_field_empty_call(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.get_field), "__call__") as call: + call.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) client.get_field() call.assert_called() _, args, _ = call.mock_calls[0] @@ -2532,6 +2882,9 @@ def test_get_field_non_empty_request_with_auto_populated_field(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.get_field), "__call__") as call: + call.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) client.get_field(request=request) call.assert_called() _, args, _ = call.mock_calls[0] @@ -2540,6 +2893,41 @@ def test_get_field_non_empty_request_with_auto_populated_field(): ) +def test_get_field_use_cached_wrapped_rpc(): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method.wrap_method") as wrapper_fn: + client = FirestoreAdminClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="grpc", + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert client._transport.get_field in client._transport._wrapped_methods + + # Replace cached wrapped function with mock + mock_rpc = mock.Mock() + mock_rpc.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) + client._transport._wrapped_methods[client._transport.get_field] = mock_rpc + request = {} + client.get_field(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + client.get_field(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 + + @pytest.mark.asyncio async def test_get_field_empty_call_async(): # This test is a coverage failsafe to make sure that totally empty calls, @@ -2563,6 +2951,46 @@ async def test_get_field_empty_call_async(): assert args[0] == firestore_admin.GetFieldRequest() +@pytest.mark.asyncio +async def test_get_field_async_use_cached_wrapped_rpc(transport: str = "grpc_asyncio"): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method_async.wrap_method") as wrapper_fn: + client = FirestoreAdminAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert ( + client._client._transport.get_field + in client._client._transport._wrapped_methods + ) + + # Replace cached wrapped function with mock + mock_rpc = mock.AsyncMock() + mock_rpc.return_value = mock.Mock() + client._client._transport._wrapped_methods[ + client._client._transport.get_field + ] = mock_rpc + + request = {} + await client.get_field(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + await client.get_field(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 + + @pytest.mark.asyncio async def test_get_field_async( transport: str = "grpc_asyncio", request_type=firestore_admin.GetFieldRequest @@ -2784,6 +3212,9 @@ def test_update_field_empty_call(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.update_field), "__call__") as call: + call.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) client.update_field() call.assert_called() _, args, _ = call.mock_calls[0] @@ -2805,12 +3236,55 @@ def test_update_field_non_empty_request_with_auto_populated_field(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.update_field), "__call__") as call: + call.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) client.update_field(request=request) call.assert_called() _, args, _ = call.mock_calls[0] assert args[0] == firestore_admin.UpdateFieldRequest() +def test_update_field_use_cached_wrapped_rpc(): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method.wrap_method") as wrapper_fn: + client = FirestoreAdminClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="grpc", + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert client._transport.update_field in client._transport._wrapped_methods + + # Replace cached wrapped function with mock + mock_rpc = mock.Mock() + mock_rpc.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) + client._transport._wrapped_methods[client._transport.update_field] = mock_rpc + request = {} + client.update_field(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + # Operation methods call wrapper_fn to build a cached + # client._transport.operations_client instance on first rpc call. + # Subsequent calls should use the cached wrapper + wrapper_fn.reset_mock() + + client.update_field(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 + + @pytest.mark.asyncio async def test_update_field_empty_call_async(): # This test is a coverage failsafe to make sure that totally empty calls, @@ -2833,19 +3307,66 @@ async def test_update_field_empty_call_async(): @pytest.mark.asyncio -async def test_update_field_async( - transport: str = "grpc_asyncio", request_type=firestore_admin.UpdateFieldRequest +async def test_update_field_async_use_cached_wrapped_rpc( + transport: str = "grpc_asyncio", ): - client = FirestoreAdminAsyncClient( - credentials=ga_credentials.AnonymousCredentials(), - transport=transport, - ) + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method_async.wrap_method") as wrapper_fn: + client = FirestoreAdminAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) - # Everything is optional in proto3 as far as the runtime is concerned, - # and we are mocking out the actual API, so just send an empty request. - request = request_type() + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() - # Mock the actual call within the gRPC stub, and fake the request. + # Ensure method has been cached + assert ( + client._client._transport.update_field + in client._client._transport._wrapped_methods + ) + + # Replace cached wrapped function with mock + mock_rpc = mock.AsyncMock() + mock_rpc.return_value = mock.Mock() + client._client._transport._wrapped_methods[ + client._client._transport.update_field + ] = mock_rpc + + request = {} + await client.update_field(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + # Operation methods call wrapper_fn to build a cached + # client._transport.operations_client instance on first rpc call. + # Subsequent calls should use the cached wrapper + wrapper_fn.reset_mock() + + await client.update_field(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 + + +@pytest.mark.asyncio +async def test_update_field_async( + transport: str = "grpc_asyncio", request_type=firestore_admin.UpdateFieldRequest +): + client = FirestoreAdminAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.update_field), "__call__") as call: # Designate an appropriate return value for the call. call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( @@ -3057,6 +3578,9 @@ def test_list_fields_empty_call(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.list_fields), "__call__") as call: + call.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) client.list_fields() call.assert_called() _, args, _ = call.mock_calls[0] @@ -3082,6 +3606,9 @@ def test_list_fields_non_empty_request_with_auto_populated_field(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.list_fields), "__call__") as call: + call.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) client.list_fields(request=request) call.assert_called() _, args, _ = call.mock_calls[0] @@ -3092,6 +3619,41 @@ def test_list_fields_non_empty_request_with_auto_populated_field(): ) +def test_list_fields_use_cached_wrapped_rpc(): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method.wrap_method") as wrapper_fn: + client = FirestoreAdminClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="grpc", + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert client._transport.list_fields in client._transport._wrapped_methods + + # Replace cached wrapped function with mock + mock_rpc = mock.Mock() + mock_rpc.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) + client._transport._wrapped_methods[client._transport.list_fields] = mock_rpc + request = {} + client.list_fields(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + client.list_fields(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 + + @pytest.mark.asyncio async def test_list_fields_empty_call_async(): # This test is a coverage failsafe to make sure that totally empty calls, @@ -3115,6 +3677,48 @@ async def test_list_fields_empty_call_async(): assert args[0] == firestore_admin.ListFieldsRequest() +@pytest.mark.asyncio +async def test_list_fields_async_use_cached_wrapped_rpc( + transport: str = "grpc_asyncio", +): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method_async.wrap_method") as wrapper_fn: + client = FirestoreAdminAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert ( + client._client._transport.list_fields + in client._client._transport._wrapped_methods + ) + + # Replace cached wrapped function with mock + mock_rpc = mock.AsyncMock() + mock_rpc.return_value = mock.Mock() + client._client._transport._wrapped_methods[ + client._client._transport.list_fields + ] = mock_rpc + + request = {} + await client.list_fields(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + await client.list_fields(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 + + @pytest.mark.asyncio async def test_list_fields_async( transport: str = "grpc_asyncio", request_type=firestore_admin.ListFieldsRequest @@ -3334,13 +3938,17 @@ def test_list_fields_pager(transport_name: str = "grpc"): RuntimeError, ) - metadata = () - metadata = tuple(metadata) + ( + expected_metadata = () + retry = retries.Retry() + timeout = 5 + expected_metadata = tuple(expected_metadata) + ( gapic_v1.routing_header.to_grpc_metadata((("parent", ""),)), ) - pager = client.list_fields(request={}) + pager = client.list_fields(request={}, retry=retry, timeout=timeout) - assert pager._metadata == metadata + assert pager._metadata == expected_metadata + assert pager._retry == retry + assert pager._timeout == timeout results = list(pager) assert len(results) == 6 @@ -3530,6 +4138,9 @@ def test_export_documents_empty_call(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.export_documents), "__call__") as call: + call.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) client.export_documents() call.assert_called() _, args, _ = call.mock_calls[0] @@ -3554,6 +4165,9 @@ def test_export_documents_non_empty_request_with_auto_populated_field(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.export_documents), "__call__") as call: + call.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) client.export_documents(request=request) call.assert_called() _, args, _ = call.mock_calls[0] @@ -3563,6 +4177,48 @@ def test_export_documents_non_empty_request_with_auto_populated_field(): ) +def test_export_documents_use_cached_wrapped_rpc(): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method.wrap_method") as wrapper_fn: + client = FirestoreAdminClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="grpc", + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert client._transport.export_documents in client._transport._wrapped_methods + + # Replace cached wrapped function with mock + mock_rpc = mock.Mock() + mock_rpc.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) + client._transport._wrapped_methods[ + client._transport.export_documents + ] = mock_rpc + request = {} + client.export_documents(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + # Operation methods call wrapper_fn to build a cached + # client._transport.operations_client instance on first rpc call. + # Subsequent calls should use the cached wrapper + wrapper_fn.reset_mock() + + client.export_documents(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 + + @pytest.mark.asyncio async def test_export_documents_empty_call_async(): # This test is a coverage failsafe to make sure that totally empty calls, @@ -3584,6 +4240,53 @@ async def test_export_documents_empty_call_async(): assert args[0] == firestore_admin.ExportDocumentsRequest() +@pytest.mark.asyncio +async def test_export_documents_async_use_cached_wrapped_rpc( + transport: str = "grpc_asyncio", +): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method_async.wrap_method") as wrapper_fn: + client = FirestoreAdminAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert ( + client._client._transport.export_documents + in client._client._transport._wrapped_methods + ) + + # Replace cached wrapped function with mock + mock_rpc = mock.AsyncMock() + mock_rpc.return_value = mock.Mock() + client._client._transport._wrapped_methods[ + client._client._transport.export_documents + ] = mock_rpc + + request = {} + await client.export_documents(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + # Operation methods call wrapper_fn to build a cached + # client._transport.operations_client instance on first rpc call. + # Subsequent calls should use the cached wrapper + wrapper_fn.reset_mock() + + await client.export_documents(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 + + @pytest.mark.asyncio async def test_export_documents_async( transport: str = "grpc_asyncio", request_type=firestore_admin.ExportDocumentsRequest @@ -3806,6 +4509,9 @@ def test_import_documents_empty_call(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.import_documents), "__call__") as call: + call.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) client.import_documents() call.assert_called() _, args, _ = call.mock_calls[0] @@ -3830,6 +4536,9 @@ def test_import_documents_non_empty_request_with_auto_populated_field(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.import_documents), "__call__") as call: + call.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) client.import_documents(request=request) call.assert_called() _, args, _ = call.mock_calls[0] @@ -3839,6 +4548,48 @@ def test_import_documents_non_empty_request_with_auto_populated_field(): ) +def test_import_documents_use_cached_wrapped_rpc(): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method.wrap_method") as wrapper_fn: + client = FirestoreAdminClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="grpc", + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert client._transport.import_documents in client._transport._wrapped_methods + + # Replace cached wrapped function with mock + mock_rpc = mock.Mock() + mock_rpc.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) + client._transport._wrapped_methods[ + client._transport.import_documents + ] = mock_rpc + request = {} + client.import_documents(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + # Operation methods call wrapper_fn to build a cached + # client._transport.operations_client instance on first rpc call. + # Subsequent calls should use the cached wrapper + wrapper_fn.reset_mock() + + client.import_documents(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 + + @pytest.mark.asyncio async def test_import_documents_empty_call_async(): # This test is a coverage failsafe to make sure that totally empty calls, @@ -3860,6 +4611,53 @@ async def test_import_documents_empty_call_async(): assert args[0] == firestore_admin.ImportDocumentsRequest() +@pytest.mark.asyncio +async def test_import_documents_async_use_cached_wrapped_rpc( + transport: str = "grpc_asyncio", +): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method_async.wrap_method") as wrapper_fn: + client = FirestoreAdminAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert ( + client._client._transport.import_documents + in client._client._transport._wrapped_methods + ) + + # Replace cached wrapped function with mock + mock_rpc = mock.AsyncMock() + mock_rpc.return_value = mock.Mock() + client._client._transport._wrapped_methods[ + client._client._transport.import_documents + ] = mock_rpc + + request = {} + await client.import_documents(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + # Operation methods call wrapper_fn to build a cached + # client._transport.operations_client instance on first rpc call. + # Subsequent calls should use the cached wrapper + wrapper_fn.reset_mock() + + await client.import_documents(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 + + @pytest.mark.asyncio async def test_import_documents_async( transport: str = "grpc_asyncio", request_type=firestore_admin.ImportDocumentsRequest @@ -4042,11 +4840,11 @@ async def test_import_documents_flattened_error_async(): @pytest.mark.parametrize( "request_type", [ - firestore_admin.CreateDatabaseRequest, + firestore_admin.BulkDeleteDocumentsRequest, dict, ], ) -def test_create_database(request_type, transport: str = "grpc"): +def test_bulk_delete_documents(request_type, transport: str = "grpc"): client = FirestoreAdminClient( credentials=ga_credentials.AnonymousCredentials(), transport=transport, @@ -4057,22 +4855,24 @@ def test_create_database(request_type, transport: str = "grpc"): request = request_type() # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client.transport.create_database), "__call__") as call: + with mock.patch.object( + type(client.transport.bulk_delete_documents), "__call__" + ) as call: # Designate an appropriate return value for the call. call.return_value = operations_pb2.Operation(name="operations/spam") - response = client.create_database(request) + response = client.bulk_delete_documents(request) # Establish that the underlying gRPC stub method was called. assert len(call.mock_calls) == 1 _, args, _ = call.mock_calls[0] - request = firestore_admin.CreateDatabaseRequest() + request = firestore_admin.BulkDeleteDocumentsRequest() assert args[0] == request # Establish that the response is the type that we expect. assert isinstance(response, future.Future) -def test_create_database_empty_call(): +def test_bulk_delete_documents_empty_call(): # This test is a coverage failsafe to make sure that totally empty calls, # i.e. request == None and no flattened fields passed, work. client = FirestoreAdminClient( @@ -4081,14 +4881,19 @@ def test_create_database_empty_call(): ) # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client.transport.create_database), "__call__") as call: - client.create_database() + with mock.patch.object( + type(client.transport.bulk_delete_documents), "__call__" + ) as call: + call.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) + client.bulk_delete_documents() call.assert_called() _, args, _ = call.mock_calls[0] - assert args[0] == firestore_admin.CreateDatabaseRequest() + assert args[0] == firestore_admin.BulkDeleteDocumentsRequest() -def test_create_database_non_empty_request_with_auto_populated_field(): +def test_bulk_delete_documents_non_empty_request_with_auto_populated_field(): # This test is a coverage failsafe to make sure that UUID4 fields are # automatically populated, according to AIP-4235, with non-empty requests. client = FirestoreAdminClient( @@ -4099,24 +4904,72 @@ def test_create_database_non_empty_request_with_auto_populated_field(): # Populate all string fields in the request which are not UUID4 # since we want to check that UUID4 are populated automatically # if they meet the requirements of AIP 4235. - request = firestore_admin.CreateDatabaseRequest( - parent="parent_value", - database_id="database_id_value", + request = firestore_admin.BulkDeleteDocumentsRequest( + name="name_value", ) # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client.transport.create_database), "__call__") as call: - client.create_database(request=request) + with mock.patch.object( + type(client.transport.bulk_delete_documents), "__call__" + ) as call: + call.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) + client.bulk_delete_documents(request=request) call.assert_called() _, args, _ = call.mock_calls[0] - assert args[0] == firestore_admin.CreateDatabaseRequest( - parent="parent_value", - database_id="database_id_value", + assert args[0] == firestore_admin.BulkDeleteDocumentsRequest( + name="name_value", + ) + + +def test_bulk_delete_documents_use_cached_wrapped_rpc(): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method.wrap_method") as wrapper_fn: + client = FirestoreAdminClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="grpc", + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert ( + client._transport.bulk_delete_documents + in client._transport._wrapped_methods + ) + + # Replace cached wrapped function with mock + mock_rpc = mock.Mock() + mock_rpc.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. ) + client._transport._wrapped_methods[ + client._transport.bulk_delete_documents + ] = mock_rpc + request = {} + client.bulk_delete_documents(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + # Operation methods call wrapper_fn to build a cached + # client._transport.operations_client instance on first rpc call. + # Subsequent calls should use the cached wrapper + wrapper_fn.reset_mock() + + client.bulk_delete_documents(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 @pytest.mark.asyncio -async def test_create_database_empty_call_async(): +async def test_bulk_delete_documents_empty_call_async(): # This test is a coverage failsafe to make sure that totally empty calls, # i.e. request == None and no flattened fields passed, work. client = FirestoreAdminAsyncClient( @@ -4125,20 +4978,70 @@ async def test_create_database_empty_call_async(): ) # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client.transport.create_database), "__call__") as call: + with mock.patch.object( + type(client.transport.bulk_delete_documents), "__call__" + ) as call: # Designate an appropriate return value for the call. call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( operations_pb2.Operation(name="operations/spam") ) - response = await client.create_database() + response = await client.bulk_delete_documents() call.assert_called() _, args, _ = call.mock_calls[0] - assert args[0] == firestore_admin.CreateDatabaseRequest() + assert args[0] == firestore_admin.BulkDeleteDocumentsRequest() @pytest.mark.asyncio -async def test_create_database_async( - transport: str = "grpc_asyncio", request_type=firestore_admin.CreateDatabaseRequest +async def test_bulk_delete_documents_async_use_cached_wrapped_rpc( + transport: str = "grpc_asyncio", +): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method_async.wrap_method") as wrapper_fn: + client = FirestoreAdminAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert ( + client._client._transport.bulk_delete_documents + in client._client._transport._wrapped_methods + ) + + # Replace cached wrapped function with mock + mock_rpc = mock.AsyncMock() + mock_rpc.return_value = mock.Mock() + client._client._transport._wrapped_methods[ + client._client._transport.bulk_delete_documents + ] = mock_rpc + + request = {} + await client.bulk_delete_documents(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + # Operation methods call wrapper_fn to build a cached + # client._transport.operations_client instance on first rpc call. + # Subsequent calls should use the cached wrapper + wrapper_fn.reset_mock() + + await client.bulk_delete_documents(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 + + +@pytest.mark.asyncio +async def test_bulk_delete_documents_async( + transport: str = "grpc_asyncio", + request_type=firestore_admin.BulkDeleteDocumentsRequest, ): client = FirestoreAdminAsyncClient( credentials=ga_credentials.AnonymousCredentials(), @@ -4150,17 +5053,19 @@ async def test_create_database_async( request = request_type() # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client.transport.create_database), "__call__") as call: + with mock.patch.object( + type(client.transport.bulk_delete_documents), "__call__" + ) as call: # Designate an appropriate return value for the call. call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( operations_pb2.Operation(name="operations/spam") ) - response = await client.create_database(request) + response = await client.bulk_delete_documents(request) # Establish that the underlying gRPC stub method was called. assert len(call.mock_calls) _, args, _ = call.mock_calls[0] - request = firestore_admin.CreateDatabaseRequest() + request = firestore_admin.BulkDeleteDocumentsRequest() assert args[0] == request # Establish that the response is the type that we expect. @@ -4168,25 +5073,27 @@ async def test_create_database_async( @pytest.mark.asyncio -async def test_create_database_async_from_dict(): - await test_create_database_async(request_type=dict) +async def test_bulk_delete_documents_async_from_dict(): + await test_bulk_delete_documents_async(request_type=dict) -def test_create_database_field_headers(): +def test_bulk_delete_documents_field_headers(): client = FirestoreAdminClient( credentials=ga_credentials.AnonymousCredentials(), ) # Any value that is part of the HTTP/1.1 URI should be sent as # a field header. Set these to a non-empty value. - request = firestore_admin.CreateDatabaseRequest() + request = firestore_admin.BulkDeleteDocumentsRequest() - request.parent = "parent_value" + request.name = "name_value" # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client.transport.create_database), "__call__") as call: + with mock.patch.object( + type(client.transport.bulk_delete_documents), "__call__" + ) as call: call.return_value = operations_pb2.Operation(name="operations/op") - client.create_database(request) + client.bulk_delete_documents(request) # Establish that the underlying gRPC stub method was called. assert len(call.mock_calls) == 1 @@ -4197,28 +5104,30 @@ def test_create_database_field_headers(): _, _, kw = call.mock_calls[0] assert ( "x-goog-request-params", - "parent=parent_value", + "name=name_value", ) in kw["metadata"] @pytest.mark.asyncio -async def test_create_database_field_headers_async(): +async def test_bulk_delete_documents_field_headers_async(): client = FirestoreAdminAsyncClient( credentials=ga_credentials.AnonymousCredentials(), ) # Any value that is part of the HTTP/1.1 URI should be sent as # a field header. Set these to a non-empty value. - request = firestore_admin.CreateDatabaseRequest() + request = firestore_admin.BulkDeleteDocumentsRequest() - request.parent = "parent_value" + request.name = "name_value" # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client.transport.create_database), "__call__") as call: + with mock.patch.object( + type(client.transport.bulk_delete_documents), "__call__" + ) as call: call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( operations_pb2.Operation(name="operations/op") ) - await client.create_database(request) + await client.bulk_delete_documents(request) # Establish that the underlying gRPC stub method was called. assert len(call.mock_calls) @@ -4229,43 +5138,37 @@ async def test_create_database_field_headers_async(): _, _, kw = call.mock_calls[0] assert ( "x-goog-request-params", - "parent=parent_value", + "name=name_value", ) in kw["metadata"] -def test_create_database_flattened(): +def test_bulk_delete_documents_flattened(): client = FirestoreAdminClient( credentials=ga_credentials.AnonymousCredentials(), ) # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client.transport.create_database), "__call__") as call: + with mock.patch.object( + type(client.transport.bulk_delete_documents), "__call__" + ) as call: # Designate an appropriate return value for the call. call.return_value = operations_pb2.Operation(name="operations/op") # Call the method with a truthy value for each flattened field, # using the keyword arguments to the method. - client.create_database( - parent="parent_value", - database=gfa_database.Database(name="name_value"), - database_id="database_id_value", + client.bulk_delete_documents( + name="name_value", ) # Establish that the underlying call was made with the expected # request object values. assert len(call.mock_calls) == 1 _, args, _ = call.mock_calls[0] - arg = args[0].parent - mock_val = "parent_value" - assert arg == mock_val - arg = args[0].database - mock_val = gfa_database.Database(name="name_value") - assert arg == mock_val - arg = args[0].database_id - mock_val = "database_id_value" + arg = args[0].name + mock_val = "name_value" assert arg == mock_val -def test_create_database_flattened_error(): +def test_bulk_delete_documents_flattened_error(): client = FirestoreAdminClient( credentials=ga_credentials.AnonymousCredentials(), ) @@ -4273,22 +5176,22 @@ def test_create_database_flattened_error(): # Attempting to call a method with both a request object and flattened # fields is an error. with pytest.raises(ValueError): - client.create_database( - firestore_admin.CreateDatabaseRequest(), - parent="parent_value", - database=gfa_database.Database(name="name_value"), - database_id="database_id_value", + client.bulk_delete_documents( + firestore_admin.BulkDeleteDocumentsRequest(), + name="name_value", ) @pytest.mark.asyncio -async def test_create_database_flattened_async(): +async def test_bulk_delete_documents_flattened_async(): client = FirestoreAdminAsyncClient( credentials=ga_credentials.AnonymousCredentials(), ) # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client.transport.create_database), "__call__") as call: + with mock.patch.object( + type(client.transport.bulk_delete_documents), "__call__" + ) as call: # Designate an appropriate return value for the call. call.return_value = operations_pb2.Operation(name="operations/op") @@ -4297,29 +5200,21 @@ async def test_create_database_flattened_async(): ) # Call the method with a truthy value for each flattened field, # using the keyword arguments to the method. - response = await client.create_database( - parent="parent_value", - database=gfa_database.Database(name="name_value"), - database_id="database_id_value", + response = await client.bulk_delete_documents( + name="name_value", ) # Establish that the underlying call was made with the expected # request object values. assert len(call.mock_calls) _, args, _ = call.mock_calls[0] - arg = args[0].parent - mock_val = "parent_value" - assert arg == mock_val - arg = args[0].database - mock_val = gfa_database.Database(name="name_value") - assert arg == mock_val - arg = args[0].database_id - mock_val = "database_id_value" + arg = args[0].name + mock_val = "name_value" assert arg == mock_val @pytest.mark.asyncio -async def test_create_database_flattened_error_async(): +async def test_bulk_delete_documents_flattened_error_async(): client = FirestoreAdminAsyncClient( credentials=ga_credentials.AnonymousCredentials(), ) @@ -4327,22 +5222,20 @@ async def test_create_database_flattened_error_async(): # Attempting to call a method with both a request object and flattened # fields is an error. with pytest.raises(ValueError): - await client.create_database( - firestore_admin.CreateDatabaseRequest(), - parent="parent_value", - database=gfa_database.Database(name="name_value"), - database_id="database_id_value", + await client.bulk_delete_documents( + firestore_admin.BulkDeleteDocumentsRequest(), + name="name_value", ) @pytest.mark.parametrize( "request_type", [ - firestore_admin.GetDatabaseRequest, + firestore_admin.CreateDatabaseRequest, dict, ], ) -def test_get_database(request_type, transport: str = "grpc"): +def test_create_database(request_type, transport: str = "grpc"): client = FirestoreAdminClient( credentials=ga_credentials.AnonymousCredentials(), transport=transport, @@ -4353,52 +5246,22 @@ def test_get_database(request_type, transport: str = "grpc"): request = request_type() # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client.transport.get_database), "__call__") as call: + with mock.patch.object(type(client.transport.create_database), "__call__") as call: # Designate an appropriate return value for the call. - call.return_value = database.Database( - name="name_value", - uid="uid_value", - location_id="location_id_value", - type_=database.Database.DatabaseType.FIRESTORE_NATIVE, - concurrency_mode=database.Database.ConcurrencyMode.OPTIMISTIC, - point_in_time_recovery_enablement=database.Database.PointInTimeRecoveryEnablement.POINT_IN_TIME_RECOVERY_ENABLED, - app_engine_integration_mode=database.Database.AppEngineIntegrationMode.ENABLED, - key_prefix="key_prefix_value", - delete_protection_state=database.Database.DeleteProtectionState.DELETE_PROTECTION_DISABLED, - etag="etag_value", - ) - response = client.get_database(request) + call.return_value = operations_pb2.Operation(name="operations/spam") + response = client.create_database(request) # Establish that the underlying gRPC stub method was called. assert len(call.mock_calls) == 1 _, args, _ = call.mock_calls[0] - request = firestore_admin.GetDatabaseRequest() + request = firestore_admin.CreateDatabaseRequest() assert args[0] == request # Establish that the response is the type that we expect. - assert isinstance(response, database.Database) - assert response.name == "name_value" - assert response.uid == "uid_value" - assert response.location_id == "location_id_value" - assert response.type_ == database.Database.DatabaseType.FIRESTORE_NATIVE - assert response.concurrency_mode == database.Database.ConcurrencyMode.OPTIMISTIC - assert ( - response.point_in_time_recovery_enablement - == database.Database.PointInTimeRecoveryEnablement.POINT_IN_TIME_RECOVERY_ENABLED - ) - assert ( - response.app_engine_integration_mode - == database.Database.AppEngineIntegrationMode.ENABLED - ) - assert response.key_prefix == "key_prefix_value" - assert ( - response.delete_protection_state - == database.Database.DeleteProtectionState.DELETE_PROTECTION_DISABLED - ) - assert response.etag == "etag_value" + assert isinstance(response, future.Future) -def test_get_database_empty_call(): +def test_create_database_empty_call(): # This test is a coverage failsafe to make sure that totally empty calls, # i.e. request == None and no flattened fields passed, work. client = FirestoreAdminClient( @@ -4407,14 +5270,17 @@ def test_get_database_empty_call(): ) # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client.transport.get_database), "__call__") as call: - client.get_database() + with mock.patch.object(type(client.transport.create_database), "__call__") as call: + call.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) + client.create_database() call.assert_called() _, args, _ = call.mock_calls[0] - assert args[0] == firestore_admin.GetDatabaseRequest() + assert args[0] == firestore_admin.CreateDatabaseRequest() -def test_get_database_non_empty_request_with_auto_populated_field(): +def test_create_database_non_empty_request_with_auto_populated_field(): # This test is a coverage failsafe to make sure that UUID4 fields are # automatically populated, according to AIP-4235, with non-empty requests. client = FirestoreAdminClient( @@ -4425,22 +5291,67 @@ def test_get_database_non_empty_request_with_auto_populated_field(): # Populate all string fields in the request which are not UUID4 # since we want to check that UUID4 are populated automatically # if they meet the requirements of AIP 4235. - request = firestore_admin.GetDatabaseRequest( - name="name_value", + request = firestore_admin.CreateDatabaseRequest( + parent="parent_value", + database_id="database_id_value", ) # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client.transport.get_database), "__call__") as call: - client.get_database(request=request) + with mock.patch.object(type(client.transport.create_database), "__call__") as call: + call.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) + client.create_database(request=request) call.assert_called() _, args, _ = call.mock_calls[0] - assert args[0] == firestore_admin.GetDatabaseRequest( - name="name_value", + assert args[0] == firestore_admin.CreateDatabaseRequest( + parent="parent_value", + database_id="database_id_value", + ) + + +def test_create_database_use_cached_wrapped_rpc(): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method.wrap_method") as wrapper_fn: + client = FirestoreAdminClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="grpc", ) + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert client._transport.create_database in client._transport._wrapped_methods + + # Replace cached wrapped function with mock + mock_rpc = mock.Mock() + mock_rpc.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) + client._transport._wrapped_methods[client._transport.create_database] = mock_rpc + request = {} + client.create_database(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + # Operation methods call wrapper_fn to build a cached + # client._transport.operations_client instance on first rpc call. + # Subsequent calls should use the cached wrapper + wrapper_fn.reset_mock() + + client.create_database(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 + @pytest.mark.asyncio -async def test_get_database_empty_call_async(): +async def test_create_database_empty_call_async(): # This test is a coverage failsafe to make sure that totally empty calls, # i.e. request == None and no flattened fields passed, work. client = FirestoreAdminAsyncClient( @@ -4449,31 +5360,67 @@ async def test_get_database_empty_call_async(): ) # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client.transport.get_database), "__call__") as call: + with mock.patch.object(type(client.transport.create_database), "__call__") as call: # Designate an appropriate return value for the call. call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( - database.Database( - name="name_value", - uid="uid_value", - location_id="location_id_value", - type_=database.Database.DatabaseType.FIRESTORE_NATIVE, - concurrency_mode=database.Database.ConcurrencyMode.OPTIMISTIC, - point_in_time_recovery_enablement=database.Database.PointInTimeRecoveryEnablement.POINT_IN_TIME_RECOVERY_ENABLED, - app_engine_integration_mode=database.Database.AppEngineIntegrationMode.ENABLED, - key_prefix="key_prefix_value", - delete_protection_state=database.Database.DeleteProtectionState.DELETE_PROTECTION_DISABLED, - etag="etag_value", - ) + operations_pb2.Operation(name="operations/spam") ) - response = await client.get_database() + response = await client.create_database() call.assert_called() _, args, _ = call.mock_calls[0] - assert args[0] == firestore_admin.GetDatabaseRequest() + assert args[0] == firestore_admin.CreateDatabaseRequest() @pytest.mark.asyncio -async def test_get_database_async( - transport: str = "grpc_asyncio", request_type=firestore_admin.GetDatabaseRequest +async def test_create_database_async_use_cached_wrapped_rpc( + transport: str = "grpc_asyncio", +): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method_async.wrap_method") as wrapper_fn: + client = FirestoreAdminAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert ( + client._client._transport.create_database + in client._client._transport._wrapped_methods + ) + + # Replace cached wrapped function with mock + mock_rpc = mock.AsyncMock() + mock_rpc.return_value = mock.Mock() + client._client._transport._wrapped_methods[ + client._client._transport.create_database + ] = mock_rpc + + request = {} + await client.create_database(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + # Operation methods call wrapper_fn to build a cached + # client._transport.operations_client instance on first rpc call. + # Subsequent calls should use the cached wrapper + wrapper_fn.reset_mock() + + await client.create_database(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 + + +@pytest.mark.asyncio +async def test_create_database_async( + transport: str = "grpc_asyncio", request_type=firestore_admin.CreateDatabaseRequest ): client = FirestoreAdminAsyncClient( credentials=ga_credentials.AnonymousCredentials(), @@ -4485,73 +5432,43 @@ async def test_get_database_async( request = request_type() # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client.transport.get_database), "__call__") as call: + with mock.patch.object(type(client.transport.create_database), "__call__") as call: # Designate an appropriate return value for the call. call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( - database.Database( - name="name_value", - uid="uid_value", - location_id="location_id_value", - type_=database.Database.DatabaseType.FIRESTORE_NATIVE, - concurrency_mode=database.Database.ConcurrencyMode.OPTIMISTIC, - point_in_time_recovery_enablement=database.Database.PointInTimeRecoveryEnablement.POINT_IN_TIME_RECOVERY_ENABLED, - app_engine_integration_mode=database.Database.AppEngineIntegrationMode.ENABLED, - key_prefix="key_prefix_value", - delete_protection_state=database.Database.DeleteProtectionState.DELETE_PROTECTION_DISABLED, - etag="etag_value", - ) + operations_pb2.Operation(name="operations/spam") ) - response = await client.get_database(request) + response = await client.create_database(request) # Establish that the underlying gRPC stub method was called. assert len(call.mock_calls) _, args, _ = call.mock_calls[0] - request = firestore_admin.GetDatabaseRequest() + request = firestore_admin.CreateDatabaseRequest() assert args[0] == request # Establish that the response is the type that we expect. - assert isinstance(response, database.Database) - assert response.name == "name_value" - assert response.uid == "uid_value" - assert response.location_id == "location_id_value" - assert response.type_ == database.Database.DatabaseType.FIRESTORE_NATIVE - assert response.concurrency_mode == database.Database.ConcurrencyMode.OPTIMISTIC - assert ( - response.point_in_time_recovery_enablement - == database.Database.PointInTimeRecoveryEnablement.POINT_IN_TIME_RECOVERY_ENABLED - ) - assert ( - response.app_engine_integration_mode - == database.Database.AppEngineIntegrationMode.ENABLED - ) - assert response.key_prefix == "key_prefix_value" - assert ( - response.delete_protection_state - == database.Database.DeleteProtectionState.DELETE_PROTECTION_DISABLED - ) - assert response.etag == "etag_value" + assert isinstance(response, future.Future) @pytest.mark.asyncio -async def test_get_database_async_from_dict(): - await test_get_database_async(request_type=dict) +async def test_create_database_async_from_dict(): + await test_create_database_async(request_type=dict) -def test_get_database_field_headers(): +def test_create_database_field_headers(): client = FirestoreAdminClient( credentials=ga_credentials.AnonymousCredentials(), ) # Any value that is part of the HTTP/1.1 URI should be sent as # a field header. Set these to a non-empty value. - request = firestore_admin.GetDatabaseRequest() + request = firestore_admin.CreateDatabaseRequest() - request.name = "name_value" + request.parent = "parent_value" # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client.transport.get_database), "__call__") as call: - call.return_value = database.Database() - client.get_database(request) + with mock.patch.object(type(client.transport.create_database), "__call__") as call: + call.return_value = operations_pb2.Operation(name="operations/op") + client.create_database(request) # Establish that the underlying gRPC stub method was called. assert len(call.mock_calls) == 1 @@ -4562,26 +5479,28 @@ def test_get_database_field_headers(): _, _, kw = call.mock_calls[0] assert ( "x-goog-request-params", - "name=name_value", + "parent=parent_value", ) in kw["metadata"] @pytest.mark.asyncio -async def test_get_database_field_headers_async(): +async def test_create_database_field_headers_async(): client = FirestoreAdminAsyncClient( credentials=ga_credentials.AnonymousCredentials(), ) # Any value that is part of the HTTP/1.1 URI should be sent as # a field header. Set these to a non-empty value. - request = firestore_admin.GetDatabaseRequest() + request = firestore_admin.CreateDatabaseRequest() - request.name = "name_value" + request.parent = "parent_value" # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client.transport.get_database), "__call__") as call: - call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(database.Database()) - await client.get_database(request) + with mock.patch.object(type(client.transport.create_database), "__call__") as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + operations_pb2.Operation(name="operations/op") + ) + await client.create_database(request) # Establish that the underlying gRPC stub method was called. assert len(call.mock_calls) @@ -4592,35 +5511,43 @@ async def test_get_database_field_headers_async(): _, _, kw = call.mock_calls[0] assert ( "x-goog-request-params", - "name=name_value", + "parent=parent_value", ) in kw["metadata"] -def test_get_database_flattened(): +def test_create_database_flattened(): client = FirestoreAdminClient( credentials=ga_credentials.AnonymousCredentials(), ) # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client.transport.get_database), "__call__") as call: + with mock.patch.object(type(client.transport.create_database), "__call__") as call: # Designate an appropriate return value for the call. - call.return_value = database.Database() + call.return_value = operations_pb2.Operation(name="operations/op") # Call the method with a truthy value for each flattened field, # using the keyword arguments to the method. - client.get_database( - name="name_value", + client.create_database( + parent="parent_value", + database=gfa_database.Database(name="name_value"), + database_id="database_id_value", ) # Establish that the underlying call was made with the expected # request object values. assert len(call.mock_calls) == 1 _, args, _ = call.mock_calls[0] - arg = args[0].name - mock_val = "name_value" + arg = args[0].parent + mock_val = "parent_value" + assert arg == mock_val + arg = args[0].database + mock_val = gfa_database.Database(name="name_value") + assert arg == mock_val + arg = args[0].database_id + mock_val = "database_id_value" assert arg == mock_val -def test_get_database_flattened_error(): +def test_create_database_flattened_error(): client = FirestoreAdminClient( credentials=ga_credentials.AnonymousCredentials(), ) @@ -4628,41 +5555,53 @@ def test_get_database_flattened_error(): # Attempting to call a method with both a request object and flattened # fields is an error. with pytest.raises(ValueError): - client.get_database( - firestore_admin.GetDatabaseRequest(), - name="name_value", + client.create_database( + firestore_admin.CreateDatabaseRequest(), + parent="parent_value", + database=gfa_database.Database(name="name_value"), + database_id="database_id_value", ) @pytest.mark.asyncio -async def test_get_database_flattened_async(): +async def test_create_database_flattened_async(): client = FirestoreAdminAsyncClient( credentials=ga_credentials.AnonymousCredentials(), ) # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client.transport.get_database), "__call__") as call: + with mock.patch.object(type(client.transport.create_database), "__call__") as call: # Designate an appropriate return value for the call. - call.return_value = database.Database() + call.return_value = operations_pb2.Operation(name="operations/op") - call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(database.Database()) + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + operations_pb2.Operation(name="operations/spam") + ) # Call the method with a truthy value for each flattened field, # using the keyword arguments to the method. - response = await client.get_database( - name="name_value", + response = await client.create_database( + parent="parent_value", + database=gfa_database.Database(name="name_value"), + database_id="database_id_value", ) # Establish that the underlying call was made with the expected # request object values. assert len(call.mock_calls) _, args, _ = call.mock_calls[0] - arg = args[0].name - mock_val = "name_value" + arg = args[0].parent + mock_val = "parent_value" + assert arg == mock_val + arg = args[0].database + mock_val = gfa_database.Database(name="name_value") + assert arg == mock_val + arg = args[0].database_id + mock_val = "database_id_value" assert arg == mock_val @pytest.mark.asyncio -async def test_get_database_flattened_error_async(): +async def test_create_database_flattened_error_async(): client = FirestoreAdminAsyncClient( credentials=ga_credentials.AnonymousCredentials(), ) @@ -4670,20 +5609,22 @@ async def test_get_database_flattened_error_async(): # Attempting to call a method with both a request object and flattened # fields is an error. with pytest.raises(ValueError): - await client.get_database( - firestore_admin.GetDatabaseRequest(), - name="name_value", + await client.create_database( + firestore_admin.CreateDatabaseRequest(), + parent="parent_value", + database=gfa_database.Database(name="name_value"), + database_id="database_id_value", ) @pytest.mark.parametrize( "request_type", [ - firestore_admin.ListDatabasesRequest, + firestore_admin.GetDatabaseRequest, dict, ], ) -def test_list_databases(request_type, transport: str = "grpc"): +def test_get_database(request_type, transport: str = "grpc"): client = FirestoreAdminClient( credentials=ga_credentials.AnonymousCredentials(), transport=transport, @@ -4694,25 +5635,52 @@ def test_list_databases(request_type, transport: str = "grpc"): request = request_type() # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client.transport.list_databases), "__call__") as call: + with mock.patch.object(type(client.transport.get_database), "__call__") as call: # Designate an appropriate return value for the call. - call.return_value = firestore_admin.ListDatabasesResponse( - unreachable=["unreachable_value"], + call.return_value = database.Database( + name="name_value", + uid="uid_value", + location_id="location_id_value", + type_=database.Database.DatabaseType.FIRESTORE_NATIVE, + concurrency_mode=database.Database.ConcurrencyMode.OPTIMISTIC, + point_in_time_recovery_enablement=database.Database.PointInTimeRecoveryEnablement.POINT_IN_TIME_RECOVERY_ENABLED, + app_engine_integration_mode=database.Database.AppEngineIntegrationMode.ENABLED, + key_prefix="key_prefix_value", + delete_protection_state=database.Database.DeleteProtectionState.DELETE_PROTECTION_DISABLED, + etag="etag_value", ) - response = client.list_databases(request) + response = client.get_database(request) # Establish that the underlying gRPC stub method was called. assert len(call.mock_calls) == 1 _, args, _ = call.mock_calls[0] - request = firestore_admin.ListDatabasesRequest() + request = firestore_admin.GetDatabaseRequest() assert args[0] == request # Establish that the response is the type that we expect. - assert isinstance(response, firestore_admin.ListDatabasesResponse) - assert response.unreachable == ["unreachable_value"] + assert isinstance(response, database.Database) + assert response.name == "name_value" + assert response.uid == "uid_value" + assert response.location_id == "location_id_value" + assert response.type_ == database.Database.DatabaseType.FIRESTORE_NATIVE + assert response.concurrency_mode == database.Database.ConcurrencyMode.OPTIMISTIC + assert ( + response.point_in_time_recovery_enablement + == database.Database.PointInTimeRecoveryEnablement.POINT_IN_TIME_RECOVERY_ENABLED + ) + assert ( + response.app_engine_integration_mode + == database.Database.AppEngineIntegrationMode.ENABLED + ) + assert response.key_prefix == "key_prefix_value" + assert ( + response.delete_protection_state + == database.Database.DeleteProtectionState.DELETE_PROTECTION_DISABLED + ) + assert response.etag == "etag_value" -def test_list_databases_empty_call(): +def test_get_database_empty_call(): # This test is a coverage failsafe to make sure that totally empty calls, # i.e. request == None and no flattened fields passed, work. client = FirestoreAdminClient( @@ -4721,14 +5689,17 @@ def test_list_databases_empty_call(): ) # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client.transport.list_databases), "__call__") as call: - client.list_databases() + with mock.patch.object(type(client.transport.get_database), "__call__") as call: + call.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) + client.get_database() call.assert_called() _, args, _ = call.mock_calls[0] - assert args[0] == firestore_admin.ListDatabasesRequest() + assert args[0] == firestore_admin.GetDatabaseRequest() -def test_list_databases_non_empty_request_with_auto_populated_field(): +def test_get_database_non_empty_request_with_auto_populated_field(): # This test is a coverage failsafe to make sure that UUID4 fields are # automatically populated, according to AIP-4235, with non-empty requests. client = FirestoreAdminClient( @@ -4739,22 +5710,60 @@ def test_list_databases_non_empty_request_with_auto_populated_field(): # Populate all string fields in the request which are not UUID4 # since we want to check that UUID4 are populated automatically # if they meet the requirements of AIP 4235. - request = firestore_admin.ListDatabasesRequest( - parent="parent_value", + request = firestore_admin.GetDatabaseRequest( + name="name_value", ) # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client.transport.list_databases), "__call__") as call: - client.list_databases(request=request) + with mock.patch.object(type(client.transport.get_database), "__call__") as call: + call.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) + client.get_database(request=request) call.assert_called() _, args, _ = call.mock_calls[0] - assert args[0] == firestore_admin.ListDatabasesRequest( - parent="parent_value", + assert args[0] == firestore_admin.GetDatabaseRequest( + name="name_value", + ) + + +def test_get_database_use_cached_wrapped_rpc(): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method.wrap_method") as wrapper_fn: + client = FirestoreAdminClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="grpc", + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert client._transport.get_database in client._transport._wrapped_methods + + # Replace cached wrapped function with mock + mock_rpc = mock.Mock() + mock_rpc.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. ) + client._transport._wrapped_methods[client._transport.get_database] = mock_rpc + request = {} + client.get_database(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + client.get_database(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 @pytest.mark.asyncio -async def test_list_databases_empty_call_async(): +async def test_get_database_empty_call_async(): # This test is a coverage failsafe to make sure that totally empty calls, # i.e. request == None and no flattened fields passed, work. client = FirestoreAdminAsyncClient( @@ -4763,22 +5772,73 @@ async def test_list_databases_empty_call_async(): ) # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client.transport.list_databases), "__call__") as call: + with mock.patch.object(type(client.transport.get_database), "__call__") as call: # Designate an appropriate return value for the call. call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( - firestore_admin.ListDatabasesResponse( - unreachable=["unreachable_value"], + database.Database( + name="name_value", + uid="uid_value", + location_id="location_id_value", + type_=database.Database.DatabaseType.FIRESTORE_NATIVE, + concurrency_mode=database.Database.ConcurrencyMode.OPTIMISTIC, + point_in_time_recovery_enablement=database.Database.PointInTimeRecoveryEnablement.POINT_IN_TIME_RECOVERY_ENABLED, + app_engine_integration_mode=database.Database.AppEngineIntegrationMode.ENABLED, + key_prefix="key_prefix_value", + delete_protection_state=database.Database.DeleteProtectionState.DELETE_PROTECTION_DISABLED, + etag="etag_value", ) ) - response = await client.list_databases() + response = await client.get_database() call.assert_called() _, args, _ = call.mock_calls[0] - assert args[0] == firestore_admin.ListDatabasesRequest() + assert args[0] == firestore_admin.GetDatabaseRequest() @pytest.mark.asyncio -async def test_list_databases_async( - transport: str = "grpc_asyncio", request_type=firestore_admin.ListDatabasesRequest +async def test_get_database_async_use_cached_wrapped_rpc( + transport: str = "grpc_asyncio", +): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method_async.wrap_method") as wrapper_fn: + client = FirestoreAdminAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert ( + client._client._transport.get_database + in client._client._transport._wrapped_methods + ) + + # Replace cached wrapped function with mock + mock_rpc = mock.AsyncMock() + mock_rpc.return_value = mock.Mock() + client._client._transport._wrapped_methods[ + client._client._transport.get_database + ] = mock_rpc + + request = {} + await client.get_database(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + await client.get_database(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 + + +@pytest.mark.asyncio +async def test_get_database_async( + transport: str = "grpc_asyncio", request_type=firestore_admin.GetDatabaseRequest ): client = FirestoreAdminAsyncClient( credentials=ga_credentials.AnonymousCredentials(), @@ -4790,46 +5850,73 @@ async def test_list_databases_async( request = request_type() # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client.transport.list_databases), "__call__") as call: + with mock.patch.object(type(client.transport.get_database), "__call__") as call: # Designate an appropriate return value for the call. call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( - firestore_admin.ListDatabasesResponse( - unreachable=["unreachable_value"], + database.Database( + name="name_value", + uid="uid_value", + location_id="location_id_value", + type_=database.Database.DatabaseType.FIRESTORE_NATIVE, + concurrency_mode=database.Database.ConcurrencyMode.OPTIMISTIC, + point_in_time_recovery_enablement=database.Database.PointInTimeRecoveryEnablement.POINT_IN_TIME_RECOVERY_ENABLED, + app_engine_integration_mode=database.Database.AppEngineIntegrationMode.ENABLED, + key_prefix="key_prefix_value", + delete_protection_state=database.Database.DeleteProtectionState.DELETE_PROTECTION_DISABLED, + etag="etag_value", ) ) - response = await client.list_databases(request) + response = await client.get_database(request) # Establish that the underlying gRPC stub method was called. assert len(call.mock_calls) _, args, _ = call.mock_calls[0] - request = firestore_admin.ListDatabasesRequest() + request = firestore_admin.GetDatabaseRequest() assert args[0] == request # Establish that the response is the type that we expect. - assert isinstance(response, firestore_admin.ListDatabasesResponse) - assert response.unreachable == ["unreachable_value"] + assert isinstance(response, database.Database) + assert response.name == "name_value" + assert response.uid == "uid_value" + assert response.location_id == "location_id_value" + assert response.type_ == database.Database.DatabaseType.FIRESTORE_NATIVE + assert response.concurrency_mode == database.Database.ConcurrencyMode.OPTIMISTIC + assert ( + response.point_in_time_recovery_enablement + == database.Database.PointInTimeRecoveryEnablement.POINT_IN_TIME_RECOVERY_ENABLED + ) + assert ( + response.app_engine_integration_mode + == database.Database.AppEngineIntegrationMode.ENABLED + ) + assert response.key_prefix == "key_prefix_value" + assert ( + response.delete_protection_state + == database.Database.DeleteProtectionState.DELETE_PROTECTION_DISABLED + ) + assert response.etag == "etag_value" @pytest.mark.asyncio -async def test_list_databases_async_from_dict(): - await test_list_databases_async(request_type=dict) +async def test_get_database_async_from_dict(): + await test_get_database_async(request_type=dict) -def test_list_databases_field_headers(): +def test_get_database_field_headers(): client = FirestoreAdminClient( credentials=ga_credentials.AnonymousCredentials(), ) # Any value that is part of the HTTP/1.1 URI should be sent as # a field header. Set these to a non-empty value. - request = firestore_admin.ListDatabasesRequest() + request = firestore_admin.GetDatabaseRequest() - request.parent = "parent_value" + request.name = "name_value" # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client.transport.list_databases), "__call__") as call: - call.return_value = firestore_admin.ListDatabasesResponse() - client.list_databases(request) + with mock.patch.object(type(client.transport.get_database), "__call__") as call: + call.return_value = database.Database() + client.get_database(request) # Establish that the underlying gRPC stub method was called. assert len(call.mock_calls) == 1 @@ -4840,30 +5927,28 @@ def test_list_databases_field_headers(): _, _, kw = call.mock_calls[0] assert ( "x-goog-request-params", - "parent=parent_value", + "name=name_value", ) in kw["metadata"] @pytest.mark.asyncio -async def test_list_databases_field_headers_async(): +async def test_get_database_field_headers_async(): client = FirestoreAdminAsyncClient( credentials=ga_credentials.AnonymousCredentials(), ) # Any value that is part of the HTTP/1.1 URI should be sent as # a field header. Set these to a non-empty value. - request = firestore_admin.ListDatabasesRequest() + request = firestore_admin.GetDatabaseRequest() - request.parent = "parent_value" + request.name = "name_value" # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client.transport.list_databases), "__call__") as call: - call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( - firestore_admin.ListDatabasesResponse() - ) - await client.list_databases(request) - - # Establish that the underlying gRPC stub method was called. + with mock.patch.object(type(client.transport.get_database), "__call__") as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(database.Database()) + await client.get_database(request) + + # Establish that the underlying gRPC stub method was called. assert len(call.mock_calls) _, args, _ = call.mock_calls[0] assert args[0] == request @@ -4872,35 +5957,35 @@ async def test_list_databases_field_headers_async(): _, _, kw = call.mock_calls[0] assert ( "x-goog-request-params", - "parent=parent_value", + "name=name_value", ) in kw["metadata"] -def test_list_databases_flattened(): +def test_get_database_flattened(): client = FirestoreAdminClient( credentials=ga_credentials.AnonymousCredentials(), ) # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client.transport.list_databases), "__call__") as call: + with mock.patch.object(type(client.transport.get_database), "__call__") as call: # Designate an appropriate return value for the call. - call.return_value = firestore_admin.ListDatabasesResponse() + call.return_value = database.Database() # Call the method with a truthy value for each flattened field, # using the keyword arguments to the method. - client.list_databases( - parent="parent_value", + client.get_database( + name="name_value", ) # Establish that the underlying call was made with the expected # request object values. assert len(call.mock_calls) == 1 _, args, _ = call.mock_calls[0] - arg = args[0].parent - mock_val = "parent_value" + arg = args[0].name + mock_val = "name_value" assert arg == mock_val -def test_list_databases_flattened_error(): +def test_get_database_flattened_error(): client = FirestoreAdminClient( credentials=ga_credentials.AnonymousCredentials(), ) @@ -4908,43 +5993,41 @@ def test_list_databases_flattened_error(): # Attempting to call a method with both a request object and flattened # fields is an error. with pytest.raises(ValueError): - client.list_databases( - firestore_admin.ListDatabasesRequest(), - parent="parent_value", + client.get_database( + firestore_admin.GetDatabaseRequest(), + name="name_value", ) @pytest.mark.asyncio -async def test_list_databases_flattened_async(): +async def test_get_database_flattened_async(): client = FirestoreAdminAsyncClient( credentials=ga_credentials.AnonymousCredentials(), ) # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client.transport.list_databases), "__call__") as call: + with mock.patch.object(type(client.transport.get_database), "__call__") as call: # Designate an appropriate return value for the call. - call.return_value = firestore_admin.ListDatabasesResponse() + call.return_value = database.Database() - call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( - firestore_admin.ListDatabasesResponse() - ) + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(database.Database()) # Call the method with a truthy value for each flattened field, # using the keyword arguments to the method. - response = await client.list_databases( - parent="parent_value", + response = await client.get_database( + name="name_value", ) # Establish that the underlying call was made with the expected # request object values. assert len(call.mock_calls) _, args, _ = call.mock_calls[0] - arg = args[0].parent - mock_val = "parent_value" + arg = args[0].name + mock_val = "name_value" assert arg == mock_val @pytest.mark.asyncio -async def test_list_databases_flattened_error_async(): +async def test_get_database_flattened_error_async(): client = FirestoreAdminAsyncClient( credentials=ga_credentials.AnonymousCredentials(), ) @@ -4952,20 +6035,20 @@ async def test_list_databases_flattened_error_async(): # Attempting to call a method with both a request object and flattened # fields is an error. with pytest.raises(ValueError): - await client.list_databases( - firestore_admin.ListDatabasesRequest(), - parent="parent_value", + await client.get_database( + firestore_admin.GetDatabaseRequest(), + name="name_value", ) @pytest.mark.parametrize( "request_type", [ - firestore_admin.UpdateDatabaseRequest, + firestore_admin.ListDatabasesRequest, dict, ], ) -def test_update_database(request_type, transport: str = "grpc"): +def test_list_databases(request_type, transport: str = "grpc"): client = FirestoreAdminClient( credentials=ga_credentials.AnonymousCredentials(), transport=transport, @@ -4976,22 +6059,25 @@ def test_update_database(request_type, transport: str = "grpc"): request = request_type() # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client.transport.update_database), "__call__") as call: + with mock.patch.object(type(client.transport.list_databases), "__call__") as call: # Designate an appropriate return value for the call. - call.return_value = operations_pb2.Operation(name="operations/spam") - response = client.update_database(request) + call.return_value = firestore_admin.ListDatabasesResponse( + unreachable=["unreachable_value"], + ) + response = client.list_databases(request) # Establish that the underlying gRPC stub method was called. assert len(call.mock_calls) == 1 _, args, _ = call.mock_calls[0] - request = firestore_admin.UpdateDatabaseRequest() + request = firestore_admin.ListDatabasesRequest() assert args[0] == request # Establish that the response is the type that we expect. - assert isinstance(response, future.Future) + assert isinstance(response, firestore_admin.ListDatabasesResponse) + assert response.unreachable == ["unreachable_value"] -def test_update_database_empty_call(): +def test_list_databases_empty_call(): # This test is a coverage failsafe to make sure that totally empty calls, # i.e. request == None and no flattened fields passed, work. client = FirestoreAdminClient( @@ -5000,14 +6086,17 @@ def test_update_database_empty_call(): ) # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client.transport.update_database), "__call__") as call: - client.update_database() + with mock.patch.object(type(client.transport.list_databases), "__call__") as call: + call.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) + client.list_databases() call.assert_called() _, args, _ = call.mock_calls[0] - assert args[0] == firestore_admin.UpdateDatabaseRequest() + assert args[0] == firestore_admin.ListDatabasesRequest() -def test_update_database_non_empty_request_with_auto_populated_field(): +def test_list_databases_non_empty_request_with_auto_populated_field(): # This test is a coverage failsafe to make sure that UUID4 fields are # automatically populated, according to AIP-4235, with non-empty requests. client = FirestoreAdminClient( @@ -5018,18 +6107,60 @@ def test_update_database_non_empty_request_with_auto_populated_field(): # Populate all string fields in the request which are not UUID4 # since we want to check that UUID4 are populated automatically # if they meet the requirements of AIP 4235. - request = firestore_admin.UpdateDatabaseRequest() + request = firestore_admin.ListDatabasesRequest( + parent="parent_value", + ) # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client.transport.update_database), "__call__") as call: - client.update_database(request=request) + with mock.patch.object(type(client.transport.list_databases), "__call__") as call: + call.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) + client.list_databases(request=request) call.assert_called() _, args, _ = call.mock_calls[0] - assert args[0] == firestore_admin.UpdateDatabaseRequest() + assert args[0] == firestore_admin.ListDatabasesRequest( + parent="parent_value", + ) + + +def test_list_databases_use_cached_wrapped_rpc(): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method.wrap_method") as wrapper_fn: + client = FirestoreAdminClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="grpc", + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert client._transport.list_databases in client._transport._wrapped_methods + + # Replace cached wrapped function with mock + mock_rpc = mock.Mock() + mock_rpc.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) + client._transport._wrapped_methods[client._transport.list_databases] = mock_rpc + request = {} + client.list_databases(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + client.list_databases(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 @pytest.mark.asyncio -async def test_update_database_empty_call_async(): +async def test_list_databases_empty_call_async(): # This test is a coverage failsafe to make sure that totally empty calls, # i.e. request == None and no flattened fields passed, work. client = FirestoreAdminAsyncClient( @@ -5038,20 +6169,64 @@ async def test_update_database_empty_call_async(): ) # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client.transport.update_database), "__call__") as call: + with mock.patch.object(type(client.transport.list_databases), "__call__") as call: # Designate an appropriate return value for the call. call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( - operations_pb2.Operation(name="operations/spam") + firestore_admin.ListDatabasesResponse( + unreachable=["unreachable_value"], + ) ) - response = await client.update_database() + response = await client.list_databases() call.assert_called() _, args, _ = call.mock_calls[0] - assert args[0] == firestore_admin.UpdateDatabaseRequest() + assert args[0] == firestore_admin.ListDatabasesRequest() @pytest.mark.asyncio -async def test_update_database_async( - transport: str = "grpc_asyncio", request_type=firestore_admin.UpdateDatabaseRequest +async def test_list_databases_async_use_cached_wrapped_rpc( + transport: str = "grpc_asyncio", +): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method_async.wrap_method") as wrapper_fn: + client = FirestoreAdminAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert ( + client._client._transport.list_databases + in client._client._transport._wrapped_methods + ) + + # Replace cached wrapped function with mock + mock_rpc = mock.AsyncMock() + mock_rpc.return_value = mock.Mock() + client._client._transport._wrapped_methods[ + client._client._transport.list_databases + ] = mock_rpc + + request = {} + await client.list_databases(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + await client.list_databases(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 + + +@pytest.mark.asyncio +async def test_list_databases_async( + transport: str = "grpc_asyncio", request_type=firestore_admin.ListDatabasesRequest ): client = FirestoreAdminAsyncClient( credentials=ga_credentials.AnonymousCredentials(), @@ -5063,43 +6238,46 @@ async def test_update_database_async( request = request_type() # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client.transport.update_database), "__call__") as call: + with mock.patch.object(type(client.transport.list_databases), "__call__") as call: # Designate an appropriate return value for the call. call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( - operations_pb2.Operation(name="operations/spam") + firestore_admin.ListDatabasesResponse( + unreachable=["unreachable_value"], + ) ) - response = await client.update_database(request) + response = await client.list_databases(request) # Establish that the underlying gRPC stub method was called. assert len(call.mock_calls) _, args, _ = call.mock_calls[0] - request = firestore_admin.UpdateDatabaseRequest() + request = firestore_admin.ListDatabasesRequest() assert args[0] == request # Establish that the response is the type that we expect. - assert isinstance(response, future.Future) + assert isinstance(response, firestore_admin.ListDatabasesResponse) + assert response.unreachable == ["unreachable_value"] @pytest.mark.asyncio -async def test_update_database_async_from_dict(): - await test_update_database_async(request_type=dict) +async def test_list_databases_async_from_dict(): + await test_list_databases_async(request_type=dict) -def test_update_database_field_headers(): +def test_list_databases_field_headers(): client = FirestoreAdminClient( credentials=ga_credentials.AnonymousCredentials(), ) # Any value that is part of the HTTP/1.1 URI should be sent as # a field header. Set these to a non-empty value. - request = firestore_admin.UpdateDatabaseRequest() + request = firestore_admin.ListDatabasesRequest() - request.database.name = "name_value" + request.parent = "parent_value" # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client.transport.update_database), "__call__") as call: - call.return_value = operations_pb2.Operation(name="operations/op") - client.update_database(request) + with mock.patch.object(type(client.transport.list_databases), "__call__") as call: + call.return_value = firestore_admin.ListDatabasesResponse() + client.list_databases(request) # Establish that the underlying gRPC stub method was called. assert len(call.mock_calls) == 1 @@ -5110,28 +6288,28 @@ def test_update_database_field_headers(): _, _, kw = call.mock_calls[0] assert ( "x-goog-request-params", - "database.name=name_value", + "parent=parent_value", ) in kw["metadata"] @pytest.mark.asyncio -async def test_update_database_field_headers_async(): +async def test_list_databases_field_headers_async(): client = FirestoreAdminAsyncClient( credentials=ga_credentials.AnonymousCredentials(), ) # Any value that is part of the HTTP/1.1 URI should be sent as # a field header. Set these to a non-empty value. - request = firestore_admin.UpdateDatabaseRequest() + request = firestore_admin.ListDatabasesRequest() - request.database.name = "name_value" + request.parent = "parent_value" # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client.transport.update_database), "__call__") as call: + with mock.patch.object(type(client.transport.list_databases), "__call__") as call: call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( - operations_pb2.Operation(name="operations/op") + firestore_admin.ListDatabasesResponse() ) - await client.update_database(request) + await client.list_databases(request) # Establish that the underlying gRPC stub method was called. assert len(call.mock_calls) @@ -5142,39 +6320,35 @@ async def test_update_database_field_headers_async(): _, _, kw = call.mock_calls[0] assert ( "x-goog-request-params", - "database.name=name_value", + "parent=parent_value", ) in kw["metadata"] -def test_update_database_flattened(): +def test_list_databases_flattened(): client = FirestoreAdminClient( credentials=ga_credentials.AnonymousCredentials(), ) # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client.transport.update_database), "__call__") as call: + with mock.patch.object(type(client.transport.list_databases), "__call__") as call: # Designate an appropriate return value for the call. - call.return_value = operations_pb2.Operation(name="operations/op") + call.return_value = firestore_admin.ListDatabasesResponse() # Call the method with a truthy value for each flattened field, # using the keyword arguments to the method. - client.update_database( - database=gfa_database.Database(name="name_value"), - update_mask=field_mask_pb2.FieldMask(paths=["paths_value"]), + client.list_databases( + parent="parent_value", ) # Establish that the underlying call was made with the expected # request object values. assert len(call.mock_calls) == 1 _, args, _ = call.mock_calls[0] - arg = args[0].database - mock_val = gfa_database.Database(name="name_value") - assert arg == mock_val - arg = args[0].update_mask - mock_val = field_mask_pb2.FieldMask(paths=["paths_value"]) + arg = args[0].parent + mock_val = "parent_value" assert arg == mock_val -def test_update_database_flattened_error(): +def test_list_databases_flattened_error(): client = FirestoreAdminClient( credentials=ga_credentials.AnonymousCredentials(), ) @@ -5182,48 +6356,43 @@ def test_update_database_flattened_error(): # Attempting to call a method with both a request object and flattened # fields is an error. with pytest.raises(ValueError): - client.update_database( - firestore_admin.UpdateDatabaseRequest(), - database=gfa_database.Database(name="name_value"), - update_mask=field_mask_pb2.FieldMask(paths=["paths_value"]), + client.list_databases( + firestore_admin.ListDatabasesRequest(), + parent="parent_value", ) @pytest.mark.asyncio -async def test_update_database_flattened_async(): +async def test_list_databases_flattened_async(): client = FirestoreAdminAsyncClient( credentials=ga_credentials.AnonymousCredentials(), ) # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client.transport.update_database), "__call__") as call: + with mock.patch.object(type(client.transport.list_databases), "__call__") as call: # Designate an appropriate return value for the call. - call.return_value = operations_pb2.Operation(name="operations/op") + call.return_value = firestore_admin.ListDatabasesResponse() call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( - operations_pb2.Operation(name="operations/spam") + firestore_admin.ListDatabasesResponse() ) # Call the method with a truthy value for each flattened field, # using the keyword arguments to the method. - response = await client.update_database( - database=gfa_database.Database(name="name_value"), - update_mask=field_mask_pb2.FieldMask(paths=["paths_value"]), + response = await client.list_databases( + parent="parent_value", ) # Establish that the underlying call was made with the expected # request object values. assert len(call.mock_calls) _, args, _ = call.mock_calls[0] - arg = args[0].database - mock_val = gfa_database.Database(name="name_value") - assert arg == mock_val - arg = args[0].update_mask - mock_val = field_mask_pb2.FieldMask(paths=["paths_value"]) + arg = args[0].parent + mock_val = "parent_value" assert arg == mock_val @pytest.mark.asyncio -async def test_update_database_flattened_error_async(): +async def test_list_databases_flattened_error_async(): client = FirestoreAdminAsyncClient( credentials=ga_credentials.AnonymousCredentials(), ) @@ -5231,21 +6400,20 @@ async def test_update_database_flattened_error_async(): # Attempting to call a method with both a request object and flattened # fields is an error. with pytest.raises(ValueError): - await client.update_database( - firestore_admin.UpdateDatabaseRequest(), - database=gfa_database.Database(name="name_value"), - update_mask=field_mask_pb2.FieldMask(paths=["paths_value"]), + await client.list_databases( + firestore_admin.ListDatabasesRequest(), + parent="parent_value", ) @pytest.mark.parametrize( "request_type", [ - firestore_admin.DeleteDatabaseRequest, + firestore_admin.UpdateDatabaseRequest, dict, ], ) -def test_delete_database(request_type, transport: str = "grpc"): +def test_update_database(request_type, transport: str = "grpc"): client = FirestoreAdminClient( credentials=ga_credentials.AnonymousCredentials(), transport=transport, @@ -5256,22 +6424,22 @@ def test_delete_database(request_type, transport: str = "grpc"): request = request_type() # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client.transport.delete_database), "__call__") as call: + with mock.patch.object(type(client.transport.update_database), "__call__") as call: # Designate an appropriate return value for the call. call.return_value = operations_pb2.Operation(name="operations/spam") - response = client.delete_database(request) + response = client.update_database(request) # Establish that the underlying gRPC stub method was called. assert len(call.mock_calls) == 1 _, args, _ = call.mock_calls[0] - request = firestore_admin.DeleteDatabaseRequest() + request = firestore_admin.UpdateDatabaseRequest() assert args[0] == request # Establish that the response is the type that we expect. assert isinstance(response, future.Future) -def test_delete_database_empty_call(): +def test_update_database_empty_call(): # This test is a coverage failsafe to make sure that totally empty calls, # i.e. request == None and no flattened fields passed, work. client = FirestoreAdminClient( @@ -5280,14 +6448,17 @@ def test_delete_database_empty_call(): ) # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client.transport.delete_database), "__call__") as call: - client.delete_database() + with mock.patch.object(type(client.transport.update_database), "__call__") as call: + call.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) + client.update_database() call.assert_called() _, args, _ = call.mock_calls[0] - assert args[0] == firestore_admin.DeleteDatabaseRequest() + assert args[0] == firestore_admin.UpdateDatabaseRequest() -def test_delete_database_non_empty_request_with_auto_populated_field(): +def test_update_database_non_empty_request_with_auto_populated_field(): # This test is a coverage failsafe to make sure that UUID4 fields are # automatically populated, according to AIP-4235, with non-empty requests. client = FirestoreAdminClient( @@ -5298,24 +6469,61 @@ def test_delete_database_non_empty_request_with_auto_populated_field(): # Populate all string fields in the request which are not UUID4 # since we want to check that UUID4 are populated automatically # if they meet the requirements of AIP 4235. - request = firestore_admin.DeleteDatabaseRequest( - name="name_value", - etag="etag_value", - ) + request = firestore_admin.UpdateDatabaseRequest() # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client.transport.delete_database), "__call__") as call: - client.delete_database(request=request) + with mock.patch.object(type(client.transport.update_database), "__call__") as call: + call.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) + client.update_database(request=request) call.assert_called() _, args, _ = call.mock_calls[0] - assert args[0] == firestore_admin.DeleteDatabaseRequest( - name="name_value", - etag="etag_value", + assert args[0] == firestore_admin.UpdateDatabaseRequest() + + +def test_update_database_use_cached_wrapped_rpc(): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method.wrap_method") as wrapper_fn: + client = FirestoreAdminClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="grpc", + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert client._transport.update_database in client._transport._wrapped_methods + + # Replace cached wrapped function with mock + mock_rpc = mock.Mock() + mock_rpc.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. ) + client._transport._wrapped_methods[client._transport.update_database] = mock_rpc + request = {} + client.update_database(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + # Operation methods call wrapper_fn to build a cached + # client._transport.operations_client instance on first rpc call. + # Subsequent calls should use the cached wrapper + wrapper_fn.reset_mock() + + client.update_database(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 @pytest.mark.asyncio -async def test_delete_database_empty_call_async(): +async def test_update_database_empty_call_async(): # This test is a coverage failsafe to make sure that totally empty calls, # i.e. request == None and no flattened fields passed, work. client = FirestoreAdminAsyncClient( @@ -5324,20 +6532,67 @@ async def test_delete_database_empty_call_async(): ) # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client.transport.delete_database), "__call__") as call: + with mock.patch.object(type(client.transport.update_database), "__call__") as call: # Designate an appropriate return value for the call. call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( operations_pb2.Operation(name="operations/spam") ) - response = await client.delete_database() + response = await client.update_database() call.assert_called() _, args, _ = call.mock_calls[0] - assert args[0] == firestore_admin.DeleteDatabaseRequest() + assert args[0] == firestore_admin.UpdateDatabaseRequest() @pytest.mark.asyncio -async def test_delete_database_async( - transport: str = "grpc_asyncio", request_type=firestore_admin.DeleteDatabaseRequest +async def test_update_database_async_use_cached_wrapped_rpc( + transport: str = "grpc_asyncio", +): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method_async.wrap_method") as wrapper_fn: + client = FirestoreAdminAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert ( + client._client._transport.update_database + in client._client._transport._wrapped_methods + ) + + # Replace cached wrapped function with mock + mock_rpc = mock.AsyncMock() + mock_rpc.return_value = mock.Mock() + client._client._transport._wrapped_methods[ + client._client._transport.update_database + ] = mock_rpc + + request = {} + await client.update_database(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + # Operation methods call wrapper_fn to build a cached + # client._transport.operations_client instance on first rpc call. + # Subsequent calls should use the cached wrapper + wrapper_fn.reset_mock() + + await client.update_database(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 + + +@pytest.mark.asyncio +async def test_update_database_async( + transport: str = "grpc_asyncio", request_type=firestore_admin.UpdateDatabaseRequest ): client = FirestoreAdminAsyncClient( credentials=ga_credentials.AnonymousCredentials(), @@ -5349,17 +6604,17 @@ async def test_delete_database_async( request = request_type() # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client.transport.delete_database), "__call__") as call: + with mock.patch.object(type(client.transport.update_database), "__call__") as call: # Designate an appropriate return value for the call. call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( operations_pb2.Operation(name="operations/spam") ) - response = await client.delete_database(request) + response = await client.update_database(request) # Establish that the underlying gRPC stub method was called. assert len(call.mock_calls) _, args, _ = call.mock_calls[0] - request = firestore_admin.DeleteDatabaseRequest() + request = firestore_admin.UpdateDatabaseRequest() assert args[0] == request # Establish that the response is the type that we expect. @@ -5367,25 +6622,25 @@ async def test_delete_database_async( @pytest.mark.asyncio -async def test_delete_database_async_from_dict(): - await test_delete_database_async(request_type=dict) +async def test_update_database_async_from_dict(): + await test_update_database_async(request_type=dict) -def test_delete_database_field_headers(): +def test_update_database_field_headers(): client = FirestoreAdminClient( credentials=ga_credentials.AnonymousCredentials(), ) # Any value that is part of the HTTP/1.1 URI should be sent as # a field header. Set these to a non-empty value. - request = firestore_admin.DeleteDatabaseRequest() + request = firestore_admin.UpdateDatabaseRequest() - request.name = "name_value" + request.database.name = "name_value" # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client.transport.delete_database), "__call__") as call: + with mock.patch.object(type(client.transport.update_database), "__call__") as call: call.return_value = operations_pb2.Operation(name="operations/op") - client.delete_database(request) + client.update_database(request) # Establish that the underlying gRPC stub method was called. assert len(call.mock_calls) == 1 @@ -5396,28 +6651,28 @@ def test_delete_database_field_headers(): _, _, kw = call.mock_calls[0] assert ( "x-goog-request-params", - "name=name_value", + "database.name=name_value", ) in kw["metadata"] @pytest.mark.asyncio -async def test_delete_database_field_headers_async(): +async def test_update_database_field_headers_async(): client = FirestoreAdminAsyncClient( credentials=ga_credentials.AnonymousCredentials(), ) # Any value that is part of the HTTP/1.1 URI should be sent as # a field header. Set these to a non-empty value. - request = firestore_admin.DeleteDatabaseRequest() + request = firestore_admin.UpdateDatabaseRequest() - request.name = "name_value" + request.database.name = "name_value" # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client.transport.delete_database), "__call__") as call: + with mock.patch.object(type(client.transport.update_database), "__call__") as call: call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( operations_pb2.Operation(name="operations/op") ) - await client.delete_database(request) + await client.update_database(request) # Establish that the underlying gRPC stub method was called. assert len(call.mock_calls) @@ -5428,35 +6683,39 @@ async def test_delete_database_field_headers_async(): _, _, kw = call.mock_calls[0] assert ( "x-goog-request-params", - "name=name_value", + "database.name=name_value", ) in kw["metadata"] -def test_delete_database_flattened(): +def test_update_database_flattened(): client = FirestoreAdminClient( credentials=ga_credentials.AnonymousCredentials(), ) # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client.transport.delete_database), "__call__") as call: + with mock.patch.object(type(client.transport.update_database), "__call__") as call: # Designate an appropriate return value for the call. call.return_value = operations_pb2.Operation(name="operations/op") # Call the method with a truthy value for each flattened field, # using the keyword arguments to the method. - client.delete_database( - name="name_value", + client.update_database( + database=gfa_database.Database(name="name_value"), + update_mask=field_mask_pb2.FieldMask(paths=["paths_value"]), ) # Establish that the underlying call was made with the expected # request object values. assert len(call.mock_calls) == 1 _, args, _ = call.mock_calls[0] - arg = args[0].name - mock_val = "name_value" + arg = args[0].database + mock_val = gfa_database.Database(name="name_value") + assert arg == mock_val + arg = args[0].update_mask + mock_val = field_mask_pb2.FieldMask(paths=["paths_value"]) assert arg == mock_val -def test_delete_database_flattened_error(): +def test_update_database_flattened_error(): client = FirestoreAdminClient( credentials=ga_credentials.AnonymousCredentials(), ) @@ -5464,20 +6723,21 @@ def test_delete_database_flattened_error(): # Attempting to call a method with both a request object and flattened # fields is an error. with pytest.raises(ValueError): - client.delete_database( - firestore_admin.DeleteDatabaseRequest(), - name="name_value", + client.update_database( + firestore_admin.UpdateDatabaseRequest(), + database=gfa_database.Database(name="name_value"), + update_mask=field_mask_pb2.FieldMask(paths=["paths_value"]), ) @pytest.mark.asyncio -async def test_delete_database_flattened_async(): +async def test_update_database_flattened_async(): client = FirestoreAdminAsyncClient( credentials=ga_credentials.AnonymousCredentials(), ) # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client.transport.delete_database), "__call__") as call: + with mock.patch.object(type(client.transport.update_database), "__call__") as call: # Designate an appropriate return value for the call. call.return_value = operations_pb2.Operation(name="operations/op") @@ -5486,21 +6746,25 @@ async def test_delete_database_flattened_async(): ) # Call the method with a truthy value for each flattened field, # using the keyword arguments to the method. - response = await client.delete_database( - name="name_value", + response = await client.update_database( + database=gfa_database.Database(name="name_value"), + update_mask=field_mask_pb2.FieldMask(paths=["paths_value"]), ) # Establish that the underlying call was made with the expected # request object values. assert len(call.mock_calls) _, args, _ = call.mock_calls[0] - arg = args[0].name - mock_val = "name_value" + arg = args[0].database + mock_val = gfa_database.Database(name="name_value") + assert arg == mock_val + arg = args[0].update_mask + mock_val = field_mask_pb2.FieldMask(paths=["paths_value"]) assert arg == mock_val @pytest.mark.asyncio -async def test_delete_database_flattened_error_async(): +async def test_update_database_flattened_error_async(): client = FirestoreAdminAsyncClient( credentials=ga_credentials.AnonymousCredentials(), ) @@ -5508,20 +6772,21 @@ async def test_delete_database_flattened_error_async(): # Attempting to call a method with both a request object and flattened # fields is an error. with pytest.raises(ValueError): - await client.delete_database( - firestore_admin.DeleteDatabaseRequest(), - name="name_value", + await client.update_database( + firestore_admin.UpdateDatabaseRequest(), + database=gfa_database.Database(name="name_value"), + update_mask=field_mask_pb2.FieldMask(paths=["paths_value"]), ) @pytest.mark.parametrize( "request_type", [ - firestore_admin.GetBackupRequest, + firestore_admin.DeleteDatabaseRequest, dict, ], ) -def test_get_backup(request_type, transport: str = "grpc"): +def test_delete_database(request_type, transport: str = "grpc"): client = FirestoreAdminClient( credentials=ga_credentials.AnonymousCredentials(), transport=transport, @@ -5532,31 +6797,22 @@ def test_get_backup(request_type, transport: str = "grpc"): request = request_type() # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client.transport.get_backup), "__call__") as call: + with mock.patch.object(type(client.transport.delete_database), "__call__") as call: # Designate an appropriate return value for the call. - call.return_value = backup.Backup( - name="name_value", - database="database_value", - database_uid="database_uid_value", - state=backup.Backup.State.CREATING, - ) - response = client.get_backup(request) + call.return_value = operations_pb2.Operation(name="operations/spam") + response = client.delete_database(request) # Establish that the underlying gRPC stub method was called. assert len(call.mock_calls) == 1 _, args, _ = call.mock_calls[0] - request = firestore_admin.GetBackupRequest() + request = firestore_admin.DeleteDatabaseRequest() assert args[0] == request # Establish that the response is the type that we expect. - assert isinstance(response, backup.Backup) - assert response.name == "name_value" - assert response.database == "database_value" - assert response.database_uid == "database_uid_value" - assert response.state == backup.Backup.State.CREATING + assert isinstance(response, future.Future) -def test_get_backup_empty_call(): +def test_delete_database_empty_call(): # This test is a coverage failsafe to make sure that totally empty calls, # i.e. request == None and no flattened fields passed, work. client = FirestoreAdminClient( @@ -5565,14 +6821,17 @@ def test_get_backup_empty_call(): ) # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client.transport.get_backup), "__call__") as call: - client.get_backup() + with mock.patch.object(type(client.transport.delete_database), "__call__") as call: + call.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) + client.delete_database() call.assert_called() _, args, _ = call.mock_calls[0] - assert args[0] == firestore_admin.GetBackupRequest() + assert args[0] == firestore_admin.DeleteDatabaseRequest() -def test_get_backup_non_empty_request_with_auto_populated_field(): +def test_delete_database_non_empty_request_with_auto_populated_field(): # This test is a coverage failsafe to make sure that UUID4 fields are # automatically populated, according to AIP-4235, with non-empty requests. client = FirestoreAdminClient( @@ -5583,22 +6842,67 @@ def test_get_backup_non_empty_request_with_auto_populated_field(): # Populate all string fields in the request which are not UUID4 # since we want to check that UUID4 are populated automatically # if they meet the requirements of AIP 4235. - request = firestore_admin.GetBackupRequest( + request = firestore_admin.DeleteDatabaseRequest( name="name_value", + etag="etag_value", ) # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client.transport.get_backup), "__call__") as call: - client.get_backup(request=request) + with mock.patch.object(type(client.transport.delete_database), "__call__") as call: + call.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) + client.delete_database(request=request) call.assert_called() _, args, _ = call.mock_calls[0] - assert args[0] == firestore_admin.GetBackupRequest( + assert args[0] == firestore_admin.DeleteDatabaseRequest( name="name_value", + etag="etag_value", + ) + + +def test_delete_database_use_cached_wrapped_rpc(): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method.wrap_method") as wrapper_fn: + client = FirestoreAdminClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="grpc", + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert client._transport.delete_database in client._transport._wrapped_methods + + # Replace cached wrapped function with mock + mock_rpc = mock.Mock() + mock_rpc.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. ) + client._transport._wrapped_methods[client._transport.delete_database] = mock_rpc + request = {} + client.delete_database(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + # Operation methods call wrapper_fn to build a cached + # client._transport.operations_client instance on first rpc call. + # Subsequent calls should use the cached wrapper + wrapper_fn.reset_mock() + + client.delete_database(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 @pytest.mark.asyncio -async def test_get_backup_empty_call_async(): +async def test_delete_database_empty_call_async(): # This test is a coverage failsafe to make sure that totally empty calls, # i.e. request == None and no flattened fields passed, work. client = FirestoreAdminAsyncClient( @@ -5607,82 +6911,115 @@ async def test_get_backup_empty_call_async(): ) # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client.transport.get_backup), "__call__") as call: + with mock.patch.object(type(client.transport.delete_database), "__call__") as call: # Designate an appropriate return value for the call. call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( - backup.Backup( - name="name_value", - database="database_value", - database_uid="database_uid_value", - state=backup.Backup.State.CREATING, - ) + operations_pb2.Operation(name="operations/spam") ) - response = await client.get_backup() + response = await client.delete_database() call.assert_called() _, args, _ = call.mock_calls[0] - assert args[0] == firestore_admin.GetBackupRequest() + assert args[0] == firestore_admin.DeleteDatabaseRequest() @pytest.mark.asyncio -async def test_get_backup_async( - transport: str = "grpc_asyncio", request_type=firestore_admin.GetBackupRequest +async def test_delete_database_async_use_cached_wrapped_rpc( + transport: str = "grpc_asyncio", ): - client = FirestoreAdminAsyncClient( - credentials=ga_credentials.AnonymousCredentials(), - transport=transport, - ) + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method_async.wrap_method") as wrapper_fn: + client = FirestoreAdminAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) - # Everything is optional in proto3 as far as the runtime is concerned, - # and we are mocking out the actual API, so just send an empty request. - request = request_type() + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() - # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client.transport.get_backup), "__call__") as call: - # Designate an appropriate return value for the call. - call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( - backup.Backup( - name="name_value", - database="database_value", - database_uid="database_uid_value", - state=backup.Backup.State.CREATING, - ) + # Ensure method has been cached + assert ( + client._client._transport.delete_database + in client._client._transport._wrapped_methods ) - response = await client.get_backup(request) + + # Replace cached wrapped function with mock + mock_rpc = mock.AsyncMock() + mock_rpc.return_value = mock.Mock() + client._client._transport._wrapped_methods[ + client._client._transport.delete_database + ] = mock_rpc + + request = {} + await client.delete_database(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + # Operation methods call wrapper_fn to build a cached + # client._transport.operations_client instance on first rpc call. + # Subsequent calls should use the cached wrapper + wrapper_fn.reset_mock() + + await client.delete_database(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 + + +@pytest.mark.asyncio +async def test_delete_database_async( + transport: str = "grpc_asyncio", request_type=firestore_admin.DeleteDatabaseRequest +): + client = FirestoreAdminAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.delete_database), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + operations_pb2.Operation(name="operations/spam") + ) + response = await client.delete_database(request) # Establish that the underlying gRPC stub method was called. assert len(call.mock_calls) _, args, _ = call.mock_calls[0] - request = firestore_admin.GetBackupRequest() + request = firestore_admin.DeleteDatabaseRequest() assert args[0] == request # Establish that the response is the type that we expect. - assert isinstance(response, backup.Backup) - assert response.name == "name_value" - assert response.database == "database_value" - assert response.database_uid == "database_uid_value" - assert response.state == backup.Backup.State.CREATING + assert isinstance(response, future.Future) @pytest.mark.asyncio -async def test_get_backup_async_from_dict(): - await test_get_backup_async(request_type=dict) +async def test_delete_database_async_from_dict(): + await test_delete_database_async(request_type=dict) -def test_get_backup_field_headers(): +def test_delete_database_field_headers(): client = FirestoreAdminClient( credentials=ga_credentials.AnonymousCredentials(), ) # Any value that is part of the HTTP/1.1 URI should be sent as # a field header. Set these to a non-empty value. - request = firestore_admin.GetBackupRequest() + request = firestore_admin.DeleteDatabaseRequest() request.name = "name_value" # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client.transport.get_backup), "__call__") as call: - call.return_value = backup.Backup() - client.get_backup(request) + with mock.patch.object(type(client.transport.delete_database), "__call__") as call: + call.return_value = operations_pb2.Operation(name="operations/op") + client.delete_database(request) # Establish that the underlying gRPC stub method was called. assert len(call.mock_calls) == 1 @@ -5698,21 +7035,23 @@ def test_get_backup_field_headers(): @pytest.mark.asyncio -async def test_get_backup_field_headers_async(): +async def test_delete_database_field_headers_async(): client = FirestoreAdminAsyncClient( credentials=ga_credentials.AnonymousCredentials(), ) # Any value that is part of the HTTP/1.1 URI should be sent as # a field header. Set these to a non-empty value. - request = firestore_admin.GetBackupRequest() + request = firestore_admin.DeleteDatabaseRequest() request.name = "name_value" # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client.transport.get_backup), "__call__") as call: - call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(backup.Backup()) - await client.get_backup(request) + with mock.patch.object(type(client.transport.delete_database), "__call__") as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + operations_pb2.Operation(name="operations/op") + ) + await client.delete_database(request) # Establish that the underlying gRPC stub method was called. assert len(call.mock_calls) @@ -5727,18 +7066,18 @@ async def test_get_backup_field_headers_async(): ) in kw["metadata"] -def test_get_backup_flattened(): +def test_delete_database_flattened(): client = FirestoreAdminClient( credentials=ga_credentials.AnonymousCredentials(), ) # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client.transport.get_backup), "__call__") as call: + with mock.patch.object(type(client.transport.delete_database), "__call__") as call: # Designate an appropriate return value for the call. - call.return_value = backup.Backup() + call.return_value = operations_pb2.Operation(name="operations/op") # Call the method with a truthy value for each flattened field, # using the keyword arguments to the method. - client.get_backup( + client.delete_database( name="name_value", ) @@ -5751,7 +7090,7 @@ def test_get_backup_flattened(): assert arg == mock_val -def test_get_backup_flattened_error(): +def test_delete_database_flattened_error(): client = FirestoreAdminClient( credentials=ga_credentials.AnonymousCredentials(), ) @@ -5759,27 +7098,29 @@ def test_get_backup_flattened_error(): # Attempting to call a method with both a request object and flattened # fields is an error. with pytest.raises(ValueError): - client.get_backup( - firestore_admin.GetBackupRequest(), + client.delete_database( + firestore_admin.DeleteDatabaseRequest(), name="name_value", ) @pytest.mark.asyncio -async def test_get_backup_flattened_async(): +async def test_delete_database_flattened_async(): client = FirestoreAdminAsyncClient( credentials=ga_credentials.AnonymousCredentials(), ) # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client.transport.get_backup), "__call__") as call: + with mock.patch.object(type(client.transport.delete_database), "__call__") as call: # Designate an appropriate return value for the call. - call.return_value = backup.Backup() + call.return_value = operations_pb2.Operation(name="operations/op") - call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(backup.Backup()) + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + operations_pb2.Operation(name="operations/spam") + ) # Call the method with a truthy value for each flattened field, # using the keyword arguments to the method. - response = await client.get_backup( + response = await client.delete_database( name="name_value", ) @@ -5793,7 +7134,7 @@ async def test_get_backup_flattened_async(): @pytest.mark.asyncio -async def test_get_backup_flattened_error_async(): +async def test_delete_database_flattened_error_async(): client = FirestoreAdminAsyncClient( credentials=ga_credentials.AnonymousCredentials(), ) @@ -5801,8 +7142,8 @@ async def test_get_backup_flattened_error_async(): # Attempting to call a method with both a request object and flattened # fields is an error. with pytest.raises(ValueError): - await client.get_backup( - firestore_admin.GetBackupRequest(), + await client.delete_database( + firestore_admin.DeleteDatabaseRequest(), name="name_value", ) @@ -5810,11 +7151,11 @@ async def test_get_backup_flattened_error_async(): @pytest.mark.parametrize( "request_type", [ - firestore_admin.ListBackupsRequest, + firestore_admin.GetBackupRequest, dict, ], ) -def test_list_backups(request_type, transport: str = "grpc"): +def test_get_backup(request_type, transport: str = "grpc"): client = FirestoreAdminClient( credentials=ga_credentials.AnonymousCredentials(), transport=transport, @@ -5825,25 +7166,31 @@ def test_list_backups(request_type, transport: str = "grpc"): request = request_type() # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client.transport.list_backups), "__call__") as call: + with mock.patch.object(type(client.transport.get_backup), "__call__") as call: # Designate an appropriate return value for the call. - call.return_value = firestore_admin.ListBackupsResponse( - unreachable=["unreachable_value"], + call.return_value = backup.Backup( + name="name_value", + database="database_value", + database_uid="database_uid_value", + state=backup.Backup.State.CREATING, ) - response = client.list_backups(request) + response = client.get_backup(request) # Establish that the underlying gRPC stub method was called. assert len(call.mock_calls) == 1 _, args, _ = call.mock_calls[0] - request = firestore_admin.ListBackupsRequest() + request = firestore_admin.GetBackupRequest() assert args[0] == request # Establish that the response is the type that we expect. - assert isinstance(response, firestore_admin.ListBackupsResponse) - assert response.unreachable == ["unreachable_value"] + assert isinstance(response, backup.Backup) + assert response.name == "name_value" + assert response.database == "database_value" + assert response.database_uid == "database_uid_value" + assert response.state == backup.Backup.State.CREATING -def test_list_backups_empty_call(): +def test_get_backup_empty_call(): # This test is a coverage failsafe to make sure that totally empty calls, # i.e. request == None and no flattened fields passed, work. client = FirestoreAdminClient( @@ -5852,14 +7199,17 @@ def test_list_backups_empty_call(): ) # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client.transport.list_backups), "__call__") as call: - client.list_backups() + with mock.patch.object(type(client.transport.get_backup), "__call__") as call: + call.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) + client.get_backup() call.assert_called() _, args, _ = call.mock_calls[0] - assert args[0] == firestore_admin.ListBackupsRequest() + assert args[0] == firestore_admin.GetBackupRequest() -def test_list_backups_non_empty_request_with_auto_populated_field(): +def test_get_backup_non_empty_request_with_auto_populated_field(): # This test is a coverage failsafe to make sure that UUID4 fields are # automatically populated, according to AIP-4235, with non-empty requests. client = FirestoreAdminClient( @@ -5870,22 +7220,60 @@ def test_list_backups_non_empty_request_with_auto_populated_field(): # Populate all string fields in the request which are not UUID4 # since we want to check that UUID4 are populated automatically # if they meet the requirements of AIP 4235. - request = firestore_admin.ListBackupsRequest( - parent="parent_value", + request = firestore_admin.GetBackupRequest( + name="name_value", ) # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client.transport.list_backups), "__call__") as call: - client.list_backups(request=request) + with mock.patch.object(type(client.transport.get_backup), "__call__") as call: + call.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) + client.get_backup(request=request) call.assert_called() _, args, _ = call.mock_calls[0] - assert args[0] == firestore_admin.ListBackupsRequest( - parent="parent_value", + assert args[0] == firestore_admin.GetBackupRequest( + name="name_value", + ) + + +def test_get_backup_use_cached_wrapped_rpc(): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method.wrap_method") as wrapper_fn: + client = FirestoreAdminClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="grpc", + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert client._transport.get_backup in client._transport._wrapped_methods + + # Replace cached wrapped function with mock + mock_rpc = mock.Mock() + mock_rpc.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. ) + client._transport._wrapped_methods[client._transport.get_backup] = mock_rpc + request = {} + client.get_backup(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + client.get_backup(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 @pytest.mark.asyncio -async def test_list_backups_empty_call_async(): +async def test_get_backup_empty_call_async(): # This test is a coverage failsafe to make sure that totally empty calls, # i.e. request == None and no flattened fields passed, work. client = FirestoreAdminAsyncClient( @@ -5894,22 +7282,65 @@ async def test_list_backups_empty_call_async(): ) # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client.transport.list_backups), "__call__") as call: + with mock.patch.object(type(client.transport.get_backup), "__call__") as call: # Designate an appropriate return value for the call. call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( - firestore_admin.ListBackupsResponse( - unreachable=["unreachable_value"], + backup.Backup( + name="name_value", + database="database_value", + database_uid="database_uid_value", + state=backup.Backup.State.CREATING, ) ) - response = await client.list_backups() + response = await client.get_backup() call.assert_called() _, args, _ = call.mock_calls[0] - assert args[0] == firestore_admin.ListBackupsRequest() + assert args[0] == firestore_admin.GetBackupRequest() @pytest.mark.asyncio -async def test_list_backups_async( - transport: str = "grpc_asyncio", request_type=firestore_admin.ListBackupsRequest +async def test_get_backup_async_use_cached_wrapped_rpc(transport: str = "grpc_asyncio"): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method_async.wrap_method") as wrapper_fn: + client = FirestoreAdminAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert ( + client._client._transport.get_backup + in client._client._transport._wrapped_methods + ) + + # Replace cached wrapped function with mock + mock_rpc = mock.AsyncMock() + mock_rpc.return_value = mock.Mock() + client._client._transport._wrapped_methods[ + client._client._transport.get_backup + ] = mock_rpc + + request = {} + await client.get_backup(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + await client.get_backup(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 + + +@pytest.mark.asyncio +async def test_get_backup_async( + transport: str = "grpc_asyncio", request_type=firestore_admin.GetBackupRequest ): client = FirestoreAdminAsyncClient( credentials=ga_credentials.AnonymousCredentials(), @@ -5921,46 +7352,52 @@ async def test_list_backups_async( request = request_type() # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client.transport.list_backups), "__call__") as call: + with mock.patch.object(type(client.transport.get_backup), "__call__") as call: # Designate an appropriate return value for the call. call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( - firestore_admin.ListBackupsResponse( - unreachable=["unreachable_value"], + backup.Backup( + name="name_value", + database="database_value", + database_uid="database_uid_value", + state=backup.Backup.State.CREATING, ) ) - response = await client.list_backups(request) + response = await client.get_backup(request) # Establish that the underlying gRPC stub method was called. assert len(call.mock_calls) _, args, _ = call.mock_calls[0] - request = firestore_admin.ListBackupsRequest() + request = firestore_admin.GetBackupRequest() assert args[0] == request # Establish that the response is the type that we expect. - assert isinstance(response, firestore_admin.ListBackupsResponse) - assert response.unreachable == ["unreachable_value"] + assert isinstance(response, backup.Backup) + assert response.name == "name_value" + assert response.database == "database_value" + assert response.database_uid == "database_uid_value" + assert response.state == backup.Backup.State.CREATING @pytest.mark.asyncio -async def test_list_backups_async_from_dict(): - await test_list_backups_async(request_type=dict) +async def test_get_backup_async_from_dict(): + await test_get_backup_async(request_type=dict) -def test_list_backups_field_headers(): +def test_get_backup_field_headers(): client = FirestoreAdminClient( credentials=ga_credentials.AnonymousCredentials(), ) # Any value that is part of the HTTP/1.1 URI should be sent as # a field header. Set these to a non-empty value. - request = firestore_admin.ListBackupsRequest() + request = firestore_admin.GetBackupRequest() - request.parent = "parent_value" + request.name = "name_value" # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client.transport.list_backups), "__call__") as call: - call.return_value = firestore_admin.ListBackupsResponse() - client.list_backups(request) + with mock.patch.object(type(client.transport.get_backup), "__call__") as call: + call.return_value = backup.Backup() + client.get_backup(request) # Establish that the underlying gRPC stub method was called. assert len(call.mock_calls) == 1 @@ -5971,28 +7408,26 @@ def test_list_backups_field_headers(): _, _, kw = call.mock_calls[0] assert ( "x-goog-request-params", - "parent=parent_value", + "name=name_value", ) in kw["metadata"] @pytest.mark.asyncio -async def test_list_backups_field_headers_async(): +async def test_get_backup_field_headers_async(): client = FirestoreAdminAsyncClient( credentials=ga_credentials.AnonymousCredentials(), ) # Any value that is part of the HTTP/1.1 URI should be sent as # a field header. Set these to a non-empty value. - request = firestore_admin.ListBackupsRequest() + request = firestore_admin.GetBackupRequest() - request.parent = "parent_value" + request.name = "name_value" # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client.transport.list_backups), "__call__") as call: - call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( - firestore_admin.ListBackupsResponse() - ) - await client.list_backups(request) + with mock.patch.object(type(client.transport.get_backup), "__call__") as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(backup.Backup()) + await client.get_backup(request) # Establish that the underlying gRPC stub method was called. assert len(call.mock_calls) @@ -6003,35 +7438,35 @@ async def test_list_backups_field_headers_async(): _, _, kw = call.mock_calls[0] assert ( "x-goog-request-params", - "parent=parent_value", + "name=name_value", ) in kw["metadata"] -def test_list_backups_flattened(): +def test_get_backup_flattened(): client = FirestoreAdminClient( credentials=ga_credentials.AnonymousCredentials(), ) # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client.transport.list_backups), "__call__") as call: + with mock.patch.object(type(client.transport.get_backup), "__call__") as call: # Designate an appropriate return value for the call. - call.return_value = firestore_admin.ListBackupsResponse() + call.return_value = backup.Backup() # Call the method with a truthy value for each flattened field, # using the keyword arguments to the method. - client.list_backups( - parent="parent_value", + client.get_backup( + name="name_value", ) # Establish that the underlying call was made with the expected # request object values. assert len(call.mock_calls) == 1 _, args, _ = call.mock_calls[0] - arg = args[0].parent - mock_val = "parent_value" + arg = args[0].name + mock_val = "name_value" assert arg == mock_val -def test_list_backups_flattened_error(): +def test_get_backup_flattened_error(): client = FirestoreAdminClient( credentials=ga_credentials.AnonymousCredentials(), ) @@ -6039,43 +7474,41 @@ def test_list_backups_flattened_error(): # Attempting to call a method with both a request object and flattened # fields is an error. with pytest.raises(ValueError): - client.list_backups( - firestore_admin.ListBackupsRequest(), - parent="parent_value", + client.get_backup( + firestore_admin.GetBackupRequest(), + name="name_value", ) @pytest.mark.asyncio -async def test_list_backups_flattened_async(): +async def test_get_backup_flattened_async(): client = FirestoreAdminAsyncClient( credentials=ga_credentials.AnonymousCredentials(), ) # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client.transport.list_backups), "__call__") as call: + with mock.patch.object(type(client.transport.get_backup), "__call__") as call: # Designate an appropriate return value for the call. - call.return_value = firestore_admin.ListBackupsResponse() + call.return_value = backup.Backup() - call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( - firestore_admin.ListBackupsResponse() - ) + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(backup.Backup()) # Call the method with a truthy value for each flattened field, # using the keyword arguments to the method. - response = await client.list_backups( - parent="parent_value", + response = await client.get_backup( + name="name_value", ) # Establish that the underlying call was made with the expected # request object values. assert len(call.mock_calls) _, args, _ = call.mock_calls[0] - arg = args[0].parent - mock_val = "parent_value" + arg = args[0].name + mock_val = "name_value" assert arg == mock_val @pytest.mark.asyncio -async def test_list_backups_flattened_error_async(): +async def test_get_backup_flattened_error_async(): client = FirestoreAdminAsyncClient( credentials=ga_credentials.AnonymousCredentials(), ) @@ -6083,20 +7516,20 @@ async def test_list_backups_flattened_error_async(): # Attempting to call a method with both a request object and flattened # fields is an error. with pytest.raises(ValueError): - await client.list_backups( - firestore_admin.ListBackupsRequest(), - parent="parent_value", + await client.get_backup( + firestore_admin.GetBackupRequest(), + name="name_value", ) @pytest.mark.parametrize( "request_type", [ - firestore_admin.DeleteBackupRequest, + firestore_admin.ListBackupsRequest, dict, ], ) -def test_delete_backup(request_type, transport: str = "grpc"): +def test_list_backups(request_type, transport: str = "grpc"): client = FirestoreAdminClient( credentials=ga_credentials.AnonymousCredentials(), transport=transport, @@ -6107,22 +7540,25 @@ def test_delete_backup(request_type, transport: str = "grpc"): request = request_type() # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client.transport.delete_backup), "__call__") as call: + with mock.patch.object(type(client.transport.list_backups), "__call__") as call: # Designate an appropriate return value for the call. - call.return_value = None - response = client.delete_backup(request) + call.return_value = firestore_admin.ListBackupsResponse( + unreachable=["unreachable_value"], + ) + response = client.list_backups(request) # Establish that the underlying gRPC stub method was called. assert len(call.mock_calls) == 1 _, args, _ = call.mock_calls[0] - request = firestore_admin.DeleteBackupRequest() + request = firestore_admin.ListBackupsRequest() assert args[0] == request # Establish that the response is the type that we expect. - assert response is None + assert isinstance(response, firestore_admin.ListBackupsResponse) + assert response.unreachable == ["unreachable_value"] -def test_delete_backup_empty_call(): +def test_list_backups_empty_call(): # This test is a coverage failsafe to make sure that totally empty calls, # i.e. request == None and no flattened fields passed, work. client = FirestoreAdminClient( @@ -6131,14 +7567,17 @@ def test_delete_backup_empty_call(): ) # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client.transport.delete_backup), "__call__") as call: - client.delete_backup() + with mock.patch.object(type(client.transport.list_backups), "__call__") as call: + call.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) + client.list_backups() call.assert_called() _, args, _ = call.mock_calls[0] - assert args[0] == firestore_admin.DeleteBackupRequest() + assert args[0] == firestore_admin.ListBackupsRequest() -def test_delete_backup_non_empty_request_with_auto_populated_field(): +def test_list_backups_non_empty_request_with_auto_populated_field(): # This test is a coverage failsafe to make sure that UUID4 fields are # automatically populated, according to AIP-4235, with non-empty requests. client = FirestoreAdminClient( @@ -6149,22 +7588,60 @@ def test_delete_backup_non_empty_request_with_auto_populated_field(): # Populate all string fields in the request which are not UUID4 # since we want to check that UUID4 are populated automatically # if they meet the requirements of AIP 4235. - request = firestore_admin.DeleteBackupRequest( - name="name_value", + request = firestore_admin.ListBackupsRequest( + parent="parent_value", ) # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client.transport.delete_backup), "__call__") as call: - client.delete_backup(request=request) + with mock.patch.object(type(client.transport.list_backups), "__call__") as call: + call.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) + client.list_backups(request=request) call.assert_called() _, args, _ = call.mock_calls[0] - assert args[0] == firestore_admin.DeleteBackupRequest( - name="name_value", + assert args[0] == firestore_admin.ListBackupsRequest( + parent="parent_value", + ) + + +def test_list_backups_use_cached_wrapped_rpc(): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method.wrap_method") as wrapper_fn: + client = FirestoreAdminClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="grpc", + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert client._transport.list_backups in client._transport._wrapped_methods + + # Replace cached wrapped function with mock + mock_rpc = mock.Mock() + mock_rpc.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. ) + client._transport._wrapped_methods[client._transport.list_backups] = mock_rpc + request = {} + client.list_backups(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + client.list_backups(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 @pytest.mark.asyncio -async def test_delete_backup_empty_call_async(): +async def test_list_backups_empty_call_async(): # This test is a coverage failsafe to make sure that totally empty calls, # i.e. request == None and no flattened fields passed, work. client = FirestoreAdminAsyncClient( @@ -6173,18 +7650,64 @@ async def test_delete_backup_empty_call_async(): ) # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client.transport.delete_backup), "__call__") as call: + with mock.patch.object(type(client.transport.list_backups), "__call__") as call: # Designate an appropriate return value for the call. - call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(None) - response = await client.delete_backup() + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + firestore_admin.ListBackupsResponse( + unreachable=["unreachable_value"], + ) + ) + response = await client.list_backups() call.assert_called() _, args, _ = call.mock_calls[0] - assert args[0] == firestore_admin.DeleteBackupRequest() + assert args[0] == firestore_admin.ListBackupsRequest() @pytest.mark.asyncio -async def test_delete_backup_async( - transport: str = "grpc_asyncio", request_type=firestore_admin.DeleteBackupRequest +async def test_list_backups_async_use_cached_wrapped_rpc( + transport: str = "grpc_asyncio", +): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method_async.wrap_method") as wrapper_fn: + client = FirestoreAdminAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert ( + client._client._transport.list_backups + in client._client._transport._wrapped_methods + ) + + # Replace cached wrapped function with mock + mock_rpc = mock.AsyncMock() + mock_rpc.return_value = mock.Mock() + client._client._transport._wrapped_methods[ + client._client._transport.list_backups + ] = mock_rpc + + request = {} + await client.list_backups(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + await client.list_backups(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 + + +@pytest.mark.asyncio +async def test_list_backups_async( + transport: str = "grpc_asyncio", request_type=firestore_admin.ListBackupsRequest ): client = FirestoreAdminAsyncClient( credentials=ga_credentials.AnonymousCredentials(), @@ -6196,41 +7719,46 @@ async def test_delete_backup_async( request = request_type() # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client.transport.delete_backup), "__call__") as call: + with mock.patch.object(type(client.transport.list_backups), "__call__") as call: # Designate an appropriate return value for the call. - call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(None) - response = await client.delete_backup(request) + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + firestore_admin.ListBackupsResponse( + unreachable=["unreachable_value"], + ) + ) + response = await client.list_backups(request) # Establish that the underlying gRPC stub method was called. assert len(call.mock_calls) _, args, _ = call.mock_calls[0] - request = firestore_admin.DeleteBackupRequest() + request = firestore_admin.ListBackupsRequest() assert args[0] == request # Establish that the response is the type that we expect. - assert response is None + assert isinstance(response, firestore_admin.ListBackupsResponse) + assert response.unreachable == ["unreachable_value"] @pytest.mark.asyncio -async def test_delete_backup_async_from_dict(): - await test_delete_backup_async(request_type=dict) +async def test_list_backups_async_from_dict(): + await test_list_backups_async(request_type=dict) -def test_delete_backup_field_headers(): +def test_list_backups_field_headers(): client = FirestoreAdminClient( credentials=ga_credentials.AnonymousCredentials(), ) # Any value that is part of the HTTP/1.1 URI should be sent as # a field header. Set these to a non-empty value. - request = firestore_admin.DeleteBackupRequest() + request = firestore_admin.ListBackupsRequest() - request.name = "name_value" + request.parent = "parent_value" # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client.transport.delete_backup), "__call__") as call: - call.return_value = None - client.delete_backup(request) + with mock.patch.object(type(client.transport.list_backups), "__call__") as call: + call.return_value = firestore_admin.ListBackupsResponse() + client.list_backups(request) # Establish that the underlying gRPC stub method was called. assert len(call.mock_calls) == 1 @@ -6241,26 +7769,28 @@ def test_delete_backup_field_headers(): _, _, kw = call.mock_calls[0] assert ( "x-goog-request-params", - "name=name_value", + "parent=parent_value", ) in kw["metadata"] @pytest.mark.asyncio -async def test_delete_backup_field_headers_async(): +async def test_list_backups_field_headers_async(): client = FirestoreAdminAsyncClient( credentials=ga_credentials.AnonymousCredentials(), ) # Any value that is part of the HTTP/1.1 URI should be sent as # a field header. Set these to a non-empty value. - request = firestore_admin.DeleteBackupRequest() + request = firestore_admin.ListBackupsRequest() - request.name = "name_value" + request.parent = "parent_value" # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client.transport.delete_backup), "__call__") as call: - call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(None) - await client.delete_backup(request) + with mock.patch.object(type(client.transport.list_backups), "__call__") as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + firestore_admin.ListBackupsResponse() + ) + await client.list_backups(request) # Establish that the underlying gRPC stub method was called. assert len(call.mock_calls) @@ -6271,35 +7801,35 @@ async def test_delete_backup_field_headers_async(): _, _, kw = call.mock_calls[0] assert ( "x-goog-request-params", - "name=name_value", + "parent=parent_value", ) in kw["metadata"] -def test_delete_backup_flattened(): +def test_list_backups_flattened(): client = FirestoreAdminClient( credentials=ga_credentials.AnonymousCredentials(), ) # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client.transport.delete_backup), "__call__") as call: + with mock.patch.object(type(client.transport.list_backups), "__call__") as call: # Designate an appropriate return value for the call. - call.return_value = None + call.return_value = firestore_admin.ListBackupsResponse() # Call the method with a truthy value for each flattened field, # using the keyword arguments to the method. - client.delete_backup( - name="name_value", + client.list_backups( + parent="parent_value", ) # Establish that the underlying call was made with the expected # request object values. assert len(call.mock_calls) == 1 _, args, _ = call.mock_calls[0] - arg = args[0].name - mock_val = "name_value" + arg = args[0].parent + mock_val = "parent_value" assert arg == mock_val -def test_delete_backup_flattened_error(): +def test_list_backups_flattened_error(): client = FirestoreAdminClient( credentials=ga_credentials.AnonymousCredentials(), ) @@ -6307,41 +7837,43 @@ def test_delete_backup_flattened_error(): # Attempting to call a method with both a request object and flattened # fields is an error. with pytest.raises(ValueError): - client.delete_backup( - firestore_admin.DeleteBackupRequest(), - name="name_value", + client.list_backups( + firestore_admin.ListBackupsRequest(), + parent="parent_value", ) @pytest.mark.asyncio -async def test_delete_backup_flattened_async(): +async def test_list_backups_flattened_async(): client = FirestoreAdminAsyncClient( credentials=ga_credentials.AnonymousCredentials(), ) # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client.transport.delete_backup), "__call__") as call: + with mock.patch.object(type(client.transport.list_backups), "__call__") as call: # Designate an appropriate return value for the call. - call.return_value = None + call.return_value = firestore_admin.ListBackupsResponse() - call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(None) + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + firestore_admin.ListBackupsResponse() + ) # Call the method with a truthy value for each flattened field, # using the keyword arguments to the method. - response = await client.delete_backup( - name="name_value", + response = await client.list_backups( + parent="parent_value", ) # Establish that the underlying call was made with the expected # request object values. assert len(call.mock_calls) _, args, _ = call.mock_calls[0] - arg = args[0].name - mock_val = "name_value" + arg = args[0].parent + mock_val = "parent_value" assert arg == mock_val @pytest.mark.asyncio -async def test_delete_backup_flattened_error_async(): +async def test_list_backups_flattened_error_async(): client = FirestoreAdminAsyncClient( credentials=ga_credentials.AnonymousCredentials(), ) @@ -6349,20 +7881,20 @@ async def test_delete_backup_flattened_error_async(): # Attempting to call a method with both a request object and flattened # fields is an error. with pytest.raises(ValueError): - await client.delete_backup( - firestore_admin.DeleteBackupRequest(), - name="name_value", + await client.list_backups( + firestore_admin.ListBackupsRequest(), + parent="parent_value", ) @pytest.mark.parametrize( "request_type", [ - firestore_admin.RestoreDatabaseRequest, + firestore_admin.DeleteBackupRequest, dict, ], ) -def test_restore_database(request_type, transport: str = "grpc"): +def test_delete_backup(request_type, transport: str = "grpc"): client = FirestoreAdminClient( credentials=ga_credentials.AnonymousCredentials(), transport=transport, @@ -6373,22 +7905,22 @@ def test_restore_database(request_type, transport: str = "grpc"): request = request_type() # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client.transport.restore_database), "__call__") as call: + with mock.patch.object(type(client.transport.delete_backup), "__call__") as call: # Designate an appropriate return value for the call. - call.return_value = operations_pb2.Operation(name="operations/spam") - response = client.restore_database(request) + call.return_value = None + response = client.delete_backup(request) # Establish that the underlying gRPC stub method was called. assert len(call.mock_calls) == 1 _, args, _ = call.mock_calls[0] - request = firestore_admin.RestoreDatabaseRequest() + request = firestore_admin.DeleteBackupRequest() assert args[0] == request # Establish that the response is the type that we expect. - assert isinstance(response, future.Future) + assert response is None -def test_restore_database_empty_call(): +def test_delete_backup_empty_call(): # This test is a coverage failsafe to make sure that totally empty calls, # i.e. request == None and no flattened fields passed, work. client = FirestoreAdminClient( @@ -6397,14 +7929,17 @@ def test_restore_database_empty_call(): ) # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client.transport.restore_database), "__call__") as call: - client.restore_database() + with mock.patch.object(type(client.transport.delete_backup), "__call__") as call: + call.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) + client.delete_backup() call.assert_called() _, args, _ = call.mock_calls[0] - assert args[0] == firestore_admin.RestoreDatabaseRequest() + assert args[0] == firestore_admin.DeleteBackupRequest() -def test_restore_database_non_empty_request_with_auto_populated_field(): +def test_delete_backup_non_empty_request_with_auto_populated_field(): # This test is a coverage failsafe to make sure that UUID4 fields are # automatically populated, according to AIP-4235, with non-empty requests. client = FirestoreAdminClient( @@ -6415,26 +7950,60 @@ def test_restore_database_non_empty_request_with_auto_populated_field(): # Populate all string fields in the request which are not UUID4 # since we want to check that UUID4 are populated automatically # if they meet the requirements of AIP 4235. - request = firestore_admin.RestoreDatabaseRequest( - parent="parent_value", - database_id="database_id_value", - backup="backup_value", + request = firestore_admin.DeleteBackupRequest( + name="name_value", ) # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client.transport.restore_database), "__call__") as call: - client.restore_database(request=request) + with mock.patch.object(type(client.transport.delete_backup), "__call__") as call: + call.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) + client.delete_backup(request=request) call.assert_called() _, args, _ = call.mock_calls[0] - assert args[0] == firestore_admin.RestoreDatabaseRequest( - parent="parent_value", - database_id="database_id_value", - backup="backup_value", + assert args[0] == firestore_admin.DeleteBackupRequest( + name="name_value", + ) + + +def test_delete_backup_use_cached_wrapped_rpc(): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method.wrap_method") as wrapper_fn: + client = FirestoreAdminClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="grpc", + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert client._transport.delete_backup in client._transport._wrapped_methods + + # Replace cached wrapped function with mock + mock_rpc = mock.Mock() + mock_rpc.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. ) + client._transport._wrapped_methods[client._transport.delete_backup] = mock_rpc + request = {} + client.delete_backup(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + client.delete_backup(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 @pytest.mark.asyncio -async def test_restore_database_empty_call_async(): +async def test_delete_backup_empty_call_async(): # This test is a coverage failsafe to make sure that totally empty calls, # i.e. request == None and no flattened fields passed, work. client = FirestoreAdminAsyncClient( @@ -6443,20 +8012,60 @@ async def test_restore_database_empty_call_async(): ) # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client.transport.restore_database), "__call__") as call: + with mock.patch.object(type(client.transport.delete_backup), "__call__") as call: # Designate an appropriate return value for the call. - call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( - operations_pb2.Operation(name="operations/spam") - ) - response = await client.restore_database() + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(None) + response = await client.delete_backup() call.assert_called() _, args, _ = call.mock_calls[0] - assert args[0] == firestore_admin.RestoreDatabaseRequest() + assert args[0] == firestore_admin.DeleteBackupRequest() @pytest.mark.asyncio -async def test_restore_database_async( - transport: str = "grpc_asyncio", request_type=firestore_admin.RestoreDatabaseRequest +async def test_delete_backup_async_use_cached_wrapped_rpc( + transport: str = "grpc_asyncio", +): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method_async.wrap_method") as wrapper_fn: + client = FirestoreAdminAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert ( + client._client._transport.delete_backup + in client._client._transport._wrapped_methods + ) + + # Replace cached wrapped function with mock + mock_rpc = mock.AsyncMock() + mock_rpc.return_value = mock.Mock() + client._client._transport._wrapped_methods[ + client._client._transport.delete_backup + ] = mock_rpc + + request = {} + await client.delete_backup(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + await client.delete_backup(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 + + +@pytest.mark.asyncio +async def test_delete_backup_async( + transport: str = "grpc_asyncio", request_type=firestore_admin.DeleteBackupRequest ): client = FirestoreAdminAsyncClient( credentials=ga_credentials.AnonymousCredentials(), @@ -6468,43 +8077,41 @@ async def test_restore_database_async( request = request_type() # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client.transport.restore_database), "__call__") as call: + with mock.patch.object(type(client.transport.delete_backup), "__call__") as call: # Designate an appropriate return value for the call. - call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( - operations_pb2.Operation(name="operations/spam") - ) - response = await client.restore_database(request) + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(None) + response = await client.delete_backup(request) # Establish that the underlying gRPC stub method was called. assert len(call.mock_calls) _, args, _ = call.mock_calls[0] - request = firestore_admin.RestoreDatabaseRequest() + request = firestore_admin.DeleteBackupRequest() assert args[0] == request # Establish that the response is the type that we expect. - assert isinstance(response, future.Future) + assert response is None @pytest.mark.asyncio -async def test_restore_database_async_from_dict(): - await test_restore_database_async(request_type=dict) +async def test_delete_backup_async_from_dict(): + await test_delete_backup_async(request_type=dict) -def test_restore_database_field_headers(): +def test_delete_backup_field_headers(): client = FirestoreAdminClient( credentials=ga_credentials.AnonymousCredentials(), ) # Any value that is part of the HTTP/1.1 URI should be sent as # a field header. Set these to a non-empty value. - request = firestore_admin.RestoreDatabaseRequest() + request = firestore_admin.DeleteBackupRequest() - request.parent = "parent_value" + request.name = "name_value" # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client.transport.restore_database), "__call__") as call: - call.return_value = operations_pb2.Operation(name="operations/op") - client.restore_database(request) + with mock.patch.object(type(client.transport.delete_backup), "__call__") as call: + call.return_value = None + client.delete_backup(request) # Establish that the underlying gRPC stub method was called. assert len(call.mock_calls) == 1 @@ -6515,28 +8122,26 @@ def test_restore_database_field_headers(): _, _, kw = call.mock_calls[0] assert ( "x-goog-request-params", - "parent=parent_value", + "name=name_value", ) in kw["metadata"] @pytest.mark.asyncio -async def test_restore_database_field_headers_async(): +async def test_delete_backup_field_headers_async(): client = FirestoreAdminAsyncClient( credentials=ga_credentials.AnonymousCredentials(), ) # Any value that is part of the HTTP/1.1 URI should be sent as # a field header. Set these to a non-empty value. - request = firestore_admin.RestoreDatabaseRequest() + request = firestore_admin.DeleteBackupRequest() - request.parent = "parent_value" + request.name = "name_value" # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object(type(client.transport.restore_database), "__call__") as call: - call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( - operations_pb2.Operation(name="operations/op") - ) - await client.restore_database(request) + with mock.patch.object(type(client.transport.delete_backup), "__call__") as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(None) + await client.delete_backup(request) # Establish that the underlying gRPC stub method was called. assert len(call.mock_calls) @@ -6547,18 +8152,98 @@ async def test_restore_database_field_headers_async(): _, _, kw = call.mock_calls[0] assert ( "x-goog-request-params", - "parent=parent_value", + "name=name_value", ) in kw["metadata"] +def test_delete_backup_flattened(): + client = FirestoreAdminClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.delete_backup), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = None + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + client.delete_backup( + name="name_value", + ) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + arg = args[0].name + mock_val = "name_value" + assert arg == mock_val + + +def test_delete_backup_flattened_error(): + client = FirestoreAdminClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.delete_backup( + firestore_admin.DeleteBackupRequest(), + name="name_value", + ) + + +@pytest.mark.asyncio +async def test_delete_backup_flattened_async(): + client = FirestoreAdminAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.delete_backup), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = None + + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(None) + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + response = await client.delete_backup( + name="name_value", + ) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + arg = args[0].name + mock_val = "name_value" + assert arg == mock_val + + +@pytest.mark.asyncio +async def test_delete_backup_flattened_error_async(): + client = FirestoreAdminAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + await client.delete_backup( + firestore_admin.DeleteBackupRequest(), + name="name_value", + ) + + @pytest.mark.parametrize( "request_type", [ - firestore_admin.CreateBackupScheduleRequest, + firestore_admin.RestoreDatabaseRequest, dict, ], ) -def test_create_backup_schedule(request_type, transport: str = "grpc"): +def test_restore_database(request_type, transport: str = "grpc"): client = FirestoreAdminClient( credentials=ga_credentials.AnonymousCredentials(), transport=transport, @@ -6569,27 +8254,22 @@ def test_create_backup_schedule(request_type, transport: str = "grpc"): request = request_type() # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object( - type(client.transport.create_backup_schedule), "__call__" - ) as call: + with mock.patch.object(type(client.transport.restore_database), "__call__") as call: # Designate an appropriate return value for the call. - call.return_value = schedule.BackupSchedule( - name="name_value", - ) - response = client.create_backup_schedule(request) + call.return_value = operations_pb2.Operation(name="operations/spam") + response = client.restore_database(request) # Establish that the underlying gRPC stub method was called. assert len(call.mock_calls) == 1 _, args, _ = call.mock_calls[0] - request = firestore_admin.CreateBackupScheduleRequest() + request = firestore_admin.RestoreDatabaseRequest() assert args[0] == request # Establish that the response is the type that we expect. - assert isinstance(response, schedule.BackupSchedule) - assert response.name == "name_value" + assert isinstance(response, future.Future) -def test_create_backup_schedule_empty_call(): +def test_restore_database_empty_call(): # This test is a coverage failsafe to make sure that totally empty calls, # i.e. request == None and no flattened fields passed, work. client = FirestoreAdminClient( @@ -6598,16 +8278,17 @@ def test_create_backup_schedule_empty_call(): ) # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object( - type(client.transport.create_backup_schedule), "__call__" - ) as call: - client.create_backup_schedule() + with mock.patch.object(type(client.transport.restore_database), "__call__") as call: + call.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) + client.restore_database() call.assert_called() _, args, _ = call.mock_calls[0] - assert args[0] == firestore_admin.CreateBackupScheduleRequest() + assert args[0] == firestore_admin.RestoreDatabaseRequest() -def test_create_backup_schedule_non_empty_request_with_auto_populated_field(): +def test_restore_database_non_empty_request_with_auto_populated_field(): # This test is a coverage failsafe to make sure that UUID4 fields are # automatically populated, according to AIP-4235, with non-empty requests. client = FirestoreAdminClient( @@ -6618,51 +8299,140 @@ def test_create_backup_schedule_non_empty_request_with_auto_populated_field(): # Populate all string fields in the request which are not UUID4 # since we want to check that UUID4 are populated automatically # if they meet the requirements of AIP 4235. - request = firestore_admin.CreateBackupScheduleRequest( + request = firestore_admin.RestoreDatabaseRequest( parent="parent_value", + database_id="database_id_value", + backup="backup_value", ) # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object( - type(client.transport.create_backup_schedule), "__call__" - ) as call: - client.create_backup_schedule(request=request) + with mock.patch.object(type(client.transport.restore_database), "__call__") as call: + call.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) + client.restore_database(request=request) call.assert_called() _, args, _ = call.mock_calls[0] - assert args[0] == firestore_admin.CreateBackupScheduleRequest( + assert args[0] == firestore_admin.RestoreDatabaseRequest( parent="parent_value", + database_id="database_id_value", + backup="backup_value", ) -@pytest.mark.asyncio -async def test_create_backup_schedule_empty_call_async(): - # This test is a coverage failsafe to make sure that totally empty calls, - # i.e. request == None and no flattened fields passed, work. - client = FirestoreAdminAsyncClient( - credentials=ga_credentials.AnonymousCredentials(), - transport="grpc_asyncio", - ) +def test_restore_database_use_cached_wrapped_rpc(): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method.wrap_method") as wrapper_fn: + client = FirestoreAdminClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="grpc", + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert client._transport.restore_database in client._transport._wrapped_methods + + # Replace cached wrapped function with mock + mock_rpc = mock.Mock() + mock_rpc.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) + client._transport._wrapped_methods[ + client._transport.restore_database + ] = mock_rpc + request = {} + client.restore_database(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + # Operation methods call wrapper_fn to build a cached + # client._transport.operations_client instance on first rpc call. + # Subsequent calls should use the cached wrapper + wrapper_fn.reset_mock() + + client.restore_database(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 + + +@pytest.mark.asyncio +async def test_restore_database_empty_call_async(): + # This test is a coverage failsafe to make sure that totally empty calls, + # i.e. request == None and no flattened fields passed, work. + client = FirestoreAdminAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="grpc_asyncio", + ) # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object( - type(client.transport.create_backup_schedule), "__call__" - ) as call: + with mock.patch.object(type(client.transport.restore_database), "__call__") as call: # Designate an appropriate return value for the call. call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( - schedule.BackupSchedule( - name="name_value", - ) + operations_pb2.Operation(name="operations/spam") ) - response = await client.create_backup_schedule() + response = await client.restore_database() call.assert_called() _, args, _ = call.mock_calls[0] - assert args[0] == firestore_admin.CreateBackupScheduleRequest() + assert args[0] == firestore_admin.RestoreDatabaseRequest() @pytest.mark.asyncio -async def test_create_backup_schedule_async( +async def test_restore_database_async_use_cached_wrapped_rpc( transport: str = "grpc_asyncio", - request_type=firestore_admin.CreateBackupScheduleRequest, +): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method_async.wrap_method") as wrapper_fn: + client = FirestoreAdminAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert ( + client._client._transport.restore_database + in client._client._transport._wrapped_methods + ) + + # Replace cached wrapped function with mock + mock_rpc = mock.AsyncMock() + mock_rpc.return_value = mock.Mock() + client._client._transport._wrapped_methods[ + client._client._transport.restore_database + ] = mock_rpc + + request = {} + await client.restore_database(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + # Operation methods call wrapper_fn to build a cached + # client._transport.operations_client instance on first rpc call. + # Subsequent calls should use the cached wrapper + wrapper_fn.reset_mock() + + await client.restore_database(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 + + +@pytest.mark.asyncio +async def test_restore_database_async( + transport: str = "grpc_asyncio", request_type=firestore_admin.RestoreDatabaseRequest ): client = FirestoreAdminAsyncClient( credentials=ga_credentials.AnonymousCredentials(), @@ -6674,50 +8444,43 @@ async def test_create_backup_schedule_async( request = request_type() # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object( - type(client.transport.create_backup_schedule), "__call__" - ) as call: + with mock.patch.object(type(client.transport.restore_database), "__call__") as call: # Designate an appropriate return value for the call. call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( - schedule.BackupSchedule( - name="name_value", - ) + operations_pb2.Operation(name="operations/spam") ) - response = await client.create_backup_schedule(request) + response = await client.restore_database(request) # Establish that the underlying gRPC stub method was called. assert len(call.mock_calls) _, args, _ = call.mock_calls[0] - request = firestore_admin.CreateBackupScheduleRequest() + request = firestore_admin.RestoreDatabaseRequest() assert args[0] == request # Establish that the response is the type that we expect. - assert isinstance(response, schedule.BackupSchedule) - assert response.name == "name_value" + assert isinstance(response, future.Future) @pytest.mark.asyncio -async def test_create_backup_schedule_async_from_dict(): - await test_create_backup_schedule_async(request_type=dict) +async def test_restore_database_async_from_dict(): + await test_restore_database_async(request_type=dict) -def test_create_backup_schedule_field_headers(): +def test_restore_database_field_headers(): client = FirestoreAdminClient( credentials=ga_credentials.AnonymousCredentials(), ) # Any value that is part of the HTTP/1.1 URI should be sent as # a field header. Set these to a non-empty value. - request = firestore_admin.CreateBackupScheduleRequest() + request = firestore_admin.RestoreDatabaseRequest() request.parent = "parent_value" # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object( - type(client.transport.create_backup_schedule), "__call__" - ) as call: - call.return_value = schedule.BackupSchedule() - client.create_backup_schedule(request) + with mock.patch.object(type(client.transport.restore_database), "__call__") as call: + call.return_value = operations_pb2.Operation(name="operations/op") + client.restore_database(request) # Establish that the underlying gRPC stub method was called. assert len(call.mock_calls) == 1 @@ -6733,25 +8496,23 @@ def test_create_backup_schedule_field_headers(): @pytest.mark.asyncio -async def test_create_backup_schedule_field_headers_async(): +async def test_restore_database_field_headers_async(): client = FirestoreAdminAsyncClient( credentials=ga_credentials.AnonymousCredentials(), ) # Any value that is part of the HTTP/1.1 URI should be sent as # a field header. Set these to a non-empty value. - request = firestore_admin.CreateBackupScheduleRequest() + request = firestore_admin.RestoreDatabaseRequest() request.parent = "parent_value" # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object( - type(client.transport.create_backup_schedule), "__call__" - ) as call: + with mock.patch.object(type(client.transport.restore_database), "__call__") as call: call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( - schedule.BackupSchedule() + operations_pb2.Operation(name="operations/op") ) - await client.create_backup_schedule(request) + await client.restore_database(request) # Establish that the underlying gRPC stub method was called. assert len(call.mock_calls) @@ -6766,110 +8527,14 @@ async def test_create_backup_schedule_field_headers_async(): ) in kw["metadata"] -def test_create_backup_schedule_flattened(): - client = FirestoreAdminClient( - credentials=ga_credentials.AnonymousCredentials(), - ) - - # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object( - type(client.transport.create_backup_schedule), "__call__" - ) as call: - # Designate an appropriate return value for the call. - call.return_value = schedule.BackupSchedule() - # Call the method with a truthy value for each flattened field, - # using the keyword arguments to the method. - client.create_backup_schedule( - parent="parent_value", - backup_schedule=schedule.BackupSchedule(name="name_value"), - ) - - # Establish that the underlying call was made with the expected - # request object values. - assert len(call.mock_calls) == 1 - _, args, _ = call.mock_calls[0] - arg = args[0].parent - mock_val = "parent_value" - assert arg == mock_val - arg = args[0].backup_schedule - mock_val = schedule.BackupSchedule(name="name_value") - assert arg == mock_val - - -def test_create_backup_schedule_flattened_error(): - client = FirestoreAdminClient( - credentials=ga_credentials.AnonymousCredentials(), - ) - - # Attempting to call a method with both a request object and flattened - # fields is an error. - with pytest.raises(ValueError): - client.create_backup_schedule( - firestore_admin.CreateBackupScheduleRequest(), - parent="parent_value", - backup_schedule=schedule.BackupSchedule(name="name_value"), - ) - - -@pytest.mark.asyncio -async def test_create_backup_schedule_flattened_async(): - client = FirestoreAdminAsyncClient( - credentials=ga_credentials.AnonymousCredentials(), - ) - - # Mock the actual call within the gRPC stub, and fake the request. - with mock.patch.object( - type(client.transport.create_backup_schedule), "__call__" - ) as call: - # Designate an appropriate return value for the call. - call.return_value = schedule.BackupSchedule() - - call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( - schedule.BackupSchedule() - ) - # Call the method with a truthy value for each flattened field, - # using the keyword arguments to the method. - response = await client.create_backup_schedule( - parent="parent_value", - backup_schedule=schedule.BackupSchedule(name="name_value"), - ) - - # Establish that the underlying call was made with the expected - # request object values. - assert len(call.mock_calls) - _, args, _ = call.mock_calls[0] - arg = args[0].parent - mock_val = "parent_value" - assert arg == mock_val - arg = args[0].backup_schedule - mock_val = schedule.BackupSchedule(name="name_value") - assert arg == mock_val - - -@pytest.mark.asyncio -async def test_create_backup_schedule_flattened_error_async(): - client = FirestoreAdminAsyncClient( - credentials=ga_credentials.AnonymousCredentials(), - ) - - # Attempting to call a method with both a request object and flattened - # fields is an error. - with pytest.raises(ValueError): - await client.create_backup_schedule( - firestore_admin.CreateBackupScheduleRequest(), - parent="parent_value", - backup_schedule=schedule.BackupSchedule(name="name_value"), - ) - - @pytest.mark.parametrize( "request_type", [ - firestore_admin.GetBackupScheduleRequest, + firestore_admin.CreateBackupScheduleRequest, dict, ], ) -def test_get_backup_schedule(request_type, transport: str = "grpc"): +def test_create_backup_schedule(request_type, transport: str = "grpc"): client = FirestoreAdminClient( credentials=ga_credentials.AnonymousCredentials(), transport=transport, @@ -6881,18 +8546,18 @@ def test_get_backup_schedule(request_type, transport: str = "grpc"): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client.transport.get_backup_schedule), "__call__" + type(client.transport.create_backup_schedule), "__call__" ) as call: # Designate an appropriate return value for the call. call.return_value = schedule.BackupSchedule( name="name_value", ) - response = client.get_backup_schedule(request) + response = client.create_backup_schedule(request) # Establish that the underlying gRPC stub method was called. assert len(call.mock_calls) == 1 _, args, _ = call.mock_calls[0] - request = firestore_admin.GetBackupScheduleRequest() + request = firestore_admin.CreateBackupScheduleRequest() assert args[0] == request # Establish that the response is the type that we expect. @@ -6900,7 +8565,7 @@ def test_get_backup_schedule(request_type, transport: str = "grpc"): assert response.name == "name_value" -def test_get_backup_schedule_empty_call(): +def test_create_backup_schedule_empty_call(): # This test is a coverage failsafe to make sure that totally empty calls, # i.e. request == None and no flattened fields passed, work. client = FirestoreAdminClient( @@ -6910,15 +8575,18 @@ def test_get_backup_schedule_empty_call(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client.transport.get_backup_schedule), "__call__" + type(client.transport.create_backup_schedule), "__call__" ) as call: - client.get_backup_schedule() + call.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) + client.create_backup_schedule() call.assert_called() _, args, _ = call.mock_calls[0] - assert args[0] == firestore_admin.GetBackupScheduleRequest() + assert args[0] == firestore_admin.CreateBackupScheduleRequest() -def test_get_backup_schedule_non_empty_request_with_auto_populated_field(): +def test_create_backup_schedule_non_empty_request_with_auto_populated_field(): # This test is a coverage failsafe to make sure that UUID4 fields are # automatically populated, according to AIP-4235, with non-empty requests. client = FirestoreAdminClient( @@ -6929,24 +8597,67 @@ def test_get_backup_schedule_non_empty_request_with_auto_populated_field(): # Populate all string fields in the request which are not UUID4 # since we want to check that UUID4 are populated automatically # if they meet the requirements of AIP 4235. - request = firestore_admin.GetBackupScheduleRequest( - name="name_value", + request = firestore_admin.CreateBackupScheduleRequest( + parent="parent_value", ) # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client.transport.get_backup_schedule), "__call__" + type(client.transport.create_backup_schedule), "__call__" ) as call: - client.get_backup_schedule(request=request) + call.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) + client.create_backup_schedule(request=request) call.assert_called() _, args, _ = call.mock_calls[0] - assert args[0] == firestore_admin.GetBackupScheduleRequest( - name="name_value", + assert args[0] == firestore_admin.CreateBackupScheduleRequest( + parent="parent_value", + ) + + +def test_create_backup_schedule_use_cached_wrapped_rpc(): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method.wrap_method") as wrapper_fn: + client = FirestoreAdminClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="grpc", + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert ( + client._transport.create_backup_schedule + in client._transport._wrapped_methods + ) + + # Replace cached wrapped function with mock + mock_rpc = mock.Mock() + mock_rpc.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. ) + client._transport._wrapped_methods[ + client._transport.create_backup_schedule + ] = mock_rpc + request = {} + client.create_backup_schedule(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + client.create_backup_schedule(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 @pytest.mark.asyncio -async def test_get_backup_schedule_empty_call_async(): +async def test_create_backup_schedule_empty_call_async(): # This test is a coverage failsafe to make sure that totally empty calls, # i.e. request == None and no flattened fields passed, work. client = FirestoreAdminAsyncClient( @@ -6956,7 +8667,7 @@ async def test_get_backup_schedule_empty_call_async(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client.transport.get_backup_schedule), "__call__" + type(client.transport.create_backup_schedule), "__call__" ) as call: # Designate an appropriate return value for the call. call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( @@ -6964,16 +8675,58 @@ async def test_get_backup_schedule_empty_call_async(): name="name_value", ) ) - response = await client.get_backup_schedule() + response = await client.create_backup_schedule() call.assert_called() _, args, _ = call.mock_calls[0] - assert args[0] == firestore_admin.GetBackupScheduleRequest() + assert args[0] == firestore_admin.CreateBackupScheduleRequest() @pytest.mark.asyncio -async def test_get_backup_schedule_async( +async def test_create_backup_schedule_async_use_cached_wrapped_rpc( transport: str = "grpc_asyncio", - request_type=firestore_admin.GetBackupScheduleRequest, +): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method_async.wrap_method") as wrapper_fn: + client = FirestoreAdminAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert ( + client._client._transport.create_backup_schedule + in client._client._transport._wrapped_methods + ) + + # Replace cached wrapped function with mock + mock_rpc = mock.AsyncMock() + mock_rpc.return_value = mock.Mock() + client._client._transport._wrapped_methods[ + client._client._transport.create_backup_schedule + ] = mock_rpc + + request = {} + await client.create_backup_schedule(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + await client.create_backup_schedule(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 + + +@pytest.mark.asyncio +async def test_create_backup_schedule_async( + transport: str = "grpc_asyncio", + request_type=firestore_admin.CreateBackupScheduleRequest, ): client = FirestoreAdminAsyncClient( credentials=ga_credentials.AnonymousCredentials(), @@ -6986,7 +8739,7 @@ async def test_get_backup_schedule_async( # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client.transport.get_backup_schedule), "__call__" + type(client.transport.create_backup_schedule), "__call__" ) as call: # Designate an appropriate return value for the call. call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( @@ -6994,12 +8747,12 @@ async def test_get_backup_schedule_async( name="name_value", ) ) - response = await client.get_backup_schedule(request) + response = await client.create_backup_schedule(request) # Establish that the underlying gRPC stub method was called. assert len(call.mock_calls) _, args, _ = call.mock_calls[0] - request = firestore_admin.GetBackupScheduleRequest() + request = firestore_admin.CreateBackupScheduleRequest() assert args[0] == request # Establish that the response is the type that we expect. @@ -7008,27 +8761,27 @@ async def test_get_backup_schedule_async( @pytest.mark.asyncio -async def test_get_backup_schedule_async_from_dict(): - await test_get_backup_schedule_async(request_type=dict) +async def test_create_backup_schedule_async_from_dict(): + await test_create_backup_schedule_async(request_type=dict) -def test_get_backup_schedule_field_headers(): +def test_create_backup_schedule_field_headers(): client = FirestoreAdminClient( credentials=ga_credentials.AnonymousCredentials(), ) # Any value that is part of the HTTP/1.1 URI should be sent as # a field header. Set these to a non-empty value. - request = firestore_admin.GetBackupScheduleRequest() + request = firestore_admin.CreateBackupScheduleRequest() - request.name = "name_value" + request.parent = "parent_value" # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client.transport.get_backup_schedule), "__call__" + type(client.transport.create_backup_schedule), "__call__" ) as call: call.return_value = schedule.BackupSchedule() - client.get_backup_schedule(request) + client.create_backup_schedule(request) # Establish that the underlying gRPC stub method was called. assert len(call.mock_calls) == 1 @@ -7039,30 +8792,30 @@ def test_get_backup_schedule_field_headers(): _, _, kw = call.mock_calls[0] assert ( "x-goog-request-params", - "name=name_value", + "parent=parent_value", ) in kw["metadata"] @pytest.mark.asyncio -async def test_get_backup_schedule_field_headers_async(): +async def test_create_backup_schedule_field_headers_async(): client = FirestoreAdminAsyncClient( credentials=ga_credentials.AnonymousCredentials(), ) # Any value that is part of the HTTP/1.1 URI should be sent as # a field header. Set these to a non-empty value. - request = firestore_admin.GetBackupScheduleRequest() + request = firestore_admin.CreateBackupScheduleRequest() - request.name = "name_value" + request.parent = "parent_value" # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client.transport.get_backup_schedule), "__call__" + type(client.transport.create_backup_schedule), "__call__" ) as call: call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( schedule.BackupSchedule() ) - await client.get_backup_schedule(request) + await client.create_backup_schedule(request) # Establish that the underlying gRPC stub method was called. assert len(call.mock_calls) @@ -7073,37 +8826,41 @@ async def test_get_backup_schedule_field_headers_async(): _, _, kw = call.mock_calls[0] assert ( "x-goog-request-params", - "name=name_value", + "parent=parent_value", ) in kw["metadata"] -def test_get_backup_schedule_flattened(): +def test_create_backup_schedule_flattened(): client = FirestoreAdminClient( credentials=ga_credentials.AnonymousCredentials(), ) # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client.transport.get_backup_schedule), "__call__" + type(client.transport.create_backup_schedule), "__call__" ) as call: # Designate an appropriate return value for the call. call.return_value = schedule.BackupSchedule() # Call the method with a truthy value for each flattened field, # using the keyword arguments to the method. - client.get_backup_schedule( - name="name_value", + client.create_backup_schedule( + parent="parent_value", + backup_schedule=schedule.BackupSchedule(name="name_value"), ) # Establish that the underlying call was made with the expected # request object values. assert len(call.mock_calls) == 1 _, args, _ = call.mock_calls[0] - arg = args[0].name - mock_val = "name_value" + arg = args[0].parent + mock_val = "parent_value" + assert arg == mock_val + arg = args[0].backup_schedule + mock_val = schedule.BackupSchedule(name="name_value") assert arg == mock_val -def test_get_backup_schedule_flattened_error(): +def test_create_backup_schedule_flattened_error(): client = FirestoreAdminClient( credentials=ga_credentials.AnonymousCredentials(), ) @@ -7111,21 +8868,22 @@ def test_get_backup_schedule_flattened_error(): # Attempting to call a method with both a request object and flattened # fields is an error. with pytest.raises(ValueError): - client.get_backup_schedule( - firestore_admin.GetBackupScheduleRequest(), - name="name_value", + client.create_backup_schedule( + firestore_admin.CreateBackupScheduleRequest(), + parent="parent_value", + backup_schedule=schedule.BackupSchedule(name="name_value"), ) @pytest.mark.asyncio -async def test_get_backup_schedule_flattened_async(): +async def test_create_backup_schedule_flattened_async(): client = FirestoreAdminAsyncClient( credentials=ga_credentials.AnonymousCredentials(), ) # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client.transport.get_backup_schedule), "__call__" + type(client.transport.create_backup_schedule), "__call__" ) as call: # Designate an appropriate return value for the call. call.return_value = schedule.BackupSchedule() @@ -7135,21 +8893,25 @@ async def test_get_backup_schedule_flattened_async(): ) # Call the method with a truthy value for each flattened field, # using the keyword arguments to the method. - response = await client.get_backup_schedule( - name="name_value", + response = await client.create_backup_schedule( + parent="parent_value", + backup_schedule=schedule.BackupSchedule(name="name_value"), ) # Establish that the underlying call was made with the expected # request object values. assert len(call.mock_calls) _, args, _ = call.mock_calls[0] - arg = args[0].name - mock_val = "name_value" + arg = args[0].parent + mock_val = "parent_value" + assert arg == mock_val + arg = args[0].backup_schedule + mock_val = schedule.BackupSchedule(name="name_value") assert arg == mock_val @pytest.mark.asyncio -async def test_get_backup_schedule_flattened_error_async(): +async def test_create_backup_schedule_flattened_error_async(): client = FirestoreAdminAsyncClient( credentials=ga_credentials.AnonymousCredentials(), ) @@ -7157,20 +8919,21 @@ async def test_get_backup_schedule_flattened_error_async(): # Attempting to call a method with both a request object and flattened # fields is an error. with pytest.raises(ValueError): - await client.get_backup_schedule( - firestore_admin.GetBackupScheduleRequest(), - name="name_value", + await client.create_backup_schedule( + firestore_admin.CreateBackupScheduleRequest(), + parent="parent_value", + backup_schedule=schedule.BackupSchedule(name="name_value"), ) @pytest.mark.parametrize( "request_type", [ - firestore_admin.ListBackupSchedulesRequest, + firestore_admin.GetBackupScheduleRequest, dict, ], ) -def test_list_backup_schedules(request_type, transport: str = "grpc"): +def test_get_backup_schedule(request_type, transport: str = "grpc"): client = FirestoreAdminClient( credentials=ga_credentials.AnonymousCredentials(), transport=transport, @@ -7182,23 +8945,26 @@ def test_list_backup_schedules(request_type, transport: str = "grpc"): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client.transport.list_backup_schedules), "__call__" + type(client.transport.get_backup_schedule), "__call__" ) as call: # Designate an appropriate return value for the call. - call.return_value = firestore_admin.ListBackupSchedulesResponse() - response = client.list_backup_schedules(request) + call.return_value = schedule.BackupSchedule( + name="name_value", + ) + response = client.get_backup_schedule(request) # Establish that the underlying gRPC stub method was called. assert len(call.mock_calls) == 1 _, args, _ = call.mock_calls[0] - request = firestore_admin.ListBackupSchedulesRequest() + request = firestore_admin.GetBackupScheduleRequest() assert args[0] == request # Establish that the response is the type that we expect. - assert isinstance(response, firestore_admin.ListBackupSchedulesResponse) + assert isinstance(response, schedule.BackupSchedule) + assert response.name == "name_value" -def test_list_backup_schedules_empty_call(): +def test_get_backup_schedule_empty_call(): # This test is a coverage failsafe to make sure that totally empty calls, # i.e. request == None and no flattened fields passed, work. client = FirestoreAdminClient( @@ -7208,15 +8974,18 @@ def test_list_backup_schedules_empty_call(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client.transport.list_backup_schedules), "__call__" + type(client.transport.get_backup_schedule), "__call__" ) as call: - client.list_backup_schedules() + call.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) + client.get_backup_schedule() call.assert_called() _, args, _ = call.mock_calls[0] - assert args[0] == firestore_admin.ListBackupSchedulesRequest() + assert args[0] == firestore_admin.GetBackupScheduleRequest() -def test_list_backup_schedules_non_empty_request_with_auto_populated_field(): +def test_get_backup_schedule_non_empty_request_with_auto_populated_field(): # This test is a coverage failsafe to make sure that UUID4 fields are # automatically populated, according to AIP-4235, with non-empty requests. client = FirestoreAdminClient( @@ -7227,24 +8996,66 @@ def test_list_backup_schedules_non_empty_request_with_auto_populated_field(): # Populate all string fields in the request which are not UUID4 # since we want to check that UUID4 are populated automatically # if they meet the requirements of AIP 4235. - request = firestore_admin.ListBackupSchedulesRequest( - parent="parent_value", + request = firestore_admin.GetBackupScheduleRequest( + name="name_value", ) # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client.transport.list_backup_schedules), "__call__" + type(client.transport.get_backup_schedule), "__call__" ) as call: - client.list_backup_schedules(request=request) + call.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) + client.get_backup_schedule(request=request) call.assert_called() _, args, _ = call.mock_calls[0] - assert args[0] == firestore_admin.ListBackupSchedulesRequest( - parent="parent_value", + assert args[0] == firestore_admin.GetBackupScheduleRequest( + name="name_value", + ) + + +def test_get_backup_schedule_use_cached_wrapped_rpc(): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method.wrap_method") as wrapper_fn: + client = FirestoreAdminClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="grpc", + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert ( + client._transport.get_backup_schedule in client._transport._wrapped_methods ) + # Replace cached wrapped function with mock + mock_rpc = mock.Mock() + mock_rpc.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) + client._transport._wrapped_methods[ + client._transport.get_backup_schedule + ] = mock_rpc + request = {} + client.get_backup_schedule(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + client.get_backup_schedule(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 + @pytest.mark.asyncio -async def test_list_backup_schedules_empty_call_async(): +async def test_get_backup_schedule_empty_call_async(): # This test is a coverage failsafe to make sure that totally empty calls, # i.e. request == None and no flattened fields passed, work. client = FirestoreAdminAsyncClient( @@ -7254,22 +9065,66 @@ async def test_list_backup_schedules_empty_call_async(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client.transport.list_backup_schedules), "__call__" + type(client.transport.get_backup_schedule), "__call__" ) as call: # Designate an appropriate return value for the call. call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( - firestore_admin.ListBackupSchedulesResponse() + schedule.BackupSchedule( + name="name_value", + ) ) - response = await client.list_backup_schedules() + response = await client.get_backup_schedule() call.assert_called() _, args, _ = call.mock_calls[0] - assert args[0] == firestore_admin.ListBackupSchedulesRequest() + assert args[0] == firestore_admin.GetBackupScheduleRequest() @pytest.mark.asyncio -async def test_list_backup_schedules_async( +async def test_get_backup_schedule_async_use_cached_wrapped_rpc( transport: str = "grpc_asyncio", - request_type=firestore_admin.ListBackupSchedulesRequest, +): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method_async.wrap_method") as wrapper_fn: + client = FirestoreAdminAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert ( + client._client._transport.get_backup_schedule + in client._client._transport._wrapped_methods + ) + + # Replace cached wrapped function with mock + mock_rpc = mock.AsyncMock() + mock_rpc.return_value = mock.Mock() + client._client._transport._wrapped_methods[ + client._client._transport.get_backup_schedule + ] = mock_rpc + + request = {} + await client.get_backup_schedule(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + await client.get_backup_schedule(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 + + +@pytest.mark.asyncio +async def test_get_backup_schedule_async( + transport: str = "grpc_asyncio", + request_type=firestore_admin.GetBackupScheduleRequest, ): client = FirestoreAdminAsyncClient( credentials=ga_credentials.AnonymousCredentials(), @@ -7282,46 +9137,49 @@ async def test_list_backup_schedules_async( # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client.transport.list_backup_schedules), "__call__" + type(client.transport.get_backup_schedule), "__call__" ) as call: # Designate an appropriate return value for the call. call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( - firestore_admin.ListBackupSchedulesResponse() + schedule.BackupSchedule( + name="name_value", + ) ) - response = await client.list_backup_schedules(request) + response = await client.get_backup_schedule(request) # Establish that the underlying gRPC stub method was called. assert len(call.mock_calls) _, args, _ = call.mock_calls[0] - request = firestore_admin.ListBackupSchedulesRequest() + request = firestore_admin.GetBackupScheduleRequest() assert args[0] == request # Establish that the response is the type that we expect. - assert isinstance(response, firestore_admin.ListBackupSchedulesResponse) + assert isinstance(response, schedule.BackupSchedule) + assert response.name == "name_value" @pytest.mark.asyncio -async def test_list_backup_schedules_async_from_dict(): - await test_list_backup_schedules_async(request_type=dict) +async def test_get_backup_schedule_async_from_dict(): + await test_get_backup_schedule_async(request_type=dict) -def test_list_backup_schedules_field_headers(): +def test_get_backup_schedule_field_headers(): client = FirestoreAdminClient( credentials=ga_credentials.AnonymousCredentials(), ) # Any value that is part of the HTTP/1.1 URI should be sent as # a field header. Set these to a non-empty value. - request = firestore_admin.ListBackupSchedulesRequest() + request = firestore_admin.GetBackupScheduleRequest() - request.parent = "parent_value" + request.name = "name_value" # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client.transport.list_backup_schedules), "__call__" + type(client.transport.get_backup_schedule), "__call__" ) as call: - call.return_value = firestore_admin.ListBackupSchedulesResponse() - client.list_backup_schedules(request) + call.return_value = schedule.BackupSchedule() + client.get_backup_schedule(request) # Establish that the underlying gRPC stub method was called. assert len(call.mock_calls) == 1 @@ -7332,30 +9190,30 @@ def test_list_backup_schedules_field_headers(): _, _, kw = call.mock_calls[0] assert ( "x-goog-request-params", - "parent=parent_value", + "name=name_value", ) in kw["metadata"] @pytest.mark.asyncio -async def test_list_backup_schedules_field_headers_async(): +async def test_get_backup_schedule_field_headers_async(): client = FirestoreAdminAsyncClient( credentials=ga_credentials.AnonymousCredentials(), ) # Any value that is part of the HTTP/1.1 URI should be sent as # a field header. Set these to a non-empty value. - request = firestore_admin.ListBackupSchedulesRequest() + request = firestore_admin.GetBackupScheduleRequest() - request.parent = "parent_value" + request.name = "name_value" # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client.transport.list_backup_schedules), "__call__" + type(client.transport.get_backup_schedule), "__call__" ) as call: call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( - firestore_admin.ListBackupSchedulesResponse() + schedule.BackupSchedule() ) - await client.list_backup_schedules(request) + await client.get_backup_schedule(request) # Establish that the underlying gRPC stub method was called. assert len(call.mock_calls) @@ -7366,37 +9224,37 @@ async def test_list_backup_schedules_field_headers_async(): _, _, kw = call.mock_calls[0] assert ( "x-goog-request-params", - "parent=parent_value", + "name=name_value", ) in kw["metadata"] -def test_list_backup_schedules_flattened(): +def test_get_backup_schedule_flattened(): client = FirestoreAdminClient( credentials=ga_credentials.AnonymousCredentials(), ) # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client.transport.list_backup_schedules), "__call__" + type(client.transport.get_backup_schedule), "__call__" ) as call: # Designate an appropriate return value for the call. - call.return_value = firestore_admin.ListBackupSchedulesResponse() + call.return_value = schedule.BackupSchedule() # Call the method with a truthy value for each flattened field, # using the keyword arguments to the method. - client.list_backup_schedules( - parent="parent_value", + client.get_backup_schedule( + name="name_value", ) # Establish that the underlying call was made with the expected # request object values. assert len(call.mock_calls) == 1 _, args, _ = call.mock_calls[0] - arg = args[0].parent - mock_val = "parent_value" + arg = args[0].name + mock_val = "name_value" assert arg == mock_val -def test_list_backup_schedules_flattened_error(): +def test_get_backup_schedule_flattened_error(): client = FirestoreAdminClient( credentials=ga_credentials.AnonymousCredentials(), ) @@ -7404,45 +9262,45 @@ def test_list_backup_schedules_flattened_error(): # Attempting to call a method with both a request object and flattened # fields is an error. with pytest.raises(ValueError): - client.list_backup_schedules( - firestore_admin.ListBackupSchedulesRequest(), - parent="parent_value", + client.get_backup_schedule( + firestore_admin.GetBackupScheduleRequest(), + name="name_value", ) @pytest.mark.asyncio -async def test_list_backup_schedules_flattened_async(): +async def test_get_backup_schedule_flattened_async(): client = FirestoreAdminAsyncClient( credentials=ga_credentials.AnonymousCredentials(), ) # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client.transport.list_backup_schedules), "__call__" + type(client.transport.get_backup_schedule), "__call__" ) as call: # Designate an appropriate return value for the call. - call.return_value = firestore_admin.ListBackupSchedulesResponse() + call.return_value = schedule.BackupSchedule() call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( - firestore_admin.ListBackupSchedulesResponse() + schedule.BackupSchedule() ) # Call the method with a truthy value for each flattened field, # using the keyword arguments to the method. - response = await client.list_backup_schedules( - parent="parent_value", + response = await client.get_backup_schedule( + name="name_value", ) # Establish that the underlying call was made with the expected # request object values. assert len(call.mock_calls) _, args, _ = call.mock_calls[0] - arg = args[0].parent - mock_val = "parent_value" + arg = args[0].name + mock_val = "name_value" assert arg == mock_val @pytest.mark.asyncio -async def test_list_backup_schedules_flattened_error_async(): +async def test_get_backup_schedule_flattened_error_async(): client = FirestoreAdminAsyncClient( credentials=ga_credentials.AnonymousCredentials(), ) @@ -7450,20 +9308,20 @@ async def test_list_backup_schedules_flattened_error_async(): # Attempting to call a method with both a request object and flattened # fields is an error. with pytest.raises(ValueError): - await client.list_backup_schedules( - firestore_admin.ListBackupSchedulesRequest(), - parent="parent_value", + await client.get_backup_schedule( + firestore_admin.GetBackupScheduleRequest(), + name="name_value", ) @pytest.mark.parametrize( "request_type", [ - firestore_admin.UpdateBackupScheduleRequest, + firestore_admin.ListBackupSchedulesRequest, dict, ], ) -def test_update_backup_schedule(request_type, transport: str = "grpc"): +def test_list_backup_schedules(request_type, transport: str = "grpc"): client = FirestoreAdminClient( credentials=ga_credentials.AnonymousCredentials(), transport=transport, @@ -7475,26 +9333,23 @@ def test_update_backup_schedule(request_type, transport: str = "grpc"): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client.transport.update_backup_schedule), "__call__" + type(client.transport.list_backup_schedules), "__call__" ) as call: # Designate an appropriate return value for the call. - call.return_value = schedule.BackupSchedule( - name="name_value", - ) - response = client.update_backup_schedule(request) + call.return_value = firestore_admin.ListBackupSchedulesResponse() + response = client.list_backup_schedules(request) # Establish that the underlying gRPC stub method was called. assert len(call.mock_calls) == 1 _, args, _ = call.mock_calls[0] - request = firestore_admin.UpdateBackupScheduleRequest() + request = firestore_admin.ListBackupSchedulesRequest() assert args[0] == request # Establish that the response is the type that we expect. - assert isinstance(response, schedule.BackupSchedule) - assert response.name == "name_value" + assert isinstance(response, firestore_admin.ListBackupSchedulesResponse) -def test_update_backup_schedule_empty_call(): +def test_list_backup_schedules_empty_call(): # This test is a coverage failsafe to make sure that totally empty calls, # i.e. request == None and no flattened fields passed, work. client = FirestoreAdminClient( @@ -7504,15 +9359,18 @@ def test_update_backup_schedule_empty_call(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client.transport.update_backup_schedule), "__call__" + type(client.transport.list_backup_schedules), "__call__" ) as call: - client.update_backup_schedule() + call.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) + client.list_backup_schedules() call.assert_called() _, args, _ = call.mock_calls[0] - assert args[0] == firestore_admin.UpdateBackupScheduleRequest() + assert args[0] == firestore_admin.ListBackupSchedulesRequest() -def test_update_backup_schedule_non_empty_request_with_auto_populated_field(): +def test_list_backup_schedules_non_empty_request_with_auto_populated_field(): # This test is a coverage failsafe to make sure that UUID4 fields are # automatically populated, according to AIP-4235, with non-empty requests. client = FirestoreAdminClient( @@ -7523,20 +9381,67 @@ def test_update_backup_schedule_non_empty_request_with_auto_populated_field(): # Populate all string fields in the request which are not UUID4 # since we want to check that UUID4 are populated automatically # if they meet the requirements of AIP 4235. - request = firestore_admin.UpdateBackupScheduleRequest() + request = firestore_admin.ListBackupSchedulesRequest( + parent="parent_value", + ) # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client.transport.update_backup_schedule), "__call__" + type(client.transport.list_backup_schedules), "__call__" ) as call: - client.update_backup_schedule(request=request) + call.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) + client.list_backup_schedules(request=request) call.assert_called() _, args, _ = call.mock_calls[0] - assert args[0] == firestore_admin.UpdateBackupScheduleRequest() + assert args[0] == firestore_admin.ListBackupSchedulesRequest( + parent="parent_value", + ) + + +def test_list_backup_schedules_use_cached_wrapped_rpc(): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method.wrap_method") as wrapper_fn: + client = FirestoreAdminClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="grpc", + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert ( + client._transport.list_backup_schedules + in client._transport._wrapped_methods + ) + + # Replace cached wrapped function with mock + mock_rpc = mock.Mock() + mock_rpc.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) + client._transport._wrapped_methods[ + client._transport.list_backup_schedules + ] = mock_rpc + request = {} + client.list_backup_schedules(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + client.list_backup_schedules(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 @pytest.mark.asyncio -async def test_update_backup_schedule_empty_call_async(): +async def test_list_backup_schedules_empty_call_async(): # This test is a coverage failsafe to make sure that totally empty calls, # i.e. request == None and no flattened fields passed, work. client = FirestoreAdminAsyncClient( @@ -7546,24 +9451,64 @@ async def test_update_backup_schedule_empty_call_async(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client.transport.update_backup_schedule), "__call__" + type(client.transport.list_backup_schedules), "__call__" ) as call: # Designate an appropriate return value for the call. call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( - schedule.BackupSchedule( - name="name_value", - ) + firestore_admin.ListBackupSchedulesResponse() ) - response = await client.update_backup_schedule() + response = await client.list_backup_schedules() call.assert_called() _, args, _ = call.mock_calls[0] - assert args[0] == firestore_admin.UpdateBackupScheduleRequest() + assert args[0] == firestore_admin.ListBackupSchedulesRequest() @pytest.mark.asyncio -async def test_update_backup_schedule_async( +async def test_list_backup_schedules_async_use_cached_wrapped_rpc( transport: str = "grpc_asyncio", - request_type=firestore_admin.UpdateBackupScheduleRequest, +): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method_async.wrap_method") as wrapper_fn: + client = FirestoreAdminAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert ( + client._client._transport.list_backup_schedules + in client._client._transport._wrapped_methods + ) + + # Replace cached wrapped function with mock + mock_rpc = mock.AsyncMock() + mock_rpc.return_value = mock.Mock() + client._client._transport._wrapped_methods[ + client._client._transport.list_backup_schedules + ] = mock_rpc + + request = {} + await client.list_backup_schedules(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + await client.list_backup_schedules(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 + + +@pytest.mark.asyncio +async def test_list_backup_schedules_async( + transport: str = "grpc_asyncio", + request_type=firestore_admin.ListBackupSchedulesRequest, ): client = FirestoreAdminAsyncClient( credentials=ga_credentials.AnonymousCredentials(), @@ -7576,49 +9521,46 @@ async def test_update_backup_schedule_async( # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client.transport.update_backup_schedule), "__call__" + type(client.transport.list_backup_schedules), "__call__" ) as call: # Designate an appropriate return value for the call. call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( - schedule.BackupSchedule( - name="name_value", - ) + firestore_admin.ListBackupSchedulesResponse() ) - response = await client.update_backup_schedule(request) + response = await client.list_backup_schedules(request) # Establish that the underlying gRPC stub method was called. assert len(call.mock_calls) _, args, _ = call.mock_calls[0] - request = firestore_admin.UpdateBackupScheduleRequest() + request = firestore_admin.ListBackupSchedulesRequest() assert args[0] == request # Establish that the response is the type that we expect. - assert isinstance(response, schedule.BackupSchedule) - assert response.name == "name_value" + assert isinstance(response, firestore_admin.ListBackupSchedulesResponse) @pytest.mark.asyncio -async def test_update_backup_schedule_async_from_dict(): - await test_update_backup_schedule_async(request_type=dict) +async def test_list_backup_schedules_async_from_dict(): + await test_list_backup_schedules_async(request_type=dict) -def test_update_backup_schedule_field_headers(): +def test_list_backup_schedules_field_headers(): client = FirestoreAdminClient( credentials=ga_credentials.AnonymousCredentials(), ) # Any value that is part of the HTTP/1.1 URI should be sent as # a field header. Set these to a non-empty value. - request = firestore_admin.UpdateBackupScheduleRequest() + request = firestore_admin.ListBackupSchedulesRequest() - request.backup_schedule.name = "name_value" + request.parent = "parent_value" # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client.transport.update_backup_schedule), "__call__" + type(client.transport.list_backup_schedules), "__call__" ) as call: - call.return_value = schedule.BackupSchedule() - client.update_backup_schedule(request) + call.return_value = firestore_admin.ListBackupSchedulesResponse() + client.list_backup_schedules(request) # Establish that the underlying gRPC stub method was called. assert len(call.mock_calls) == 1 @@ -7629,30 +9571,30 @@ def test_update_backup_schedule_field_headers(): _, _, kw = call.mock_calls[0] assert ( "x-goog-request-params", - "backup_schedule.name=name_value", + "parent=parent_value", ) in kw["metadata"] @pytest.mark.asyncio -async def test_update_backup_schedule_field_headers_async(): +async def test_list_backup_schedules_field_headers_async(): client = FirestoreAdminAsyncClient( credentials=ga_credentials.AnonymousCredentials(), ) # Any value that is part of the HTTP/1.1 URI should be sent as # a field header. Set these to a non-empty value. - request = firestore_admin.UpdateBackupScheduleRequest() + request = firestore_admin.ListBackupSchedulesRequest() - request.backup_schedule.name = "name_value" + request.parent = "parent_value" # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client.transport.update_backup_schedule), "__call__" + type(client.transport.list_backup_schedules), "__call__" ) as call: call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( - schedule.BackupSchedule() + firestore_admin.ListBackupSchedulesResponse() ) - await client.update_backup_schedule(request) + await client.list_backup_schedules(request) # Establish that the underlying gRPC stub method was called. assert len(call.mock_calls) @@ -7663,41 +9605,37 @@ async def test_update_backup_schedule_field_headers_async(): _, _, kw = call.mock_calls[0] assert ( "x-goog-request-params", - "backup_schedule.name=name_value", + "parent=parent_value", ) in kw["metadata"] -def test_update_backup_schedule_flattened(): +def test_list_backup_schedules_flattened(): client = FirestoreAdminClient( credentials=ga_credentials.AnonymousCredentials(), ) # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client.transport.update_backup_schedule), "__call__" + type(client.transport.list_backup_schedules), "__call__" ) as call: # Designate an appropriate return value for the call. - call.return_value = schedule.BackupSchedule() + call.return_value = firestore_admin.ListBackupSchedulesResponse() # Call the method with a truthy value for each flattened field, # using the keyword arguments to the method. - client.update_backup_schedule( - backup_schedule=schedule.BackupSchedule(name="name_value"), - update_mask=field_mask_pb2.FieldMask(paths=["paths_value"]), + client.list_backup_schedules( + parent="parent_value", ) # Establish that the underlying call was made with the expected # request object values. assert len(call.mock_calls) == 1 _, args, _ = call.mock_calls[0] - arg = args[0].backup_schedule - mock_val = schedule.BackupSchedule(name="name_value") - assert arg == mock_val - arg = args[0].update_mask - mock_val = field_mask_pb2.FieldMask(paths=["paths_value"]) + arg = args[0].parent + mock_val = "parent_value" assert arg == mock_val -def test_update_backup_schedule_flattened_error(): +def test_list_backup_schedules_flattened_error(): client = FirestoreAdminClient( credentials=ga_credentials.AnonymousCredentials(), ) @@ -7705,50 +9643,45 @@ def test_update_backup_schedule_flattened_error(): # Attempting to call a method with both a request object and flattened # fields is an error. with pytest.raises(ValueError): - client.update_backup_schedule( - firestore_admin.UpdateBackupScheduleRequest(), - backup_schedule=schedule.BackupSchedule(name="name_value"), - update_mask=field_mask_pb2.FieldMask(paths=["paths_value"]), + client.list_backup_schedules( + firestore_admin.ListBackupSchedulesRequest(), + parent="parent_value", ) @pytest.mark.asyncio -async def test_update_backup_schedule_flattened_async(): +async def test_list_backup_schedules_flattened_async(): client = FirestoreAdminAsyncClient( credentials=ga_credentials.AnonymousCredentials(), ) # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client.transport.update_backup_schedule), "__call__" + type(client.transport.list_backup_schedules), "__call__" ) as call: # Designate an appropriate return value for the call. - call.return_value = schedule.BackupSchedule() + call.return_value = firestore_admin.ListBackupSchedulesResponse() call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( - schedule.BackupSchedule() + firestore_admin.ListBackupSchedulesResponse() ) # Call the method with a truthy value for each flattened field, # using the keyword arguments to the method. - response = await client.update_backup_schedule( - backup_schedule=schedule.BackupSchedule(name="name_value"), - update_mask=field_mask_pb2.FieldMask(paths=["paths_value"]), + response = await client.list_backup_schedules( + parent="parent_value", ) # Establish that the underlying call was made with the expected # request object values. assert len(call.mock_calls) _, args, _ = call.mock_calls[0] - arg = args[0].backup_schedule - mock_val = schedule.BackupSchedule(name="name_value") - assert arg == mock_val - arg = args[0].update_mask - mock_val = field_mask_pb2.FieldMask(paths=["paths_value"]) + arg = args[0].parent + mock_val = "parent_value" assert arg == mock_val @pytest.mark.asyncio -async def test_update_backup_schedule_flattened_error_async(): +async def test_list_backup_schedules_flattened_error_async(): client = FirestoreAdminAsyncClient( credentials=ga_credentials.AnonymousCredentials(), ) @@ -7756,21 +9689,20 @@ async def test_update_backup_schedule_flattened_error_async(): # Attempting to call a method with both a request object and flattened # fields is an error. with pytest.raises(ValueError): - await client.update_backup_schedule( - firestore_admin.UpdateBackupScheduleRequest(), - backup_schedule=schedule.BackupSchedule(name="name_value"), - update_mask=field_mask_pb2.FieldMask(paths=["paths_value"]), + await client.list_backup_schedules( + firestore_admin.ListBackupSchedulesRequest(), + parent="parent_value", ) @pytest.mark.parametrize( "request_type", [ - firestore_admin.DeleteBackupScheduleRequest, + firestore_admin.UpdateBackupScheduleRequest, dict, ], ) -def test_delete_backup_schedule(request_type, transport: str = "grpc"): +def test_update_backup_schedule(request_type, transport: str = "grpc"): client = FirestoreAdminClient( credentials=ga_credentials.AnonymousCredentials(), transport=transport, @@ -7782,23 +9714,26 @@ def test_delete_backup_schedule(request_type, transport: str = "grpc"): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client.transport.delete_backup_schedule), "__call__" + type(client.transport.update_backup_schedule), "__call__" ) as call: # Designate an appropriate return value for the call. - call.return_value = None - response = client.delete_backup_schedule(request) + call.return_value = schedule.BackupSchedule( + name="name_value", + ) + response = client.update_backup_schedule(request) # Establish that the underlying gRPC stub method was called. assert len(call.mock_calls) == 1 _, args, _ = call.mock_calls[0] - request = firestore_admin.DeleteBackupScheduleRequest() + request = firestore_admin.UpdateBackupScheduleRequest() assert args[0] == request # Establish that the response is the type that we expect. - assert response is None + assert isinstance(response, schedule.BackupSchedule) + assert response.name == "name_value" -def test_delete_backup_schedule_empty_call(): +def test_update_backup_schedule_empty_call(): # This test is a coverage failsafe to make sure that totally empty calls, # i.e. request == None and no flattened fields passed, work. client = FirestoreAdminClient( @@ -7808,15 +9743,18 @@ def test_delete_backup_schedule_empty_call(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client.transport.delete_backup_schedule), "__call__" + type(client.transport.update_backup_schedule), "__call__" ) as call: - client.delete_backup_schedule() + call.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) + client.update_backup_schedule() call.assert_called() _, args, _ = call.mock_calls[0] - assert args[0] == firestore_admin.DeleteBackupScheduleRequest() + assert args[0] == firestore_admin.UpdateBackupScheduleRequest() -def test_delete_backup_schedule_non_empty_request_with_auto_populated_field(): +def test_update_backup_schedule_non_empty_request_with_auto_populated_field(): # This test is a coverage failsafe to make sure that UUID4 fields are # automatically populated, according to AIP-4235, with non-empty requests. client = FirestoreAdminClient( @@ -7827,24 +9765,63 @@ def test_delete_backup_schedule_non_empty_request_with_auto_populated_field(): # Populate all string fields in the request which are not UUID4 # since we want to check that UUID4 are populated automatically # if they meet the requirements of AIP 4235. - request = firestore_admin.DeleteBackupScheduleRequest( - name="name_value", - ) + request = firestore_admin.UpdateBackupScheduleRequest() # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client.transport.delete_backup_schedule), "__call__" + type(client.transport.update_backup_schedule), "__call__" ) as call: - client.delete_backup_schedule(request=request) + call.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) + client.update_backup_schedule(request=request) call.assert_called() _, args, _ = call.mock_calls[0] - assert args[0] == firestore_admin.DeleteBackupScheduleRequest( - name="name_value", + assert args[0] == firestore_admin.UpdateBackupScheduleRequest() + + +def test_update_backup_schedule_use_cached_wrapped_rpc(): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method.wrap_method") as wrapper_fn: + client = FirestoreAdminClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="grpc", + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert ( + client._transport.update_backup_schedule + in client._transport._wrapped_methods + ) + + # Replace cached wrapped function with mock + mock_rpc = mock.Mock() + mock_rpc.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. ) + client._transport._wrapped_methods[ + client._transport.update_backup_schedule + ] = mock_rpc + request = {} + client.update_backup_schedule(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + client.update_backup_schedule(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 @pytest.mark.asyncio -async def test_delete_backup_schedule_empty_call_async(): +async def test_update_backup_schedule_empty_call_async(): # This test is a coverage failsafe to make sure that totally empty calls, # i.e. request == None and no flattened fields passed, work. client = FirestoreAdminAsyncClient( @@ -7854,20 +9831,66 @@ async def test_delete_backup_schedule_empty_call_async(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client.transport.delete_backup_schedule), "__call__" + type(client.transport.update_backup_schedule), "__call__" ) as call: # Designate an appropriate return value for the call. - call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(None) - response = await client.delete_backup_schedule() + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + schedule.BackupSchedule( + name="name_value", + ) + ) + response = await client.update_backup_schedule() call.assert_called() _, args, _ = call.mock_calls[0] - assert args[0] == firestore_admin.DeleteBackupScheduleRequest() + assert args[0] == firestore_admin.UpdateBackupScheduleRequest() @pytest.mark.asyncio -async def test_delete_backup_schedule_async( +async def test_update_backup_schedule_async_use_cached_wrapped_rpc( transport: str = "grpc_asyncio", - request_type=firestore_admin.DeleteBackupScheduleRequest, +): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method_async.wrap_method") as wrapper_fn: + client = FirestoreAdminAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert ( + client._client._transport.update_backup_schedule + in client._client._transport._wrapped_methods + ) + + # Replace cached wrapped function with mock + mock_rpc = mock.AsyncMock() + mock_rpc.return_value = mock.Mock() + client._client._transport._wrapped_methods[ + client._client._transport.update_backup_schedule + ] = mock_rpc + + request = {} + await client.update_backup_schedule(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + await client.update_backup_schedule(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 + + +@pytest.mark.asyncio +async def test_update_backup_schedule_async( + transport: str = "grpc_asyncio", + request_type=firestore_admin.UpdateBackupScheduleRequest, ): client = FirestoreAdminAsyncClient( credentials=ga_credentials.AnonymousCredentials(), @@ -7880,44 +9903,49 @@ async def test_delete_backup_schedule_async( # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client.transport.delete_backup_schedule), "__call__" + type(client.transport.update_backup_schedule), "__call__" ) as call: # Designate an appropriate return value for the call. - call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(None) - response = await client.delete_backup_schedule(request) + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + schedule.BackupSchedule( + name="name_value", + ) + ) + response = await client.update_backup_schedule(request) # Establish that the underlying gRPC stub method was called. assert len(call.mock_calls) _, args, _ = call.mock_calls[0] - request = firestore_admin.DeleteBackupScheduleRequest() + request = firestore_admin.UpdateBackupScheduleRequest() assert args[0] == request # Establish that the response is the type that we expect. - assert response is None + assert isinstance(response, schedule.BackupSchedule) + assert response.name == "name_value" @pytest.mark.asyncio -async def test_delete_backup_schedule_async_from_dict(): - await test_delete_backup_schedule_async(request_type=dict) +async def test_update_backup_schedule_async_from_dict(): + await test_update_backup_schedule_async(request_type=dict) -def test_delete_backup_schedule_field_headers(): +def test_update_backup_schedule_field_headers(): client = FirestoreAdminClient( credentials=ga_credentials.AnonymousCredentials(), ) # Any value that is part of the HTTP/1.1 URI should be sent as # a field header. Set these to a non-empty value. - request = firestore_admin.DeleteBackupScheduleRequest() + request = firestore_admin.UpdateBackupScheduleRequest() - request.name = "name_value" + request.backup_schedule.name = "name_value" # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client.transport.delete_backup_schedule), "__call__" + type(client.transport.update_backup_schedule), "__call__" ) as call: - call.return_value = None - client.delete_backup_schedule(request) + call.return_value = schedule.BackupSchedule() + client.update_backup_schedule(request) # Establish that the underlying gRPC stub method was called. assert len(call.mock_calls) == 1 @@ -7928,28 +9956,30 @@ def test_delete_backup_schedule_field_headers(): _, _, kw = call.mock_calls[0] assert ( "x-goog-request-params", - "name=name_value", + "backup_schedule.name=name_value", ) in kw["metadata"] @pytest.mark.asyncio -async def test_delete_backup_schedule_field_headers_async(): +async def test_update_backup_schedule_field_headers_async(): client = FirestoreAdminAsyncClient( credentials=ga_credentials.AnonymousCredentials(), ) # Any value that is part of the HTTP/1.1 URI should be sent as # a field header. Set these to a non-empty value. - request = firestore_admin.DeleteBackupScheduleRequest() + request = firestore_admin.UpdateBackupScheduleRequest() - request.name = "name_value" + request.backup_schedule.name = "name_value" # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client.transport.delete_backup_schedule), "__call__" + type(client.transport.update_backup_schedule), "__call__" ) as call: - call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(None) - await client.delete_backup_schedule(request) + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + schedule.BackupSchedule() + ) + await client.update_backup_schedule(request) # Establish that the underlying gRPC stub method was called. assert len(call.mock_calls) @@ -7960,37 +9990,41 @@ async def test_delete_backup_schedule_field_headers_async(): _, _, kw = call.mock_calls[0] assert ( "x-goog-request-params", - "name=name_value", + "backup_schedule.name=name_value", ) in kw["metadata"] -def test_delete_backup_schedule_flattened(): +def test_update_backup_schedule_flattened(): client = FirestoreAdminClient( credentials=ga_credentials.AnonymousCredentials(), ) # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client.transport.delete_backup_schedule), "__call__" + type(client.transport.update_backup_schedule), "__call__" ) as call: # Designate an appropriate return value for the call. - call.return_value = None + call.return_value = schedule.BackupSchedule() # Call the method with a truthy value for each flattened field, # using the keyword arguments to the method. - client.delete_backup_schedule( - name="name_value", + client.update_backup_schedule( + backup_schedule=schedule.BackupSchedule(name="name_value"), + update_mask=field_mask_pb2.FieldMask(paths=["paths_value"]), ) # Establish that the underlying call was made with the expected # request object values. assert len(call.mock_calls) == 1 _, args, _ = call.mock_calls[0] - arg = args[0].name - mock_val = "name_value" + arg = args[0].backup_schedule + mock_val = schedule.BackupSchedule(name="name_value") + assert arg == mock_val + arg = args[0].update_mask + mock_val = field_mask_pb2.FieldMask(paths=["paths_value"]) assert arg == mock_val -def test_delete_backup_schedule_flattened_error(): +def test_update_backup_schedule_flattened_error(): client = FirestoreAdminClient( credentials=ga_credentials.AnonymousCredentials(), ) @@ -7998,43 +10032,50 @@ def test_delete_backup_schedule_flattened_error(): # Attempting to call a method with both a request object and flattened # fields is an error. with pytest.raises(ValueError): - client.delete_backup_schedule( - firestore_admin.DeleteBackupScheduleRequest(), - name="name_value", + client.update_backup_schedule( + firestore_admin.UpdateBackupScheduleRequest(), + backup_schedule=schedule.BackupSchedule(name="name_value"), + update_mask=field_mask_pb2.FieldMask(paths=["paths_value"]), ) @pytest.mark.asyncio -async def test_delete_backup_schedule_flattened_async(): +async def test_update_backup_schedule_flattened_async(): client = FirestoreAdminAsyncClient( credentials=ga_credentials.AnonymousCredentials(), ) # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object( - type(client.transport.delete_backup_schedule), "__call__" + type(client.transport.update_backup_schedule), "__call__" ) as call: # Designate an appropriate return value for the call. - call.return_value = None + call.return_value = schedule.BackupSchedule() - call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(None) + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + schedule.BackupSchedule() + ) # Call the method with a truthy value for each flattened field, # using the keyword arguments to the method. - response = await client.delete_backup_schedule( - name="name_value", + response = await client.update_backup_schedule( + backup_schedule=schedule.BackupSchedule(name="name_value"), + update_mask=field_mask_pb2.FieldMask(paths=["paths_value"]), ) # Establish that the underlying call was made with the expected # request object values. assert len(call.mock_calls) _, args, _ = call.mock_calls[0] - arg = args[0].name - mock_val = "name_value" + arg = args[0].backup_schedule + mock_val = schedule.BackupSchedule(name="name_value") + assert arg == mock_val + arg = args[0].update_mask + mock_val = field_mask_pb2.FieldMask(paths=["paths_value"]) assert arg == mock_val @pytest.mark.asyncio -async def test_delete_backup_schedule_flattened_error_async(): +async def test_update_backup_schedule_flattened_error_async(): client = FirestoreAdminAsyncClient( credentials=ga_credentials.AnonymousCredentials(), ) @@ -8042,20 +10083,791 @@ async def test_delete_backup_schedule_flattened_error_async(): # Attempting to call a method with both a request object and flattened # fields is an error. with pytest.raises(ValueError): - await client.delete_backup_schedule( - firestore_admin.DeleteBackupScheduleRequest(), - name="name_value", + await client.update_backup_schedule( + firestore_admin.UpdateBackupScheduleRequest(), + backup_schedule=schedule.BackupSchedule(name="name_value"), + update_mask=field_mask_pb2.FieldMask(paths=["paths_value"]), + ) + + +@pytest.mark.parametrize( + "request_type", + [ + firestore_admin.DeleteBackupScheduleRequest, + dict, + ], +) +def test_delete_backup_schedule(request_type, transport: str = "grpc"): + client = FirestoreAdminClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.delete_backup_schedule), "__call__" + ) as call: + # Designate an appropriate return value for the call. + call.return_value = None + response = client.delete_backup_schedule(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + request = firestore_admin.DeleteBackupScheduleRequest() + assert args[0] == request + + # Establish that the response is the type that we expect. + assert response is None + + +def test_delete_backup_schedule_empty_call(): + # This test is a coverage failsafe to make sure that totally empty calls, + # i.e. request == None and no flattened fields passed, work. + client = FirestoreAdminClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="grpc", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.delete_backup_schedule), "__call__" + ) as call: + call.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) + client.delete_backup_schedule() + call.assert_called() + _, args, _ = call.mock_calls[0] + assert args[0] == firestore_admin.DeleteBackupScheduleRequest() + + +def test_delete_backup_schedule_non_empty_request_with_auto_populated_field(): + # This test is a coverage failsafe to make sure that UUID4 fields are + # automatically populated, according to AIP-4235, with non-empty requests. + client = FirestoreAdminClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="grpc", + ) + + # Populate all string fields in the request which are not UUID4 + # since we want to check that UUID4 are populated automatically + # if they meet the requirements of AIP 4235. + request = firestore_admin.DeleteBackupScheduleRequest( + name="name_value", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.delete_backup_schedule), "__call__" + ) as call: + call.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. ) + client.delete_backup_schedule(request=request) + call.assert_called() + _, args, _ = call.mock_calls[0] + assert args[0] == firestore_admin.DeleteBackupScheduleRequest( + name="name_value", + ) + + +def test_delete_backup_schedule_use_cached_wrapped_rpc(): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method.wrap_method") as wrapper_fn: + client = FirestoreAdminClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="grpc", + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert ( + client._transport.delete_backup_schedule + in client._transport._wrapped_methods + ) + + # Replace cached wrapped function with mock + mock_rpc = mock.Mock() + mock_rpc.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) + client._transport._wrapped_methods[ + client._transport.delete_backup_schedule + ] = mock_rpc + request = {} + client.delete_backup_schedule(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + client.delete_backup_schedule(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 + + +@pytest.mark.asyncio +async def test_delete_backup_schedule_empty_call_async(): + # This test is a coverage failsafe to make sure that totally empty calls, + # i.e. request == None and no flattened fields passed, work. + client = FirestoreAdminAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="grpc_asyncio", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.delete_backup_schedule), "__call__" + ) as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(None) + response = await client.delete_backup_schedule() + call.assert_called() + _, args, _ = call.mock_calls[0] + assert args[0] == firestore_admin.DeleteBackupScheduleRequest() + + +@pytest.mark.asyncio +async def test_delete_backup_schedule_async_use_cached_wrapped_rpc( + transport: str = "grpc_asyncio", +): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method_async.wrap_method") as wrapper_fn: + client = FirestoreAdminAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert ( + client._client._transport.delete_backup_schedule + in client._client._transport._wrapped_methods + ) + + # Replace cached wrapped function with mock + mock_rpc = mock.AsyncMock() + mock_rpc.return_value = mock.Mock() + client._client._transport._wrapped_methods[ + client._client._transport.delete_backup_schedule + ] = mock_rpc + + request = {} + await client.delete_backup_schedule(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + await client.delete_backup_schedule(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 + + +@pytest.mark.asyncio +async def test_delete_backup_schedule_async( + transport: str = "grpc_asyncio", + request_type=firestore_admin.DeleteBackupScheduleRequest, +): + client = FirestoreAdminAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type() + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.delete_backup_schedule), "__call__" + ) as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(None) + response = await client.delete_backup_schedule(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + request = firestore_admin.DeleteBackupScheduleRequest() + assert args[0] == request + + # Establish that the response is the type that we expect. + assert response is None + + +@pytest.mark.asyncio +async def test_delete_backup_schedule_async_from_dict(): + await test_delete_backup_schedule_async(request_type=dict) + + +def test_delete_backup_schedule_field_headers(): + client = FirestoreAdminClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = firestore_admin.DeleteBackupScheduleRequest() + + request.name = "name_value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.delete_backup_schedule), "__call__" + ) as call: + call.return_value = None + client.delete_backup_schedule(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + "x-goog-request-params", + "name=name_value", + ) in kw["metadata"] + + +@pytest.mark.asyncio +async def test_delete_backup_schedule_field_headers_async(): + client = FirestoreAdminAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = firestore_admin.DeleteBackupScheduleRequest() + + request.name = "name_value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.delete_backup_schedule), "__call__" + ) as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(None) + await client.delete_backup_schedule(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + "x-goog-request-params", + "name=name_value", + ) in kw["metadata"] + + +def test_delete_backup_schedule_flattened(): + client = FirestoreAdminClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.delete_backup_schedule), "__call__" + ) as call: + # Designate an appropriate return value for the call. + call.return_value = None + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + client.delete_backup_schedule( + name="name_value", + ) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + arg = args[0].name + mock_val = "name_value" + assert arg == mock_val + + +def test_delete_backup_schedule_flattened_error(): + client = FirestoreAdminClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.delete_backup_schedule( + firestore_admin.DeleteBackupScheduleRequest(), + name="name_value", + ) + + +@pytest.mark.asyncio +async def test_delete_backup_schedule_flattened_async(): + client = FirestoreAdminAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object( + type(client.transport.delete_backup_schedule), "__call__" + ) as call: + # Designate an appropriate return value for the call. + call.return_value = None + + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall(None) + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + response = await client.delete_backup_schedule( + name="name_value", + ) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + arg = args[0].name + mock_val = "name_value" + assert arg == mock_val + + +@pytest.mark.asyncio +async def test_delete_backup_schedule_flattened_error_async(): + client = FirestoreAdminAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + await client.delete_backup_schedule( + firestore_admin.DeleteBackupScheduleRequest(), + name="name_value", + ) + + +@pytest.mark.parametrize( + "request_type", + [ + firestore_admin.CreateIndexRequest, + dict, + ], +) +def test_create_index_rest(request_type): + client = FirestoreAdminClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # send a request that will satisfy transcoding + request_init = { + "parent": "projects/sample1/databases/sample2/collectionGroups/sample3" + } + request_init["index"] = { + "name": "name_value", + "query_scope": 1, + "api_scope": 1, + "fields": [ + { + "field_path": "field_path_value", + "order": 1, + "array_config": 1, + "vector_config": {"dimension": 966, "flat": {}}, + } + ], + "state": 1, + } + # The version of a generated dependency at test runtime may differ from the version used during generation. + # Delete any fields which are not present in the current runtime dependency + # See https://github.com/googleapis/gapic-generator-python/issues/1748 + + # Determine if the message type is proto-plus or protobuf + test_field = firestore_admin.CreateIndexRequest.meta.fields["index"] + + def get_message_fields(field): + # Given a field which is a message (composite type), return a list with + # all the fields of the message. + # If the field is not a composite type, return an empty list. + message_fields = [] + + if hasattr(field, "message") and field.message: + is_field_type_proto_plus_type = not hasattr(field.message, "DESCRIPTOR") + + if is_field_type_proto_plus_type: + message_fields = field.message.meta.fields.values() + # Add `# pragma: NO COVER` because there may not be any `*_pb2` field types + else: # pragma: NO COVER + message_fields = field.message.DESCRIPTOR.fields + return message_fields + + runtime_nested_fields = [ + (field.name, nested_field.name) + for field in get_message_fields(test_field) + for nested_field in get_message_fields(field) + ] + + subfields_not_in_runtime = [] + + # For each item in the sample request, create a list of sub fields which are not present at runtime + # Add `# pragma: NO COVER` because this test code will not run if all subfields are present at runtime + for field, value in request_init["index"].items(): # pragma: NO COVER + result = None + is_repeated = False + # For repeated fields + if isinstance(value, list) and len(value): + is_repeated = True + result = value[0] + # For fields where the type is another message + if isinstance(value, dict): + result = value + + if result and hasattr(result, "keys"): + for subfield in result.keys(): + if (field, subfield) not in runtime_nested_fields: + subfields_not_in_runtime.append( + { + "field": field, + "subfield": subfield, + "is_repeated": is_repeated, + } + ) + + # Remove fields from the sample request which are not present in the runtime version of the dependency + # Add `# pragma: NO COVER` because this test code will not run if all subfields are present at runtime + for subfield_to_delete in subfields_not_in_runtime: # pragma: NO COVER + field = subfield_to_delete.get("field") + field_repeated = subfield_to_delete.get("is_repeated") + subfield = subfield_to_delete.get("subfield") + if subfield: + if field_repeated: + for i in range(0, len(request_init["index"][field])): + del request_init["index"][field][i][subfield] + else: + del request_init["index"][field][subfield] + request = request_type(**request_init) + + # Mock the http request call within the method and 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_index(request) + + # Establish that the response is the type that we expect. + assert response.operation.name == "operations/spam" + + +def test_create_index_rest_use_cached_wrapped_rpc(): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method.wrap_method") as wrapper_fn: + client = FirestoreAdminClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert client._transport.create_index in client._transport._wrapped_methods + + # Replace cached wrapped function with mock + mock_rpc = mock.Mock() + mock_rpc.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) + client._transport._wrapped_methods[client._transport.create_index] = mock_rpc + + request = {} + client.create_index(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + # Operation methods build a cached wrapper on first rpc call + # subsequent calls should use the cached wrapper + wrapper_fn.reset_mock() + + client.create_index(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 + + +def test_create_index_rest_required_fields( + request_type=firestore_admin.CreateIndexRequest, +): + transport_class = transports.FirestoreAdminRestTransport + + 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, use_integers_for_enums=False) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).create_index._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_index._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 = FirestoreAdminClient( + 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_index(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert expected_params == actual_params + + +def test_create_index_rest_unset_required_fields(): + transport = transports.FirestoreAdminRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.create_index._get_unset_required_fields({}) + assert set(unset_fields) == ( + set(()) + & set( + ( + "parent", + "index", + ) + ) + ) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_create_index_rest_interceptors(null_interceptor): + transport = transports.FirestoreAdminRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.FirestoreAdminRestInterceptor(), + ) + client = FirestoreAdminClient(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.FirestoreAdminRestInterceptor, "post_create_index" + ) as post, mock.patch.object( + transports.FirestoreAdminRestInterceptor, "pre_create_index" + ) as pre: + pre.assert_not_called() + post.assert_not_called() + pb_message = firestore_admin.CreateIndexRequest.pb( + firestore_admin.CreateIndexRequest() + ) + 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 = firestore_admin.CreateIndexRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = operations_pb2.Operation() + + client.create_index( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + + +def test_create_index_rest_bad_request( + transport: str = "rest", request_type=firestore_admin.CreateIndexRequest +): + client = FirestoreAdminClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # send a request that will satisfy transcoding + request_init = { + "parent": "projects/sample1/databases/sample2/collectionGroups/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.create_index(request) + + +def test_create_index_rest_flattened(): + client = FirestoreAdminClient( + 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/databases/sample2/collectionGroups/sample3" + } + + # get truthy value for each flattened field + mock_args = dict( + parent="parent_value", + index=gfa_index.Index(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_index(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v1/{parent=projects/*/databases/*/collectionGroups/*}/indexes" + % client.transport._host, + args[1], + ) + + +def test_create_index_rest_flattened_error(transport: str = "rest"): + client = FirestoreAdminClient( + 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_index( + firestore_admin.CreateIndexRequest(), + parent="parent_value", + index=gfa_index.Index(name="name_value"), + ) + + +def test_create_index_rest_error(): + client = FirestoreAdminClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) @pytest.mark.parametrize( "request_type", [ - firestore_admin.CreateIndexRequest, + firestore_admin.ListIndexesRequest, dict, ], ) -def test_create_index_rest(request_type): +def test_list_indexes_rest(request_type): client = FirestoreAdminClient( credentials=ga_credentials.AnonymousCredentials(), transport="rest", @@ -8065,109 +10877,69 @@ def test_create_index_rest(request_type): request_init = { "parent": "projects/sample1/databases/sample2/collectionGroups/sample3" } - request_init["index"] = { - "name": "name_value", - "query_scope": 1, - "api_scope": 1, - "fields": [ - { - "field_path": "field_path_value", - "order": 1, - "array_config": 1, - "vector_config": {"dimension": 966, "flat": {}}, - } - ], - "state": 1, - } - # The version of a generated dependency at test runtime may differ from the version used during generation. - # Delete any fields which are not present in the current runtime dependency - # See https://github.com/googleapis/gapic-generator-python/issues/1748 - - # Determine if the message type is proto-plus or protobuf - test_field = firestore_admin.CreateIndexRequest.meta.fields["index"] - - def get_message_fields(field): - # Given a field which is a message (composite type), return a list with - # all the fields of the message. - # If the field is not a composite type, return an empty list. - message_fields = [] - - if hasattr(field, "message") and field.message: - is_field_type_proto_plus_type = not hasattr(field.message, "DESCRIPTOR") - - if is_field_type_proto_plus_type: - message_fields = field.message.meta.fields.values() - # Add `# pragma: NO COVER` because there may not be any `*_pb2` field types - else: # pragma: NO COVER - message_fields = field.message.DESCRIPTOR.fields - return message_fields - - runtime_nested_fields = [ - (field.name, nested_field.name) - for field in get_message_fields(test_field) - for nested_field in get_message_fields(field) - ] - - subfields_not_in_runtime = [] - - # For each item in the sample request, create a list of sub fields which are not present at runtime - # Add `# pragma: NO COVER` because this test code will not run if all subfields are present at runtime - for field, value in request_init["index"].items(): # pragma: NO COVER - result = None - is_repeated = False - # For repeated fields - if isinstance(value, list) and len(value): - is_repeated = True - result = value[0] - # For fields where the type is another message - if isinstance(value, dict): - result = value - - if result and hasattr(result, "keys"): - for subfield in result.keys(): - if (field, subfield) not in runtime_nested_fields: - subfields_not_in_runtime.append( - { - "field": field, - "subfield": subfield, - "is_repeated": is_repeated, - } - ) - - # Remove fields from the sample request which are not present in the runtime version of the dependency - # Add `# pragma: NO COVER` because this test code will not run if all subfields are present at runtime - for subfield_to_delete in subfields_not_in_runtime: # pragma: NO COVER - field = subfield_to_delete.get("field") - field_repeated = subfield_to_delete.get("is_repeated") - subfield = subfield_to_delete.get("subfield") - if subfield: - if field_repeated: - for i in range(0, len(request_init["index"][field])): - del request_init["index"][field][i][subfield] - else: - del request_init["index"][field][subfield] request = request_type(**request_init) # Mock the http request call within the method and 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") + return_value = firestore_admin.ListIndexesResponse( + next_page_token="next_page_token_value", + ) # Wrap the value into a proper Response obj response_value = Response() response_value.status_code = 200 + # Convert return value to protobuf type + return_value = firestore_admin.ListIndexesResponse.pb(return_value) 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_index(request) + response = client.list_indexes(request) # Establish that the response is the type that we expect. - assert response.operation.name == "operations/spam" + assert isinstance(response, pagers.ListIndexesPager) + assert response.next_page_token == "next_page_token_value" -def test_create_index_rest_required_fields( - request_type=firestore_admin.CreateIndexRequest, +def test_list_indexes_rest_use_cached_wrapped_rpc(): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method.wrap_method") as wrapper_fn: + client = FirestoreAdminClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert client._transport.list_indexes in client._transport._wrapped_methods + + # Replace cached wrapped function with mock + mock_rpc = mock.Mock() + mock_rpc.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) + client._transport._wrapped_methods[client._transport.list_indexes] = mock_rpc + + request = {} + client.list_indexes(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + client.list_indexes(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 + + +def test_list_indexes_rest_required_fields( + request_type=firestore_admin.ListIndexesRequest, ): transport_class = transports.FirestoreAdminRestTransport @@ -8183,7 +10955,7 @@ def test_create_index_rest_required_fields( unset_fields = transport_class( credentials=ga_credentials.AnonymousCredentials() - ).create_index._get_unset_required_fields(jsonified_request) + ).list_indexes._get_unset_required_fields(jsonified_request) jsonified_request.update(unset_fields) # verify required fields with default values are now present @@ -8192,7 +10964,15 @@ def test_create_index_rest_required_fields( unset_fields = transport_class( credentials=ga_credentials.AnonymousCredentials() - ).create_index._get_unset_required_fields(jsonified_request) + ).list_indexes._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 @@ -8206,7 +10986,7 @@ def test_create_index_rest_required_fields( request = request_type(**request_init) # Designate an appropriate value for the returned response. - return_value = operations_pb2.Operation(name="operations/spam") + return_value = firestore_admin.ListIndexesResponse() # 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 @@ -8218,45 +10998,48 @@ def test_create_index_rest_required_fields( pb_request = request_type.pb(request) transcode_result = { "uri": "v1/sample_method", - "method": "post", + "method": "get", "query_params": pb_request, } - transcode_result["body"] = pb_request transcode.return_value = transcode_result response_value = Response() response_value.status_code = 200 + + # Convert return value to protobuf type + return_value = firestore_admin.ListIndexesResponse.pb(return_value) 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_index(request) + response = client.list_indexes(request) expected_params = [("$alt", "json;enum-encoding=int")] actual_params = req.call_args.kwargs["params"] assert expected_params == actual_params -def test_create_index_rest_unset_required_fields(): +def test_list_indexes_rest_unset_required_fields(): transport = transports.FirestoreAdminRestTransport( credentials=ga_credentials.AnonymousCredentials ) - unset_fields = transport.create_index._get_unset_required_fields({}) + unset_fields = transport.list_indexes._get_unset_required_fields({}) assert set(unset_fields) == ( - set(()) - & set( + set( ( - "parent", - "index", + "filter", + "pageSize", + "pageToken", ) ) + & set(("parent",)) ) @pytest.mark.parametrize("null_interceptor", [True, False]) -def test_create_index_rest_interceptors(null_interceptor): +def test_list_indexes_rest_interceptors(null_interceptor): transport = transports.FirestoreAdminRestTransport( credentials=ga_credentials.AnonymousCredentials(), interceptor=None @@ -8269,16 +11052,14 @@ def test_create_index_rest_interceptors(null_interceptor): ) as req, mock.patch.object( path_template, "transcode" ) as transcode, mock.patch.object( - operation.Operation, "_set_result_from_operation" - ), mock.patch.object( - transports.FirestoreAdminRestInterceptor, "post_create_index" + transports.FirestoreAdminRestInterceptor, "post_list_indexes" ) as post, mock.patch.object( - transports.FirestoreAdminRestInterceptor, "pre_create_index" + transports.FirestoreAdminRestInterceptor, "pre_list_indexes" ) as pre: pre.assert_not_called() post.assert_not_called() - pb_message = firestore_admin.CreateIndexRequest.pb( - firestore_admin.CreateIndexRequest() + pb_message = firestore_admin.ListIndexesRequest.pb( + firestore_admin.ListIndexesRequest() ) transcode.return_value = { "method": "post", @@ -8290,19 +11071,19 @@ def test_create_index_rest_interceptors(null_interceptor): 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() + req.return_value._content = firestore_admin.ListIndexesResponse.to_json( + firestore_admin.ListIndexesResponse() ) - request = firestore_admin.CreateIndexRequest() + request = firestore_admin.ListIndexesRequest() metadata = [ ("key", "val"), ("cephalopod", "squid"), ] pre.return_value = request, metadata - post.return_value = operations_pb2.Operation() + post.return_value = firestore_admin.ListIndexesResponse() - client.create_index( + client.list_indexes( request, metadata=[ ("key", "val"), @@ -8314,8 +11095,8 @@ def test_create_index_rest_interceptors(null_interceptor): post.assert_called_once() -def test_create_index_rest_bad_request( - transport: str = "rest", request_type=firestore_admin.CreateIndexRequest +def test_list_indexes_rest_bad_request( + transport: str = "rest", request_type=firestore_admin.ListIndexesRequest ): client = FirestoreAdminClient( credentials=ga_credentials.AnonymousCredentials(), @@ -8337,10 +11118,10 @@ def test_create_index_rest_bad_request( response_value.status_code = 400 response_value.request = Request() req.return_value = response_value - client.create_index(request) + client.list_indexes(request) -def test_create_index_rest_flattened(): +def test_list_indexes_rest_flattened(): client = FirestoreAdminClient( credentials=ga_credentials.AnonymousCredentials(), transport="rest", @@ -8349,7 +11130,7 @@ def test_create_index_rest_flattened(): # Mock the http request call within the method and 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") + return_value = firestore_admin.ListIndexesResponse() # get arguments that satisfy an http rule for this method sample_request = { @@ -8359,18 +11140,19 @@ def test_create_index_rest_flattened(): # get truthy value for each flattened field mock_args = dict( parent="parent_value", - index=gfa_index.Index(name="name_value"), ) mock_args.update(sample_request) # Wrap the value into a proper Response obj response_value = Response() response_value.status_code = 200 + # Convert return value to protobuf type + return_value = firestore_admin.ListIndexesResponse.pb(return_value) json_return_value = json_format.MessageToJson(return_value) response_value._content = json_return_value.encode("UTF-8") req.return_value = response_value - client.create_index(**mock_args) + client.list_indexes(**mock_args) # Establish that the underlying call was made with the expected # request object values. @@ -8383,36 +11165,94 @@ def test_create_index_rest_flattened(): ) -def test_create_index_rest_flattened_error(transport: str = "rest"): - client = FirestoreAdminClient( - credentials=ga_credentials.AnonymousCredentials(), - transport=transport, - ) +def test_list_indexes_rest_flattened_error(transport: str = "rest"): + client = FirestoreAdminClient( + 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_indexes( + firestore_admin.ListIndexesRequest(), + parent="parent_value", + ) + + +def test_list_indexes_rest_pager(transport: str = "rest"): + client = FirestoreAdminClient( + 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 = ( + firestore_admin.ListIndexesResponse( + indexes=[ + index.Index(), + index.Index(), + index.Index(), + ], + next_page_token="abc", + ), + firestore_admin.ListIndexesResponse( + indexes=[], + next_page_token="def", + ), + firestore_admin.ListIndexesResponse( + indexes=[ + index.Index(), + ], + next_page_token="ghi", + ), + firestore_admin.ListIndexesResponse( + indexes=[ + index.Index(), + index.Index(), + ], + ), + ) + # Two responses for two calls + response = response + response + + # Wrap the values into proper Response objs + response = tuple( + firestore_admin.ListIndexesResponse.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/databases/sample2/collectionGroups/sample3" + } - # Attempting to call a method with both a request object and flattened - # fields is an error. - with pytest.raises(ValueError): - client.create_index( - firestore_admin.CreateIndexRequest(), - parent="parent_value", - index=gfa_index.Index(name="name_value"), - ) + pager = client.list_indexes(request=sample_request) + results = list(pager) + assert len(results) == 6 + assert all(isinstance(i, index.Index) for i in results) -def test_create_index_rest_error(): - client = FirestoreAdminClient( - credentials=ga_credentials.AnonymousCredentials(), transport="rest" - ) + pages = list(client.list_indexes(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", [ - firestore_admin.ListIndexesRequest, + firestore_admin.GetIndexRequest, dict, ], ) -def test_list_indexes_rest(request_type): +def test_get_index_rest(request_type): client = FirestoreAdminClient( credentials=ga_credentials.AnonymousCredentials(), transport="rest", @@ -8420,40 +11260,80 @@ def test_list_indexes_rest(request_type): # send a request that will satisfy transcoding request_init = { - "parent": "projects/sample1/databases/sample2/collectionGroups/sample3" + "name": "projects/sample1/databases/sample2/collectionGroups/sample3/indexes/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 = firestore_admin.ListIndexesResponse( - next_page_token="next_page_token_value", + return_value = index.Index( + name="name_value", + query_scope=index.Index.QueryScope.COLLECTION, + api_scope=index.Index.ApiScope.DATASTORE_MODE_API, + state=index.Index.State.CREATING, ) # Wrap the value into a proper Response obj response_value = Response() response_value.status_code = 200 # Convert return value to protobuf type - return_value = firestore_admin.ListIndexesResponse.pb(return_value) + return_value = index.Index.pb(return_value) 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_indexes(request) + response = client.get_index(request) # Establish that the response is the type that we expect. - assert isinstance(response, pagers.ListIndexesPager) - assert response.next_page_token == "next_page_token_value" + assert isinstance(response, index.Index) + assert response.name == "name_value" + assert response.query_scope == index.Index.QueryScope.COLLECTION + assert response.api_scope == index.Index.ApiScope.DATASTORE_MODE_API + assert response.state == index.Index.State.CREATING -def test_list_indexes_rest_required_fields( - request_type=firestore_admin.ListIndexesRequest, -): +def test_get_index_rest_use_cached_wrapped_rpc(): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method.wrap_method") as wrapper_fn: + client = FirestoreAdminClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert client._transport.get_index in client._transport._wrapped_methods + + # Replace cached wrapped function with mock + mock_rpc = mock.Mock() + mock_rpc.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) + client._transport._wrapped_methods[client._transport.get_index] = mock_rpc + + request = {} + client.get_index(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + client.get_index(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 + + +def test_get_index_rest_required_fields(request_type=firestore_admin.GetIndexRequest): transport_class = transports.FirestoreAdminRestTransport request_init = {} - request_init["parent"] = "" + request_init["name"] = "" request = request_type(**request_init) pb_request = request_type.pb(request) jsonified_request = json.loads( @@ -8464,29 +11344,21 @@ def test_list_indexes_rest_required_fields( unset_fields = transport_class( credentials=ga_credentials.AnonymousCredentials() - ).list_indexes._get_unset_required_fields(jsonified_request) + ).get_index._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["name"] = "name_value" unset_fields = transport_class( credentials=ga_credentials.AnonymousCredentials() - ).list_indexes._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", - ) - ) + ).get_index._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 "name" in jsonified_request + assert jsonified_request["name"] == "name_value" client = FirestoreAdminClient( credentials=ga_credentials.AnonymousCredentials(), @@ -8495,7 +11367,7 @@ def test_list_indexes_rest_required_fields( request = request_type(**request_init) # Designate an appropriate value for the returned response. - return_value = firestore_admin.ListIndexesResponse() + return_value = index.Index() # 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 @@ -8516,39 +11388,30 @@ def test_list_indexes_rest_required_fields( response_value.status_code = 200 # Convert return value to protobuf type - return_value = firestore_admin.ListIndexesResponse.pb(return_value) + return_value = index.Index.pb(return_value) 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_indexes(request) + response = client.get_index(request) expected_params = [("$alt", "json;enum-encoding=int")] actual_params = req.call_args.kwargs["params"] assert expected_params == actual_params -def test_list_indexes_rest_unset_required_fields(): +def test_get_index_rest_unset_required_fields(): transport = transports.FirestoreAdminRestTransport( credentials=ga_credentials.AnonymousCredentials ) - unset_fields = transport.list_indexes._get_unset_required_fields({}) - assert set(unset_fields) == ( - set( - ( - "filter", - "pageSize", - "pageToken", - ) - ) - & set(("parent",)) - ) + unset_fields = transport.get_index._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) @pytest.mark.parametrize("null_interceptor", [True, False]) -def test_list_indexes_rest_interceptors(null_interceptor): +def test_get_index_rest_interceptors(null_interceptor): transport = transports.FirestoreAdminRestTransport( credentials=ga_credentials.AnonymousCredentials(), interceptor=None @@ -8561,14 +11424,14 @@ def test_list_indexes_rest_interceptors(null_interceptor): ) as req, mock.patch.object( path_template, "transcode" ) as transcode, mock.patch.object( - transports.FirestoreAdminRestInterceptor, "post_list_indexes" + transports.FirestoreAdminRestInterceptor, "post_get_index" ) as post, mock.patch.object( - transports.FirestoreAdminRestInterceptor, "pre_list_indexes" + transports.FirestoreAdminRestInterceptor, "pre_get_index" ) as pre: pre.assert_not_called() post.assert_not_called() - pb_message = firestore_admin.ListIndexesRequest.pb( - firestore_admin.ListIndexesRequest() + pb_message = firestore_admin.GetIndexRequest.pb( + firestore_admin.GetIndexRequest() ) transcode.return_value = { "method": "post", @@ -8580,19 +11443,17 @@ def test_list_indexes_rest_interceptors(null_interceptor): req.return_value = Response() req.return_value.status_code = 200 req.return_value.request = PreparedRequest() - req.return_value._content = firestore_admin.ListIndexesResponse.to_json( - firestore_admin.ListIndexesResponse() - ) + req.return_value._content = index.Index.to_json(index.Index()) - request = firestore_admin.ListIndexesRequest() + request = firestore_admin.GetIndexRequest() metadata = [ ("key", "val"), ("cephalopod", "squid"), ] pre.return_value = request, metadata - post.return_value = firestore_admin.ListIndexesResponse() + post.return_value = index.Index() - client.list_indexes( + client.get_index( request, metadata=[ ("key", "val"), @@ -8604,8 +11465,8 @@ def test_list_indexes_rest_interceptors(null_interceptor): post.assert_called_once() -def test_list_indexes_rest_bad_request( - transport: str = "rest", request_type=firestore_admin.ListIndexesRequest +def test_get_index_rest_bad_request( + transport: str = "rest", request_type=firestore_admin.GetIndexRequest ): client = FirestoreAdminClient( credentials=ga_credentials.AnonymousCredentials(), @@ -8614,7 +11475,7 @@ def test_list_indexes_rest_bad_request( # send a request that will satisfy transcoding request_init = { - "parent": "projects/sample1/databases/sample2/collectionGroups/sample3" + "name": "projects/sample1/databases/sample2/collectionGroups/sample3/indexes/sample4" } request = request_type(**request_init) @@ -8627,10 +11488,10 @@ def test_list_indexes_rest_bad_request( response_value.status_code = 400 response_value.request = Request() req.return_value = response_value - client.list_indexes(request) + client.get_index(request) -def test_list_indexes_rest_flattened(): +def test_get_index_rest_flattened(): client = FirestoreAdminClient( credentials=ga_credentials.AnonymousCredentials(), transport="rest", @@ -8639,16 +11500,16 @@ def test_list_indexes_rest_flattened(): # Mock the http request call within the method and fake a response. with mock.patch.object(type(client.transport._session), "request") as req: # Designate an appropriate value for the returned response. - return_value = firestore_admin.ListIndexesResponse() + return_value = index.Index() # get arguments that satisfy an http rule for this method sample_request = { - "parent": "projects/sample1/databases/sample2/collectionGroups/sample3" + "name": "projects/sample1/databases/sample2/collectionGroups/sample3/indexes/sample4" } # get truthy value for each flattened field mock_args = dict( - parent="parent_value", + name="name_value", ) mock_args.update(sample_request) @@ -8656,25 +11517,25 @@ def test_list_indexes_rest_flattened(): response_value = Response() response_value.status_code = 200 # Convert return value to protobuf type - return_value = firestore_admin.ListIndexesResponse.pb(return_value) + return_value = index.Index.pb(return_value) json_return_value = json_format.MessageToJson(return_value) response_value._content = json_return_value.encode("UTF-8") req.return_value = response_value - client.list_indexes(**mock_args) + client.get_index(**mock_args) # Establish that the underlying call was made with the expected # request object values. assert len(req.mock_calls) == 1 _, args, _ = req.mock_calls[0] assert path_template.validate( - "%s/v1/{parent=projects/*/databases/*/collectionGroups/*}/indexes" + "%s/v1/{name=projects/*/databases/*/collectionGroups/*/indexes/*}" % client.transport._host, args[1], ) -def test_list_indexes_rest_flattened_error(transport: str = "rest"): +def test_get_index_rest_flattened_error(transport: str = "rest"): client = FirestoreAdminClient( credentials=ga_credentials.AnonymousCredentials(), transport=transport, @@ -8683,85 +11544,26 @@ def test_list_indexes_rest_flattened_error(transport: str = "rest"): # Attempting to call a method with both a request object and flattened # fields is an error. with pytest.raises(ValueError): - client.list_indexes( - firestore_admin.ListIndexesRequest(), - parent="parent_value", + client.get_index( + firestore_admin.GetIndexRequest(), + name="name_value", ) -def test_list_indexes_rest_pager(transport: str = "rest"): +def test_get_index_rest_error(): client = FirestoreAdminClient( - credentials=ga_credentials.AnonymousCredentials(), - transport=transport, + credentials=ga_credentials.AnonymousCredentials(), transport="rest" ) - # 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 = ( - firestore_admin.ListIndexesResponse( - indexes=[ - index.Index(), - index.Index(), - index.Index(), - ], - next_page_token="abc", - ), - firestore_admin.ListIndexesResponse( - indexes=[], - next_page_token="def", - ), - firestore_admin.ListIndexesResponse( - indexes=[ - index.Index(), - ], - next_page_token="ghi", - ), - firestore_admin.ListIndexesResponse( - indexes=[ - index.Index(), - index.Index(), - ], - ), - ) - # Two responses for two calls - response = response + response - - # Wrap the values into proper Response objs - response = tuple( - firestore_admin.ListIndexesResponse.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/databases/sample2/collectionGroups/sample3" - } - - pager = client.list_indexes(request=sample_request) - - results = list(pager) - assert len(results) == 6 - assert all(isinstance(i, index.Index) for i in results) - - pages = list(client.list_indexes(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", [ - firestore_admin.GetIndexRequest, + firestore_admin.DeleteIndexRequest, dict, ], ) -def test_get_index_rest(request_type): +def test_delete_index_rest(request_type): client = FirestoreAdminClient( credentials=ga_credentials.AnonymousCredentials(), transport="rest", @@ -8776,33 +11578,60 @@ def test_get_index_rest(request_type): # Mock the http request call within the method and fake a response. with mock.patch.object(type(client.transport._session), "request") as req: # Designate an appropriate value for the returned response. - return_value = index.Index( - name="name_value", - query_scope=index.Index.QueryScope.COLLECTION, - api_scope=index.Index.ApiScope.DATASTORE_MODE_API, - state=index.Index.State.CREATING, - ) + return_value = None # Wrap the value into a proper Response obj response_value = Response() response_value.status_code = 200 - # Convert return value to protobuf type - return_value = index.Index.pb(return_value) - json_return_value = json_format.MessageToJson(return_value) + json_return_value = "" + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + response = client.delete_index(request) + + # Establish that the response is the type that we expect. + assert response is None + + +def test_delete_index_rest_use_cached_wrapped_rpc(): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method.wrap_method") as wrapper_fn: + client = FirestoreAdminClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert client._transport.delete_index in client._transport._wrapped_methods - response_value._content = json_return_value.encode("UTF-8") - req.return_value = response_value - response = client.get_index(request) + # Replace cached wrapped function with mock + mock_rpc = mock.Mock() + mock_rpc.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) + client._transport._wrapped_methods[client._transport.delete_index] = mock_rpc - # Establish that the response is the type that we expect. - assert isinstance(response, index.Index) - assert response.name == "name_value" - assert response.query_scope == index.Index.QueryScope.COLLECTION - assert response.api_scope == index.Index.ApiScope.DATASTORE_MODE_API - assert response.state == index.Index.State.CREATING + request = {} + client.delete_index(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + client.delete_index(request) + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 -def test_get_index_rest_required_fields(request_type=firestore_admin.GetIndexRequest): + +def test_delete_index_rest_required_fields( + request_type=firestore_admin.DeleteIndexRequest, +): transport_class = transports.FirestoreAdminRestTransport request_init = {} @@ -8817,7 +11646,7 @@ def test_get_index_rest_required_fields(request_type=firestore_admin.GetIndexReq unset_fields = transport_class( credentials=ga_credentials.AnonymousCredentials() - ).get_index._get_unset_required_fields(jsonified_request) + ).delete_index._get_unset_required_fields(jsonified_request) jsonified_request.update(unset_fields) # verify required fields with default values are now present @@ -8826,7 +11655,7 @@ def test_get_index_rest_required_fields(request_type=firestore_admin.GetIndexReq unset_fields = transport_class( credentials=ga_credentials.AnonymousCredentials() - ).get_index._get_unset_required_fields(jsonified_request) + ).delete_index._get_unset_required_fields(jsonified_request) jsonified_request.update(unset_fields) # verify required fields with non-default values are left alone @@ -8840,7 +11669,7 @@ def test_get_index_rest_required_fields(request_type=firestore_admin.GetIndexReq request = request_type(**request_init) # Designate an appropriate value for the returned response. - return_value = index.Index() + 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 @@ -8852,39 +11681,36 @@ def test_get_index_rest_required_fields(request_type=firestore_admin.GetIndexReq pb_request = request_type.pb(request) transcode_result = { "uri": "v1/sample_method", - "method": "get", + "method": "delete", "query_params": pb_request, } transcode.return_value = transcode_result response_value = Response() response_value.status_code = 200 - - # Convert return value to protobuf type - return_value = index.Index.pb(return_value) - json_return_value = json_format.MessageToJson(return_value) + json_return_value = "" response_value._content = json_return_value.encode("UTF-8") req.return_value = response_value - response = client.get_index(request) + response = client.delete_index(request) expected_params = [("$alt", "json;enum-encoding=int")] actual_params = req.call_args.kwargs["params"] assert expected_params == actual_params -def test_get_index_rest_unset_required_fields(): +def test_delete_index_rest_unset_required_fields(): transport = transports.FirestoreAdminRestTransport( credentials=ga_credentials.AnonymousCredentials ) - unset_fields = transport.get_index._get_unset_required_fields({}) + unset_fields = transport.delete_index._get_unset_required_fields({}) assert set(unset_fields) == (set(()) & set(("name",))) @pytest.mark.parametrize("null_interceptor", [True, False]) -def test_get_index_rest_interceptors(null_interceptor): +def test_delete_index_rest_interceptors(null_interceptor): transport = transports.FirestoreAdminRestTransport( credentials=ga_credentials.AnonymousCredentials(), interceptor=None @@ -8897,14 +11723,11 @@ def test_get_index_rest_interceptors(null_interceptor): ) as req, mock.patch.object( path_template, "transcode" ) as transcode, mock.patch.object( - transports.FirestoreAdminRestInterceptor, "post_get_index" - ) as post, mock.patch.object( - transports.FirestoreAdminRestInterceptor, "pre_get_index" + transports.FirestoreAdminRestInterceptor, "pre_delete_index" ) as pre: pre.assert_not_called() - post.assert_not_called() - pb_message = firestore_admin.GetIndexRequest.pb( - firestore_admin.GetIndexRequest() + pb_message = firestore_admin.DeleteIndexRequest.pb( + firestore_admin.DeleteIndexRequest() ) transcode.return_value = { "method": "post", @@ -8916,17 +11739,15 @@ def test_get_index_rest_interceptors(null_interceptor): req.return_value = Response() req.return_value.status_code = 200 req.return_value.request = PreparedRequest() - req.return_value._content = index.Index.to_json(index.Index()) - request = firestore_admin.GetIndexRequest() + request = firestore_admin.DeleteIndexRequest() metadata = [ ("key", "val"), ("cephalopod", "squid"), ] pre.return_value = request, metadata - post.return_value = index.Index() - client.get_index( + client.delete_index( request, metadata=[ ("key", "val"), @@ -8935,11 +11756,10 @@ def test_get_index_rest_interceptors(null_interceptor): ) pre.assert_called_once() - post.assert_called_once() -def test_get_index_rest_bad_request( - transport: str = "rest", request_type=firestore_admin.GetIndexRequest +def test_delete_index_rest_bad_request( + transport: str = "rest", request_type=firestore_admin.DeleteIndexRequest ): client = FirestoreAdminClient( credentials=ga_credentials.AnonymousCredentials(), @@ -8961,10 +11781,10 @@ def test_get_index_rest_bad_request( response_value.status_code = 400 response_value.request = Request() req.return_value = response_value - client.get_index(request) + client.delete_index(request) -def test_get_index_rest_flattened(): +def test_delete_index_rest_flattened(): client = FirestoreAdminClient( credentials=ga_credentials.AnonymousCredentials(), transport="rest", @@ -8973,7 +11793,7 @@ def test_get_index_rest_flattened(): # Mock the http request call within the method and fake a response. with mock.patch.object(type(client.transport._session), "request") as req: # Designate an appropriate value for the returned response. - return_value = index.Index() + return_value = None # get arguments that satisfy an http rule for this method sample_request = { @@ -8989,13 +11809,11 @@ def test_get_index_rest_flattened(): # Wrap the value into a proper Response obj response_value = Response() response_value.status_code = 200 - # Convert return value to protobuf type - return_value = index.Index.pb(return_value) - json_return_value = json_format.MessageToJson(return_value) + json_return_value = "" response_value._content = json_return_value.encode("UTF-8") req.return_value = response_value - client.get_index(**mock_args) + client.delete_index(**mock_args) # Establish that the underlying call was made with the expected # request object values. @@ -9008,7 +11826,7 @@ def test_get_index_rest_flattened(): ) -def test_get_index_rest_flattened_error(transport: str = "rest"): +def test_delete_index_rest_flattened_error(transport: str = "rest"): client = FirestoreAdminClient( credentials=ga_credentials.AnonymousCredentials(), transport=transport, @@ -9017,13 +11835,13 @@ def test_get_index_rest_flattened_error(transport: str = "rest"): # Attempting to call a method with both a request object and flattened # fields is an error. with pytest.raises(ValueError): - client.get_index( - firestore_admin.GetIndexRequest(), + client.delete_index( + firestore_admin.DeleteIndexRequest(), name="name_value", ) -def test_get_index_rest_error(): +def test_delete_index_rest_error(): client = FirestoreAdminClient( credentials=ga_credentials.AnonymousCredentials(), transport="rest" ) @@ -9032,11 +11850,11 @@ def test_get_index_rest_error(): @pytest.mark.parametrize( "request_type", [ - firestore_admin.DeleteIndexRequest, + firestore_admin.GetFieldRequest, dict, ], ) -def test_delete_index_rest(request_type): +def test_get_field_rest(request_type): client = FirestoreAdminClient( credentials=ga_credentials.AnonymousCredentials(), transport="rest", @@ -9044,31 +11862,70 @@ def test_delete_index_rest(request_type): # send a request that will satisfy transcoding request_init = { - "name": "projects/sample1/databases/sample2/collectionGroups/sample3/indexes/sample4" + "name": "projects/sample1/databases/sample2/collectionGroups/sample3/fields/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 + return_value = field.Field( + name="name_value", + ) # Wrap the value into a proper Response obj response_value = Response() response_value.status_code = 200 - json_return_value = "" + # Convert return value to protobuf type + return_value = field.Field.pb(return_value) + json_return_value = json_format.MessageToJson(return_value) response_value._content = json_return_value.encode("UTF-8") req.return_value = response_value - response = client.delete_index(request) + response = client.get_field(request) # Establish that the response is the type that we expect. - assert response is None + assert isinstance(response, field.Field) + assert response.name == "name_value" -def test_delete_index_rest_required_fields( - request_type=firestore_admin.DeleteIndexRequest, -): +def test_get_field_rest_use_cached_wrapped_rpc(): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method.wrap_method") as wrapper_fn: + client = FirestoreAdminClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert client._transport.get_field in client._transport._wrapped_methods + + # Replace cached wrapped function with mock + mock_rpc = mock.Mock() + mock_rpc.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) + client._transport._wrapped_methods[client._transport.get_field] = mock_rpc + + request = {} + client.get_field(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + client.get_field(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 + + +def test_get_field_rest_required_fields(request_type=firestore_admin.GetFieldRequest): transport_class = transports.FirestoreAdminRestTransport request_init = {} @@ -9083,7 +11940,7 @@ def test_delete_index_rest_required_fields( unset_fields = transport_class( credentials=ga_credentials.AnonymousCredentials() - ).delete_index._get_unset_required_fields(jsonified_request) + ).get_field._get_unset_required_fields(jsonified_request) jsonified_request.update(unset_fields) # verify required fields with default values are now present @@ -9092,7 +11949,7 @@ def test_delete_index_rest_required_fields( unset_fields = transport_class( credentials=ga_credentials.AnonymousCredentials() - ).delete_index._get_unset_required_fields(jsonified_request) + ).get_field._get_unset_required_fields(jsonified_request) jsonified_request.update(unset_fields) # verify required fields with non-default values are left alone @@ -9106,7 +11963,7 @@ def test_delete_index_rest_required_fields( request = request_type(**request_init) # Designate an appropriate value for the returned response. - return_value = None + return_value = field.Field() # 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 @@ -9118,36 +11975,39 @@ def test_delete_index_rest_required_fields( pb_request = request_type.pb(request) transcode_result = { "uri": "v1/sample_method", - "method": "delete", + "method": "get", "query_params": pb_request, } transcode.return_value = transcode_result response_value = Response() response_value.status_code = 200 - json_return_value = "" + + # Convert return value to protobuf type + return_value = field.Field.pb(return_value) + json_return_value = json_format.MessageToJson(return_value) response_value._content = json_return_value.encode("UTF-8") req.return_value = response_value - response = client.delete_index(request) + response = client.get_field(request) expected_params = [("$alt", "json;enum-encoding=int")] actual_params = req.call_args.kwargs["params"] assert expected_params == actual_params -def test_delete_index_rest_unset_required_fields(): +def test_get_field_rest_unset_required_fields(): transport = transports.FirestoreAdminRestTransport( credentials=ga_credentials.AnonymousCredentials ) - unset_fields = transport.delete_index._get_unset_required_fields({}) + unset_fields = transport.get_field._get_unset_required_fields({}) assert set(unset_fields) == (set(()) & set(("name",))) @pytest.mark.parametrize("null_interceptor", [True, False]) -def test_delete_index_rest_interceptors(null_interceptor): +def test_get_field_rest_interceptors(null_interceptor): transport = transports.FirestoreAdminRestTransport( credentials=ga_credentials.AnonymousCredentials(), interceptor=None @@ -9160,11 +12020,14 @@ def test_delete_index_rest_interceptors(null_interceptor): ) as req, mock.patch.object( path_template, "transcode" ) as transcode, mock.patch.object( - transports.FirestoreAdminRestInterceptor, "pre_delete_index" + transports.FirestoreAdminRestInterceptor, "post_get_field" + ) as post, mock.patch.object( + transports.FirestoreAdminRestInterceptor, "pre_get_field" ) as pre: pre.assert_not_called() - pb_message = firestore_admin.DeleteIndexRequest.pb( - firestore_admin.DeleteIndexRequest() + post.assert_not_called() + pb_message = firestore_admin.GetFieldRequest.pb( + firestore_admin.GetFieldRequest() ) transcode.return_value = { "method": "post", @@ -9176,15 +12039,17 @@ def test_delete_index_rest_interceptors(null_interceptor): req.return_value = Response() req.return_value.status_code = 200 req.return_value.request = PreparedRequest() + req.return_value._content = field.Field.to_json(field.Field()) - request = firestore_admin.DeleteIndexRequest() + request = firestore_admin.GetFieldRequest() metadata = [ ("key", "val"), ("cephalopod", "squid"), ] pre.return_value = request, metadata + post.return_value = field.Field() - client.delete_index( + client.get_field( request, metadata=[ ("key", "val"), @@ -9193,10 +12058,11 @@ def test_delete_index_rest_interceptors(null_interceptor): ) pre.assert_called_once() + post.assert_called_once() -def test_delete_index_rest_bad_request( - transport: str = "rest", request_type=firestore_admin.DeleteIndexRequest +def test_get_field_rest_bad_request( + transport: str = "rest", request_type=firestore_admin.GetFieldRequest ): client = FirestoreAdminClient( credentials=ga_credentials.AnonymousCredentials(), @@ -9205,7 +12071,7 @@ def test_delete_index_rest_bad_request( # send a request that will satisfy transcoding request_init = { - "name": "projects/sample1/databases/sample2/collectionGroups/sample3/indexes/sample4" + "name": "projects/sample1/databases/sample2/collectionGroups/sample3/fields/sample4" } request = request_type(**request_init) @@ -9218,10 +12084,10 @@ def test_delete_index_rest_bad_request( response_value.status_code = 400 response_value.request = Request() req.return_value = response_value - client.delete_index(request) + client.get_field(request) -def test_delete_index_rest_flattened(): +def test_get_field_rest_flattened(): client = FirestoreAdminClient( credentials=ga_credentials.AnonymousCredentials(), transport="rest", @@ -9230,11 +12096,11 @@ def test_delete_index_rest_flattened(): # Mock the http request call within the method and 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 + return_value = field.Field() # get arguments that satisfy an http rule for this method sample_request = { - "name": "projects/sample1/databases/sample2/collectionGroups/sample3/indexes/sample4" + "name": "projects/sample1/databases/sample2/collectionGroups/sample3/fields/sample4" } # get truthy value for each flattened field @@ -9246,24 +12112,26 @@ def test_delete_index_rest_flattened(): # Wrap the value into a proper Response obj response_value = Response() response_value.status_code = 200 - json_return_value = "" + # Convert return value to protobuf type + return_value = field.Field.pb(return_value) + json_return_value = json_format.MessageToJson(return_value) response_value._content = json_return_value.encode("UTF-8") req.return_value = response_value - client.delete_index(**mock_args) + client.get_field(**mock_args) # Establish that the underlying call was made with the expected # request object values. assert len(req.mock_calls) == 1 _, args, _ = req.mock_calls[0] assert path_template.validate( - "%s/v1/{name=projects/*/databases/*/collectionGroups/*/indexes/*}" + "%s/v1/{name=projects/*/databases/*/collectionGroups/*/fields/*}" % client.transport._host, args[1], ) -def test_delete_index_rest_flattened_error(transport: str = "rest"): +def test_get_field_rest_flattened_error(transport: str = "rest"): client = FirestoreAdminClient( credentials=ga_credentials.AnonymousCredentials(), transport=transport, @@ -9272,13 +12140,13 @@ def test_delete_index_rest_flattened_error(transport: str = "rest"): # Attempting to call a method with both a request object and flattened # fields is an error. with pytest.raises(ValueError): - client.delete_index( - firestore_admin.DeleteIndexRequest(), + client.get_field( + firestore_admin.GetFieldRequest(), name="name_value", ) -def test_delete_index_rest_error(): +def test_get_field_rest_error(): client = FirestoreAdminClient( credentials=ga_credentials.AnonymousCredentials(), transport="rest" ) @@ -9287,50 +12155,180 @@ def test_delete_index_rest_error(): @pytest.mark.parametrize( "request_type", [ - firestore_admin.GetFieldRequest, + firestore_admin.UpdateFieldRequest, dict, ], ) -def test_get_field_rest(request_type): +def test_update_field_rest(request_type): client = FirestoreAdminClient( credentials=ga_credentials.AnonymousCredentials(), transport="rest", ) - # send a request that will satisfy transcoding - request_init = { - "name": "projects/sample1/databases/sample2/collectionGroups/sample3/fields/sample4" - } + # send a request that will satisfy transcoding + request_init = { + "field": { + "name": "projects/sample1/databases/sample2/collectionGroups/sample3/fields/sample4" + } + } + request_init["field"] = { + "name": "projects/sample1/databases/sample2/collectionGroups/sample3/fields/sample4", + "index_config": { + "indexes": [ + { + "name": "name_value", + "query_scope": 1, + "api_scope": 1, + "fields": [ + { + "field_path": "field_path_value", + "order": 1, + "array_config": 1, + "vector_config": {"dimension": 966, "flat": {}}, + } + ], + "state": 1, + } + ], + "uses_ancestor_config": True, + "ancestor_field": "ancestor_field_value", + "reverting": True, + }, + "ttl_config": {"state": 1}, + } + # The version of a generated dependency at test runtime may differ from the version used during generation. + # Delete any fields which are not present in the current runtime dependency + # See https://github.com/googleapis/gapic-generator-python/issues/1748 + + # Determine if the message type is proto-plus or protobuf + test_field = firestore_admin.UpdateFieldRequest.meta.fields["field"] + + def get_message_fields(field): + # Given a field which is a message (composite type), return a list with + # all the fields of the message. + # If the field is not a composite type, return an empty list. + message_fields = [] + + if hasattr(field, "message") and field.message: + is_field_type_proto_plus_type = not hasattr(field.message, "DESCRIPTOR") + + if is_field_type_proto_plus_type: + message_fields = field.message.meta.fields.values() + # Add `# pragma: NO COVER` because there may not be any `*_pb2` field types + else: # pragma: NO COVER + message_fields = field.message.DESCRIPTOR.fields + return message_fields + + runtime_nested_fields = [ + (field.name, nested_field.name) + for field in get_message_fields(test_field) + for nested_field in get_message_fields(field) + ] + + subfields_not_in_runtime = [] + + # For each item in the sample request, create a list of sub fields which are not present at runtime + # Add `# pragma: NO COVER` because this test code will not run if all subfields are present at runtime + for field, value in request_init["field"].items(): # pragma: NO COVER + result = None + is_repeated = False + # For repeated fields + if isinstance(value, list) and len(value): + is_repeated = True + result = value[0] + # For fields where the type is another message + if isinstance(value, dict): + result = value + + if result and hasattr(result, "keys"): + for subfield in result.keys(): + if (field, subfield) not in runtime_nested_fields: + subfields_not_in_runtime.append( + { + "field": field, + "subfield": subfield, + "is_repeated": is_repeated, + } + ) + + # Remove fields from the sample request which are not present in the runtime version of the dependency + # Add `# pragma: NO COVER` because this test code will not run if all subfields are present at runtime + for subfield_to_delete in subfields_not_in_runtime: # pragma: NO COVER + field = subfield_to_delete.get("field") + field_repeated = subfield_to_delete.get("is_repeated") + subfield = subfield_to_delete.get("subfield") + if subfield: + if field_repeated: + for i in range(0, len(request_init["field"][field])): + del request_init["field"][field][i][subfield] + else: + del request_init["field"][field][subfield] request = request_type(**request_init) # Mock the http request call within the method and fake a response. with mock.patch.object(type(client.transport._session), "request") as req: # Designate an appropriate value for the returned response. - return_value = field.Field( - name="name_value", - ) + return_value = operations_pb2.Operation(name="operations/spam") # Wrap the value into a proper Response obj response_value = Response() response_value.status_code = 200 - # Convert return value to protobuf type - return_value = field.Field.pb(return_value) 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_field(request) + response = client.update_field(request) # Establish that the response is the type that we expect. - assert isinstance(response, field.Field) - assert response.name == "name_value" + assert response.operation.name == "operations/spam" -def test_get_field_rest_required_fields(request_type=firestore_admin.GetFieldRequest): +def test_update_field_rest_use_cached_wrapped_rpc(): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method.wrap_method") as wrapper_fn: + client = FirestoreAdminClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert client._transport.update_field in client._transport._wrapped_methods + + # Replace cached wrapped function with mock + mock_rpc = mock.Mock() + mock_rpc.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) + client._transport._wrapped_methods[client._transport.update_field] = mock_rpc + + request = {} + client.update_field(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + # Operation methods build a cached wrapper on first rpc call + # subsequent calls should use the cached wrapper + wrapper_fn.reset_mock() + + client.update_field(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 + + +def test_update_field_rest_required_fields( + request_type=firestore_admin.UpdateFieldRequest, +): transport_class = transports.FirestoreAdminRestTransport request_init = {} - request_init["name"] = "" request = request_type(**request_init) pb_request = request_type.pb(request) jsonified_request = json.loads( @@ -9341,21 +12339,19 @@ def test_get_field_rest_required_fields(request_type=firestore_admin.GetFieldReq unset_fields = transport_class( credentials=ga_credentials.AnonymousCredentials() - ).get_field._get_unset_required_fields(jsonified_request) + ).update_field._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_field._get_unset_required_fields(jsonified_request) + ).update_field._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 - assert "name" in jsonified_request - assert jsonified_request["name"] == "name_value" client = FirestoreAdminClient( credentials=ga_credentials.AnonymousCredentials(), @@ -9364,7 +12360,7 @@ def test_get_field_rest_required_fields(request_type=firestore_admin.GetFieldReq request = request_type(**request_init) # Designate an appropriate value for the returned response. - return_value = field.Field() + 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 @@ -9376,39 +12372,37 @@ def test_get_field_rest_required_fields(request_type=firestore_admin.GetFieldReq pb_request = request_type.pb(request) transcode_result = { "uri": "v1/sample_method", - "method": "get", + "method": "patch", "query_params": pb_request, } + transcode_result["body"] = pb_request transcode.return_value = transcode_result response_value = Response() response_value.status_code = 200 - - # Convert return value to protobuf type - return_value = field.Field.pb(return_value) 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_field(request) + response = client.update_field(request) expected_params = [("$alt", "json;enum-encoding=int")] actual_params = req.call_args.kwargs["params"] assert expected_params == actual_params -def test_get_field_rest_unset_required_fields(): +def test_update_field_rest_unset_required_fields(): transport = transports.FirestoreAdminRestTransport( credentials=ga_credentials.AnonymousCredentials ) - unset_fields = transport.get_field._get_unset_required_fields({}) - assert set(unset_fields) == (set(()) & set(("name",))) + unset_fields = transport.update_field._get_unset_required_fields({}) + assert set(unset_fields) == (set(("updateMask",)) & set(("field",))) @pytest.mark.parametrize("null_interceptor", [True, False]) -def test_get_field_rest_interceptors(null_interceptor): +def test_update_field_rest_interceptors(null_interceptor): transport = transports.FirestoreAdminRestTransport( credentials=ga_credentials.AnonymousCredentials(), interceptor=None @@ -9421,14 +12415,16 @@ def test_get_field_rest_interceptors(null_interceptor): ) as req, mock.patch.object( path_template, "transcode" ) as transcode, mock.patch.object( - transports.FirestoreAdminRestInterceptor, "post_get_field" + operation.Operation, "_set_result_from_operation" + ), mock.patch.object( + transports.FirestoreAdminRestInterceptor, "post_update_field" ) as post, mock.patch.object( - transports.FirestoreAdminRestInterceptor, "pre_get_field" + transports.FirestoreAdminRestInterceptor, "pre_update_field" ) as pre: pre.assert_not_called() post.assert_not_called() - pb_message = firestore_admin.GetFieldRequest.pb( - firestore_admin.GetFieldRequest() + pb_message = firestore_admin.UpdateFieldRequest.pb( + firestore_admin.UpdateFieldRequest() ) transcode.return_value = { "method": "post", @@ -9440,17 +12436,19 @@ def test_get_field_rest_interceptors(null_interceptor): req.return_value = Response() req.return_value.status_code = 200 req.return_value.request = PreparedRequest() - req.return_value._content = field.Field.to_json(field.Field()) + req.return_value._content = json_format.MessageToJson( + operations_pb2.Operation() + ) - request = firestore_admin.GetFieldRequest() + request = firestore_admin.UpdateFieldRequest() metadata = [ ("key", "val"), ("cephalopod", "squid"), ] pre.return_value = request, metadata - post.return_value = field.Field() + post.return_value = operations_pb2.Operation() - client.get_field( + client.update_field( request, metadata=[ ("key", "val"), @@ -9462,8 +12460,8 @@ def test_get_field_rest_interceptors(null_interceptor): post.assert_called_once() -def test_get_field_rest_bad_request( - transport: str = "rest", request_type=firestore_admin.GetFieldRequest +def test_update_field_rest_bad_request( + transport: str = "rest", request_type=firestore_admin.UpdateFieldRequest ): client = FirestoreAdminClient( credentials=ga_credentials.AnonymousCredentials(), @@ -9472,7 +12470,9 @@ def test_get_field_rest_bad_request( # send a request that will satisfy transcoding request_init = { - "name": "projects/sample1/databases/sample2/collectionGroups/sample3/fields/sample4" + "field": { + "name": "projects/sample1/databases/sample2/collectionGroups/sample3/fields/sample4" + } } request = request_type(**request_init) @@ -9485,10 +12485,10 @@ def test_get_field_rest_bad_request( response_value.status_code = 400 response_value.request = Request() req.return_value = response_value - client.get_field(request) + client.update_field(request) -def test_get_field_rest_flattened(): +def test_update_field_rest_flattened(): client = FirestoreAdminClient( credentials=ga_credentials.AnonymousCredentials(), transport="rest", @@ -9497,42 +12497,42 @@ def test_get_field_rest_flattened(): # Mock the http request call within the method and fake a response. with mock.patch.object(type(client.transport._session), "request") as req: # Designate an appropriate value for the returned response. - return_value = field.Field() + return_value = operations_pb2.Operation(name="operations/spam") # get arguments that satisfy an http rule for this method sample_request = { - "name": "projects/sample1/databases/sample2/collectionGroups/sample3/fields/sample4" + "field": { + "name": "projects/sample1/databases/sample2/collectionGroups/sample3/fields/sample4" + } } # get truthy value for each flattened field mock_args = dict( - name="name_value", + field=gfa_field.Field(name="name_value"), ) mock_args.update(sample_request) # Wrap the value into a proper Response obj response_value = Response() response_value.status_code = 200 - # Convert return value to protobuf type - return_value = field.Field.pb(return_value) json_return_value = json_format.MessageToJson(return_value) response_value._content = json_return_value.encode("UTF-8") req.return_value = response_value - client.get_field(**mock_args) + client.update_field(**mock_args) # Establish that the underlying call was made with the expected # request object values. assert len(req.mock_calls) == 1 _, args, _ = req.mock_calls[0] assert path_template.validate( - "%s/v1/{name=projects/*/databases/*/collectionGroups/*/fields/*}" + "%s/v1/{field.name=projects/*/databases/*/collectionGroups/*/fields/*}" % client.transport._host, args[1], ) -def test_get_field_rest_flattened_error(transport: str = "rest"): +def test_update_field_rest_flattened_error(transport: str = "rest"): client = FirestoreAdminClient( credentials=ga_credentials.AnonymousCredentials(), transport=transport, @@ -9541,13 +12541,13 @@ def test_get_field_rest_flattened_error(transport: str = "rest"): # Attempting to call a method with both a request object and flattened # fields is an error. with pytest.raises(ValueError): - client.get_field( - firestore_admin.GetFieldRequest(), - name="name_value", + client.update_field( + firestore_admin.UpdateFieldRequest(), + field=gfa_field.Field(name="name_value"), ) -def test_get_field_rest_error(): +def test_update_field_rest_error(): client = FirestoreAdminClient( credentials=ga_credentials.AnonymousCredentials(), transport="rest" ) @@ -9556,140 +12556,88 @@ def test_get_field_rest_error(): @pytest.mark.parametrize( "request_type", [ - firestore_admin.UpdateFieldRequest, + firestore_admin.ListFieldsRequest, dict, ], ) -def test_update_field_rest(request_type): +def test_list_fields_rest(request_type): client = FirestoreAdminClient( credentials=ga_credentials.AnonymousCredentials(), transport="rest", ) - # send a request that will satisfy transcoding - request_init = { - "field": { - "name": "projects/sample1/databases/sample2/collectionGroups/sample3/fields/sample4" - } - } - request_init["field"] = { - "name": "projects/sample1/databases/sample2/collectionGroups/sample3/fields/sample4", - "index_config": { - "indexes": [ - { - "name": "name_value", - "query_scope": 1, - "api_scope": 1, - "fields": [ - { - "field_path": "field_path_value", - "order": 1, - "array_config": 1, - "vector_config": {"dimension": 966, "flat": {}}, - } - ], - "state": 1, - } - ], - "uses_ancestor_config": True, - "ancestor_field": "ancestor_field_value", - "reverting": True, - }, - "ttl_config": {"state": 1}, - } - # The version of a generated dependency at test runtime may differ from the version used during generation. - # Delete any fields which are not present in the current runtime dependency - # See https://github.com/googleapis/gapic-generator-python/issues/1748 - - # Determine if the message type is proto-plus or protobuf - test_field = firestore_admin.UpdateFieldRequest.meta.fields["field"] - - def get_message_fields(field): - # Given a field which is a message (composite type), return a list with - # all the fields of the message. - # If the field is not a composite type, return an empty list. - message_fields = [] - - if hasattr(field, "message") and field.message: - is_field_type_proto_plus_type = not hasattr(field.message, "DESCRIPTOR") - - if is_field_type_proto_plus_type: - message_fields = field.message.meta.fields.values() - # Add `# pragma: NO COVER` because there may not be any `*_pb2` field types - else: # pragma: NO COVER - message_fields = field.message.DESCRIPTOR.fields - return message_fields - - runtime_nested_fields = [ - (field.name, nested_field.name) - for field in get_message_fields(test_field) - for nested_field in get_message_fields(field) - ] - - subfields_not_in_runtime = [] - - # For each item in the sample request, create a list of sub fields which are not present at runtime - # Add `# pragma: NO COVER` because this test code will not run if all subfields are present at runtime - for field, value in request_init["field"].items(): # pragma: NO COVER - result = None - is_repeated = False - # For repeated fields - if isinstance(value, list) and len(value): - is_repeated = True - result = value[0] - # For fields where the type is another message - if isinstance(value, dict): - result = value - - if result and hasattr(result, "keys"): - for subfield in result.keys(): - if (field, subfield) not in runtime_nested_fields: - subfields_not_in_runtime.append( - { - "field": field, - "subfield": subfield, - "is_repeated": is_repeated, - } - ) - - # Remove fields from the sample request which are not present in the runtime version of the dependency - # Add `# pragma: NO COVER` because this test code will not run if all subfields are present at runtime - for subfield_to_delete in subfields_not_in_runtime: # pragma: NO COVER - field = subfield_to_delete.get("field") - field_repeated = subfield_to_delete.get("is_repeated") - subfield = subfield_to_delete.get("subfield") - if subfield: - if field_repeated: - for i in range(0, len(request_init["field"][field])): - del request_init["field"][field][i][subfield] - else: - del request_init["field"][field][subfield] + # send a request that will satisfy transcoding + request_init = { + "parent": "projects/sample1/databases/sample2/collectionGroups/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") + return_value = firestore_admin.ListFieldsResponse( + next_page_token="next_page_token_value", + ) # Wrap the value into a proper Response obj response_value = Response() response_value.status_code = 200 + # Convert return value to protobuf type + return_value = firestore_admin.ListFieldsResponse.pb(return_value) 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_field(request) + response = client.list_fields(request) # Establish that the response is the type that we expect. - assert response.operation.name == "operations/spam" + assert isinstance(response, pagers.ListFieldsPager) + assert response.next_page_token == "next_page_token_value" -def test_update_field_rest_required_fields( - request_type=firestore_admin.UpdateFieldRequest, +def test_list_fields_rest_use_cached_wrapped_rpc(): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method.wrap_method") as wrapper_fn: + client = FirestoreAdminClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert client._transport.list_fields in client._transport._wrapped_methods + + # Replace cached wrapped function with mock + mock_rpc = mock.Mock() + mock_rpc.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) + client._transport._wrapped_methods[client._transport.list_fields] = mock_rpc + + request = {} + client.list_fields(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + client.list_fields(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 + + +def test_list_fields_rest_required_fields( + request_type=firestore_admin.ListFieldsRequest, ): transport_class = transports.FirestoreAdminRestTransport request_init = {} + request_init["parent"] = "" request = request_type(**request_init) pb_request = request_type.pb(request) jsonified_request = json.loads( @@ -9700,19 +12648,29 @@ def test_update_field_rest_required_fields( unset_fields = transport_class( credentials=ga_credentials.AnonymousCredentials() - ).update_field._get_unset_required_fields(jsonified_request) + ).list_fields._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() - ).update_field._get_unset_required_fields(jsonified_request) + ).list_fields._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",)) + 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 = FirestoreAdminClient( credentials=ga_credentials.AnonymousCredentials(), @@ -9721,7 +12679,7 @@ def test_update_field_rest_required_fields( request = request_type(**request_init) # Designate an appropriate value for the returned response. - return_value = operations_pb2.Operation(name="operations/spam") + return_value = firestore_admin.ListFieldsResponse() # 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 @@ -9733,37 +12691,48 @@ def test_update_field_rest_required_fields( pb_request = request_type.pb(request) transcode_result = { "uri": "v1/sample_method", - "method": "patch", + "method": "get", "query_params": pb_request, } - transcode_result["body"] = pb_request transcode.return_value = transcode_result response_value = Response() response_value.status_code = 200 + + # Convert return value to protobuf type + return_value = firestore_admin.ListFieldsResponse.pb(return_value) 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_field(request) + response = client.list_fields(request) expected_params = [("$alt", "json;enum-encoding=int")] actual_params = req.call_args.kwargs["params"] assert expected_params == actual_params -def test_update_field_rest_unset_required_fields(): +def test_list_fields_rest_unset_required_fields(): transport = transports.FirestoreAdminRestTransport( credentials=ga_credentials.AnonymousCredentials ) - unset_fields = transport.update_field._get_unset_required_fields({}) - assert set(unset_fields) == (set(("updateMask",)) & set(("field",))) + unset_fields = transport.list_fields._get_unset_required_fields({}) + assert set(unset_fields) == ( + set( + ( + "filter", + "pageSize", + "pageToken", + ) + ) + & set(("parent",)) + ) @pytest.mark.parametrize("null_interceptor", [True, False]) -def test_update_field_rest_interceptors(null_interceptor): +def test_list_fields_rest_interceptors(null_interceptor): transport = transports.FirestoreAdminRestTransport( credentials=ga_credentials.AnonymousCredentials(), interceptor=None @@ -9776,16 +12745,14 @@ def test_update_field_rest_interceptors(null_interceptor): ) as req, mock.patch.object( path_template, "transcode" ) as transcode, mock.patch.object( - operation.Operation, "_set_result_from_operation" - ), mock.patch.object( - transports.FirestoreAdminRestInterceptor, "post_update_field" + transports.FirestoreAdminRestInterceptor, "post_list_fields" ) as post, mock.patch.object( - transports.FirestoreAdminRestInterceptor, "pre_update_field" + transports.FirestoreAdminRestInterceptor, "pre_list_fields" ) as pre: pre.assert_not_called() post.assert_not_called() - pb_message = firestore_admin.UpdateFieldRequest.pb( - firestore_admin.UpdateFieldRequest() + pb_message = firestore_admin.ListFieldsRequest.pb( + firestore_admin.ListFieldsRequest() ) transcode.return_value = { "method": "post", @@ -9797,19 +12764,19 @@ def test_update_field_rest_interceptors(null_interceptor): 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() + req.return_value._content = firestore_admin.ListFieldsResponse.to_json( + firestore_admin.ListFieldsResponse() ) - request = firestore_admin.UpdateFieldRequest() + request = firestore_admin.ListFieldsRequest() metadata = [ ("key", "val"), ("cephalopod", "squid"), ] pre.return_value = request, metadata - post.return_value = operations_pb2.Operation() + post.return_value = firestore_admin.ListFieldsResponse() - client.update_field( + client.list_fields( request, metadata=[ ("key", "val"), @@ -9821,8 +12788,8 @@ def test_update_field_rest_interceptors(null_interceptor): post.assert_called_once() -def test_update_field_rest_bad_request( - transport: str = "rest", request_type=firestore_admin.UpdateFieldRequest +def test_list_fields_rest_bad_request( + transport: str = "rest", request_type=firestore_admin.ListFieldsRequest ): client = FirestoreAdminClient( credentials=ga_credentials.AnonymousCredentials(), @@ -9831,9 +12798,7 @@ def test_update_field_rest_bad_request( # send a request that will satisfy transcoding request_init = { - "field": { - "name": "projects/sample1/databases/sample2/collectionGroups/sample3/fields/sample4" - } + "parent": "projects/sample1/databases/sample2/collectionGroups/sample3" } request = request_type(**request_init) @@ -9846,10 +12811,10 @@ def test_update_field_rest_bad_request( response_value.status_code = 400 response_value.request = Request() req.return_value = response_value - client.update_field(request) + client.list_fields(request) -def test_update_field_rest_flattened(): +def test_list_fields_rest_flattened(): client = FirestoreAdminClient( credentials=ga_credentials.AnonymousCredentials(), transport="rest", @@ -9858,42 +12823,42 @@ def test_update_field_rest_flattened(): # Mock the http request call within the method and 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") + return_value = firestore_admin.ListFieldsResponse() # get arguments that satisfy an http rule for this method sample_request = { - "field": { - "name": "projects/sample1/databases/sample2/collectionGroups/sample3/fields/sample4" - } + "parent": "projects/sample1/databases/sample2/collectionGroups/sample3" } # get truthy value for each flattened field mock_args = dict( - field=gfa_field.Field(name="name_value"), + parent="parent_value", ) mock_args.update(sample_request) # Wrap the value into a proper Response obj response_value = Response() response_value.status_code = 200 + # Convert return value to protobuf type + return_value = firestore_admin.ListFieldsResponse.pb(return_value) json_return_value = json_format.MessageToJson(return_value) response_value._content = json_return_value.encode("UTF-8") req.return_value = response_value - client.update_field(**mock_args) + client.list_fields(**mock_args) # Establish that the underlying call was made with the expected # request object values. assert len(req.mock_calls) == 1 _, args, _ = req.mock_calls[0] assert path_template.validate( - "%s/v1/{field.name=projects/*/databases/*/collectionGroups/*/fields/*}" + "%s/v1/{parent=projects/*/databases/*/collectionGroups/*}/fields" % client.transport._host, args[1], ) -def test_update_field_rest_flattened_error(transport: str = "rest"): +def test_list_fields_rest_flattened_error(transport: str = "rest"): client = FirestoreAdminClient( credentials=ga_credentials.AnonymousCredentials(), transport=transport, @@ -9902,67 +12867,161 @@ def test_update_field_rest_flattened_error(transport: str = "rest"): # Attempting to call a method with both a request object and flattened # fields is an error. with pytest.raises(ValueError): - client.update_field( - firestore_admin.UpdateFieldRequest(), - field=gfa_field.Field(name="name_value"), + client.list_fields( + firestore_admin.ListFieldsRequest(), + parent="parent_value", ) -def test_update_field_rest_error(): +def test_list_fields_rest_pager(transport: str = "rest"): client = FirestoreAdminClient( - credentials=ga_credentials.AnonymousCredentials(), transport="rest" + 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 = ( + firestore_admin.ListFieldsResponse( + fields=[ + field.Field(), + field.Field(), + field.Field(), + ], + next_page_token="abc", + ), + firestore_admin.ListFieldsResponse( + fields=[], + next_page_token="def", + ), + firestore_admin.ListFieldsResponse( + fields=[ + field.Field(), + ], + next_page_token="ghi", + ), + firestore_admin.ListFieldsResponse( + fields=[ + field.Field(), + field.Field(), + ], + ), + ) + # Two responses for two calls + response = response + response + + # Wrap the values into proper Response objs + response = tuple( + firestore_admin.ListFieldsResponse.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/databases/sample2/collectionGroups/sample3" + } + + pager = client.list_fields(request=sample_request) + + results = list(pager) + assert len(results) == 6 + assert all(isinstance(i, field.Field) for i in results) + + pages = list(client.list_fields(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", [ - firestore_admin.ListFieldsRequest, + firestore_admin.ExportDocumentsRequest, dict, ], ) -def test_list_fields_rest(request_type): +def test_export_documents_rest(request_type): client = FirestoreAdminClient( credentials=ga_credentials.AnonymousCredentials(), transport="rest", ) # send a request that will satisfy transcoding - request_init = { - "parent": "projects/sample1/databases/sample2/collectionGroups/sample3" - } + request_init = {"name": "projects/sample1/databases/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 = firestore_admin.ListFieldsResponse( - next_page_token="next_page_token_value", - ) + return_value = operations_pb2.Operation(name="operations/spam") # Wrap the value into a proper Response obj response_value = Response() response_value.status_code = 200 - # Convert return value to protobuf type - return_value = firestore_admin.ListFieldsResponse.pb(return_value) 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_fields(request) + response = client.export_documents(request) # Establish that the response is the type that we expect. - assert isinstance(response, pagers.ListFieldsPager) - assert response.next_page_token == "next_page_token_value" + assert response.operation.name == "operations/spam" -def test_list_fields_rest_required_fields( - request_type=firestore_admin.ListFieldsRequest, +def test_export_documents_rest_use_cached_wrapped_rpc(): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method.wrap_method") as wrapper_fn: + client = FirestoreAdminClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert client._transport.export_documents in client._transport._wrapped_methods + + # Replace cached wrapped function with mock + mock_rpc = mock.Mock() + mock_rpc.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) + client._transport._wrapped_methods[ + client._transport.export_documents + ] = mock_rpc + + request = {} + client.export_documents(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + # Operation methods build a cached wrapper on first rpc call + # subsequent calls should use the cached wrapper + wrapper_fn.reset_mock() + + client.export_documents(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 + + +def test_export_documents_rest_required_fields( + request_type=firestore_admin.ExportDocumentsRequest, ): transport_class = transports.FirestoreAdminRestTransport request_init = {} - request_init["parent"] = "" + request_init["name"] = "" request = request_type(**request_init) pb_request = request_type.pb(request) jsonified_request = json.loads( @@ -9973,29 +13032,21 @@ def test_list_fields_rest_required_fields( unset_fields = transport_class( credentials=ga_credentials.AnonymousCredentials() - ).list_fields._get_unset_required_fields(jsonified_request) + ).export_documents._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_fields._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", - ) - ) + + # verify required fields with default values are now present + + jsonified_request["name"] = "name_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).export_documents._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 "name" in jsonified_request + assert jsonified_request["name"] == "name_value" client = FirestoreAdminClient( credentials=ga_credentials.AnonymousCredentials(), @@ -10004,7 +13055,7 @@ def test_list_fields_rest_required_fields( request = request_type(**request_init) # Designate an appropriate value for the returned response. - return_value = firestore_admin.ListFieldsResponse() + 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 @@ -10016,48 +13067,37 @@ def test_list_fields_rest_required_fields( pb_request = request_type.pb(request) transcode_result = { "uri": "v1/sample_method", - "method": "get", + "method": "post", "query_params": pb_request, } + transcode_result["body"] = pb_request transcode.return_value = transcode_result response_value = Response() response_value.status_code = 200 - - # Convert return value to protobuf type - return_value = firestore_admin.ListFieldsResponse.pb(return_value) 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_fields(request) + response = client.export_documents(request) expected_params = [("$alt", "json;enum-encoding=int")] actual_params = req.call_args.kwargs["params"] assert expected_params == actual_params -def test_list_fields_rest_unset_required_fields(): +def test_export_documents_rest_unset_required_fields(): transport = transports.FirestoreAdminRestTransport( credentials=ga_credentials.AnonymousCredentials ) - unset_fields = transport.list_fields._get_unset_required_fields({}) - assert set(unset_fields) == ( - set( - ( - "filter", - "pageSize", - "pageToken", - ) - ) - & set(("parent",)) - ) + unset_fields = transport.export_documents._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) @pytest.mark.parametrize("null_interceptor", [True, False]) -def test_list_fields_rest_interceptors(null_interceptor): +def test_export_documents_rest_interceptors(null_interceptor): transport = transports.FirestoreAdminRestTransport( credentials=ga_credentials.AnonymousCredentials(), interceptor=None @@ -10070,14 +13110,16 @@ def test_list_fields_rest_interceptors(null_interceptor): ) as req, mock.patch.object( path_template, "transcode" ) as transcode, mock.patch.object( - transports.FirestoreAdminRestInterceptor, "post_list_fields" + operation.Operation, "_set_result_from_operation" + ), mock.patch.object( + transports.FirestoreAdminRestInterceptor, "post_export_documents" ) as post, mock.patch.object( - transports.FirestoreAdminRestInterceptor, "pre_list_fields" + transports.FirestoreAdminRestInterceptor, "pre_export_documents" ) as pre: pre.assert_not_called() post.assert_not_called() - pb_message = firestore_admin.ListFieldsRequest.pb( - firestore_admin.ListFieldsRequest() + pb_message = firestore_admin.ExportDocumentsRequest.pb( + firestore_admin.ExportDocumentsRequest() ) transcode.return_value = { "method": "post", @@ -10089,19 +13131,19 @@ def test_list_fields_rest_interceptors(null_interceptor): req.return_value = Response() req.return_value.status_code = 200 req.return_value.request = PreparedRequest() - req.return_value._content = firestore_admin.ListFieldsResponse.to_json( - firestore_admin.ListFieldsResponse() + req.return_value._content = json_format.MessageToJson( + operations_pb2.Operation() ) - request = firestore_admin.ListFieldsRequest() + request = firestore_admin.ExportDocumentsRequest() metadata = [ ("key", "val"), ("cephalopod", "squid"), ] pre.return_value = request, metadata - post.return_value = firestore_admin.ListFieldsResponse() + post.return_value = operations_pb2.Operation() - client.list_fields( + client.export_documents( request, metadata=[ ("key", "val"), @@ -10113,8 +13155,8 @@ def test_list_fields_rest_interceptors(null_interceptor): post.assert_called_once() -def test_list_fields_rest_bad_request( - transport: str = "rest", request_type=firestore_admin.ListFieldsRequest +def test_export_documents_rest_bad_request( + transport: str = "rest", request_type=firestore_admin.ExportDocumentsRequest ): client = FirestoreAdminClient( credentials=ga_credentials.AnonymousCredentials(), @@ -10122,9 +13164,7 @@ def test_list_fields_rest_bad_request( ) # send a request that will satisfy transcoding - request_init = { - "parent": "projects/sample1/databases/sample2/collectionGroups/sample3" - } + request_init = {"name": "projects/sample1/databases/sample2"} request = request_type(**request_init) # Mock the http request call within the method and fake a BadRequest error. @@ -10136,10 +13176,10 @@ def test_list_fields_rest_bad_request( response_value.status_code = 400 response_value.request = Request() req.return_value = response_value - client.list_fields(request) + client.export_documents(request) -def test_list_fields_rest_flattened(): +def test_export_documents_rest_flattened(): client = FirestoreAdminClient( credentials=ga_credentials.AnonymousCredentials(), transport="rest", @@ -10148,42 +13188,38 @@ def test_list_fields_rest_flattened(): # Mock the http request call within the method and fake a response. with mock.patch.object(type(client.transport._session), "request") as req: # Designate an appropriate value for the returned response. - return_value = firestore_admin.ListFieldsResponse() + return_value = operations_pb2.Operation(name="operations/spam") # get arguments that satisfy an http rule for this method - sample_request = { - "parent": "projects/sample1/databases/sample2/collectionGroups/sample3" - } + sample_request = {"name": "projects/sample1/databases/sample2"} # get truthy value for each flattened field mock_args = dict( - parent="parent_value", + name="name_value", ) mock_args.update(sample_request) # Wrap the value into a proper Response obj response_value = Response() response_value.status_code = 200 - # Convert return value to protobuf type - return_value = firestore_admin.ListFieldsResponse.pb(return_value) json_return_value = json_format.MessageToJson(return_value) response_value._content = json_return_value.encode("UTF-8") req.return_value = response_value - client.list_fields(**mock_args) + client.export_documents(**mock_args) # Establish that the underlying call was made with the expected # request object values. assert len(req.mock_calls) == 1 _, args, _ = req.mock_calls[0] assert path_template.validate( - "%s/v1/{parent=projects/*/databases/*/collectionGroups/*}/fields" + "%s/v1/{name=projects/*/databases/*}:exportDocuments" % client.transport._host, args[1], ) -def test_list_fields_rest_flattened_error(transport: str = "rest"): +def test_export_documents_rest_flattened_error(transport: str = "rest"): client = FirestoreAdminClient( credentials=ga_credentials.AnonymousCredentials(), transport=transport, @@ -10192,85 +13228,26 @@ def test_list_fields_rest_flattened_error(transport: str = "rest"): # Attempting to call a method with both a request object and flattened # fields is an error. with pytest.raises(ValueError): - client.list_fields( - firestore_admin.ListFieldsRequest(), - parent="parent_value", + client.export_documents( + firestore_admin.ExportDocumentsRequest(), + name="name_value", ) -def test_list_fields_rest_pager(transport: str = "rest"): +def test_export_documents_rest_error(): client = FirestoreAdminClient( - credentials=ga_credentials.AnonymousCredentials(), - transport=transport, + credentials=ga_credentials.AnonymousCredentials(), transport="rest" ) - # 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 = ( - firestore_admin.ListFieldsResponse( - fields=[ - field.Field(), - field.Field(), - field.Field(), - ], - next_page_token="abc", - ), - firestore_admin.ListFieldsResponse( - fields=[], - next_page_token="def", - ), - firestore_admin.ListFieldsResponse( - fields=[ - field.Field(), - ], - next_page_token="ghi", - ), - firestore_admin.ListFieldsResponse( - fields=[ - field.Field(), - field.Field(), - ], - ), - ) - # Two responses for two calls - response = response + response - - # Wrap the values into proper Response objs - response = tuple( - firestore_admin.ListFieldsResponse.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/databases/sample2/collectionGroups/sample3" - } - - pager = client.list_fields(request=sample_request) - - results = list(pager) - assert len(results) == 6 - assert all(isinstance(i, field.Field) for i in results) - - pages = list(client.list_fields(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", [ - firestore_admin.ExportDocumentsRequest, + firestore_admin.ImportDocumentsRequest, dict, ], ) -def test_export_documents_rest(request_type): +def test_import_documents_rest(request_type): client = FirestoreAdminClient( credentials=ga_credentials.AnonymousCredentials(), transport="rest", @@ -10292,14 +13269,56 @@ def test_export_documents_rest(request_type): response_value._content = json_return_value.encode("UTF-8") req.return_value = response_value - response = client.export_documents(request) + response = client.import_documents(request) # Establish that the response is the type that we expect. assert response.operation.name == "operations/spam" -def test_export_documents_rest_required_fields( - request_type=firestore_admin.ExportDocumentsRequest, +def test_import_documents_rest_use_cached_wrapped_rpc(): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method.wrap_method") as wrapper_fn: + client = FirestoreAdminClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert client._transport.import_documents in client._transport._wrapped_methods + + # Replace cached wrapped function with mock + mock_rpc = mock.Mock() + mock_rpc.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) + client._transport._wrapped_methods[ + client._transport.import_documents + ] = mock_rpc + + request = {} + client.import_documents(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + # Operation methods build a cached wrapper on first rpc call + # subsequent calls should use the cached wrapper + wrapper_fn.reset_mock() + + client.import_documents(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 + + +def test_import_documents_rest_required_fields( + request_type=firestore_admin.ImportDocumentsRequest, ): transport_class = transports.FirestoreAdminRestTransport @@ -10315,7 +13334,7 @@ def test_export_documents_rest_required_fields( unset_fields = transport_class( credentials=ga_credentials.AnonymousCredentials() - ).export_documents._get_unset_required_fields(jsonified_request) + ).import_documents._get_unset_required_fields(jsonified_request) jsonified_request.update(unset_fields) # verify required fields with default values are now present @@ -10324,7 +13343,7 @@ def test_export_documents_rest_required_fields( unset_fields = transport_class( credentials=ga_credentials.AnonymousCredentials() - ).export_documents._get_unset_required_fields(jsonified_request) + ).import_documents._get_unset_required_fields(jsonified_request) jsonified_request.update(unset_fields) # verify required fields with non-default values are left alone @@ -10363,24 +13382,24 @@ def test_export_documents_rest_required_fields( response_value._content = json_return_value.encode("UTF-8") req.return_value = response_value - response = client.export_documents(request) + response = client.import_documents(request) expected_params = [("$alt", "json;enum-encoding=int")] actual_params = req.call_args.kwargs["params"] assert expected_params == actual_params -def test_export_documents_rest_unset_required_fields(): +def test_import_documents_rest_unset_required_fields(): transport = transports.FirestoreAdminRestTransport( credentials=ga_credentials.AnonymousCredentials ) - unset_fields = transport.export_documents._get_unset_required_fields({}) + unset_fields = transport.import_documents._get_unset_required_fields({}) assert set(unset_fields) == (set(()) & set(("name",))) @pytest.mark.parametrize("null_interceptor", [True, False]) -def test_export_documents_rest_interceptors(null_interceptor): +def test_import_documents_rest_interceptors(null_interceptor): transport = transports.FirestoreAdminRestTransport( credentials=ga_credentials.AnonymousCredentials(), interceptor=None @@ -10395,14 +13414,14 @@ def test_export_documents_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( operation.Operation, "_set_result_from_operation" ), mock.patch.object( - transports.FirestoreAdminRestInterceptor, "post_export_documents" + transports.FirestoreAdminRestInterceptor, "post_import_documents" ) as post, mock.patch.object( - transports.FirestoreAdminRestInterceptor, "pre_export_documents" + transports.FirestoreAdminRestInterceptor, "pre_import_documents" ) as pre: pre.assert_not_called() post.assert_not_called() - pb_message = firestore_admin.ExportDocumentsRequest.pb( - firestore_admin.ExportDocumentsRequest() + pb_message = firestore_admin.ImportDocumentsRequest.pb( + firestore_admin.ImportDocumentsRequest() ) transcode.return_value = { "method": "post", @@ -10418,7 +13437,7 @@ def test_export_documents_rest_interceptors(null_interceptor): operations_pb2.Operation() ) - request = firestore_admin.ExportDocumentsRequest() + request = firestore_admin.ImportDocumentsRequest() metadata = [ ("key", "val"), ("cephalopod", "squid"), @@ -10426,7 +13445,7 @@ def test_export_documents_rest_interceptors(null_interceptor): pre.return_value = request, metadata post.return_value = operations_pb2.Operation() - client.export_documents( + client.import_documents( request, metadata=[ ("key", "val"), @@ -10438,8 +13457,8 @@ def test_export_documents_rest_interceptors(null_interceptor): post.assert_called_once() -def test_export_documents_rest_bad_request( - transport: str = "rest", request_type=firestore_admin.ExportDocumentsRequest +def test_import_documents_rest_bad_request( + transport: str = "rest", request_type=firestore_admin.ImportDocumentsRequest ): client = FirestoreAdminClient( credentials=ga_credentials.AnonymousCredentials(), @@ -10459,10 +13478,10 @@ def test_export_documents_rest_bad_request( response_value.status_code = 400 response_value.request = Request() req.return_value = response_value - client.export_documents(request) + client.import_documents(request) -def test_export_documents_rest_flattened(): +def test_import_documents_rest_flattened(): client = FirestoreAdminClient( credentials=ga_credentials.AnonymousCredentials(), transport="rest", @@ -10489,20 +13508,20 @@ def test_export_documents_rest_flattened(): response_value._content = json_return_value.encode("UTF-8") req.return_value = response_value - client.export_documents(**mock_args) + client.import_documents(**mock_args) # Establish that the underlying call was made with the expected # request object values. assert len(req.mock_calls) == 1 _, args, _ = req.mock_calls[0] assert path_template.validate( - "%s/v1/{name=projects/*/databases/*}:exportDocuments" + "%s/v1/{name=projects/*/databases/*}:importDocuments" % client.transport._host, args[1], ) -def test_export_documents_rest_flattened_error(transport: str = "rest"): +def test_import_documents_rest_flattened_error(transport: str = "rest"): client = FirestoreAdminClient( credentials=ga_credentials.AnonymousCredentials(), transport=transport, @@ -10511,13 +13530,13 @@ def test_export_documents_rest_flattened_error(transport: str = "rest"): # Attempting to call a method with both a request object and flattened # fields is an error. with pytest.raises(ValueError): - client.export_documents( - firestore_admin.ExportDocumentsRequest(), + client.import_documents( + firestore_admin.ImportDocumentsRequest(), name="name_value", ) -def test_export_documents_rest_error(): +def test_import_documents_rest_error(): client = FirestoreAdminClient( credentials=ga_credentials.AnonymousCredentials(), transport="rest" ) @@ -10526,11 +13545,11 @@ def test_export_documents_rest_error(): @pytest.mark.parametrize( "request_type", [ - firestore_admin.ImportDocumentsRequest, + firestore_admin.BulkDeleteDocumentsRequest, dict, ], ) -def test_import_documents_rest(request_type): +def test_bulk_delete_documents_rest(request_type): client = FirestoreAdminClient( credentials=ga_credentials.AnonymousCredentials(), transport="rest", @@ -10552,14 +13571,59 @@ def test_import_documents_rest(request_type): response_value._content = json_return_value.encode("UTF-8") req.return_value = response_value - response = client.import_documents(request) + response = client.bulk_delete_documents(request) # Establish that the response is the type that we expect. assert response.operation.name == "operations/spam" -def test_import_documents_rest_required_fields( - request_type=firestore_admin.ImportDocumentsRequest, +def test_bulk_delete_documents_rest_use_cached_wrapped_rpc(): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method.wrap_method") as wrapper_fn: + client = FirestoreAdminClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert ( + client._transport.bulk_delete_documents + in client._transport._wrapped_methods + ) + + # Replace cached wrapped function with mock + mock_rpc = mock.Mock() + mock_rpc.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) + client._transport._wrapped_methods[ + client._transport.bulk_delete_documents + ] = mock_rpc + + request = {} + client.bulk_delete_documents(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + # Operation methods build a cached wrapper on first rpc call + # subsequent calls should use the cached wrapper + wrapper_fn.reset_mock() + + client.bulk_delete_documents(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 + + +def test_bulk_delete_documents_rest_required_fields( + request_type=firestore_admin.BulkDeleteDocumentsRequest, ): transport_class = transports.FirestoreAdminRestTransport @@ -10575,7 +13639,7 @@ def test_import_documents_rest_required_fields( unset_fields = transport_class( credentials=ga_credentials.AnonymousCredentials() - ).import_documents._get_unset_required_fields(jsonified_request) + ).bulk_delete_documents._get_unset_required_fields(jsonified_request) jsonified_request.update(unset_fields) # verify required fields with default values are now present @@ -10584,7 +13648,7 @@ def test_import_documents_rest_required_fields( unset_fields = transport_class( credentials=ga_credentials.AnonymousCredentials() - ).import_documents._get_unset_required_fields(jsonified_request) + ).bulk_delete_documents._get_unset_required_fields(jsonified_request) jsonified_request.update(unset_fields) # verify required fields with non-default values are left alone @@ -10623,24 +13687,24 @@ def test_import_documents_rest_required_fields( response_value._content = json_return_value.encode("UTF-8") req.return_value = response_value - response = client.import_documents(request) + response = client.bulk_delete_documents(request) expected_params = [("$alt", "json;enum-encoding=int")] actual_params = req.call_args.kwargs["params"] assert expected_params == actual_params -def test_import_documents_rest_unset_required_fields(): +def test_bulk_delete_documents_rest_unset_required_fields(): transport = transports.FirestoreAdminRestTransport( credentials=ga_credentials.AnonymousCredentials ) - unset_fields = transport.import_documents._get_unset_required_fields({}) + unset_fields = transport.bulk_delete_documents._get_unset_required_fields({}) assert set(unset_fields) == (set(()) & set(("name",))) @pytest.mark.parametrize("null_interceptor", [True, False]) -def test_import_documents_rest_interceptors(null_interceptor): +def test_bulk_delete_documents_rest_interceptors(null_interceptor): transport = transports.FirestoreAdminRestTransport( credentials=ga_credentials.AnonymousCredentials(), interceptor=None @@ -10655,14 +13719,14 @@ def test_import_documents_rest_interceptors(null_interceptor): ) as transcode, mock.patch.object( operation.Operation, "_set_result_from_operation" ), mock.patch.object( - transports.FirestoreAdminRestInterceptor, "post_import_documents" + transports.FirestoreAdminRestInterceptor, "post_bulk_delete_documents" ) as post, mock.patch.object( - transports.FirestoreAdminRestInterceptor, "pre_import_documents" + transports.FirestoreAdminRestInterceptor, "pre_bulk_delete_documents" ) as pre: pre.assert_not_called() post.assert_not_called() - pb_message = firestore_admin.ImportDocumentsRequest.pb( - firestore_admin.ImportDocumentsRequest() + pb_message = firestore_admin.BulkDeleteDocumentsRequest.pb( + firestore_admin.BulkDeleteDocumentsRequest() ) transcode.return_value = { "method": "post", @@ -10678,7 +13742,7 @@ def test_import_documents_rest_interceptors(null_interceptor): operations_pb2.Operation() ) - request = firestore_admin.ImportDocumentsRequest() + request = firestore_admin.BulkDeleteDocumentsRequest() metadata = [ ("key", "val"), ("cephalopod", "squid"), @@ -10686,7 +13750,7 @@ def test_import_documents_rest_interceptors(null_interceptor): pre.return_value = request, metadata post.return_value = operations_pb2.Operation() - client.import_documents( + client.bulk_delete_documents( request, metadata=[ ("key", "val"), @@ -10698,8 +13762,8 @@ def test_import_documents_rest_interceptors(null_interceptor): post.assert_called_once() -def test_import_documents_rest_bad_request( - transport: str = "rest", request_type=firestore_admin.ImportDocumentsRequest +def test_bulk_delete_documents_rest_bad_request( + transport: str = "rest", request_type=firestore_admin.BulkDeleteDocumentsRequest ): client = FirestoreAdminClient( credentials=ga_credentials.AnonymousCredentials(), @@ -10719,10 +13783,10 @@ def test_import_documents_rest_bad_request( response_value.status_code = 400 response_value.request = Request() req.return_value = response_value - client.import_documents(request) + client.bulk_delete_documents(request) -def test_import_documents_rest_flattened(): +def test_bulk_delete_documents_rest_flattened(): client = FirestoreAdminClient( credentials=ga_credentials.AnonymousCredentials(), transport="rest", @@ -10749,20 +13813,20 @@ def test_import_documents_rest_flattened(): response_value._content = json_return_value.encode("UTF-8") req.return_value = response_value - client.import_documents(**mock_args) + client.bulk_delete_documents(**mock_args) # Establish that the underlying call was made with the expected # request object values. assert len(req.mock_calls) == 1 _, args, _ = req.mock_calls[0] assert path_template.validate( - "%s/v1/{name=projects/*/databases/*}:importDocuments" + "%s/v1/{name=projects/*/databases/*}:bulkDeleteDocuments" % client.transport._host, args[1], ) -def test_import_documents_rest_flattened_error(transport: str = "rest"): +def test_bulk_delete_documents_rest_flattened_error(transport: str = "rest"): client = FirestoreAdminClient( credentials=ga_credentials.AnonymousCredentials(), transport=transport, @@ -10771,13 +13835,13 @@ def test_import_documents_rest_flattened_error(transport: str = "rest"): # Attempting to call a method with both a request object and flattened # fields is an error. with pytest.raises(ValueError): - client.import_documents( - firestore_admin.ImportDocumentsRequest(), + client.bulk_delete_documents( + firestore_admin.BulkDeleteDocumentsRequest(), name="name_value", ) -def test_import_documents_rest_error(): +def test_bulk_delete_documents_rest_error(): client = FirestoreAdminClient( credentials=ga_credentials.AnonymousCredentials(), transport="rest" ) @@ -10901,6 +13965,46 @@ def get_message_fields(field): assert response.operation.name == "operations/spam" +def test_create_database_rest_use_cached_wrapped_rpc(): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method.wrap_method") as wrapper_fn: + client = FirestoreAdminClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert client._transport.create_database in client._transport._wrapped_methods + + # Replace cached wrapped function with mock + mock_rpc = mock.Mock() + mock_rpc.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) + client._transport._wrapped_methods[client._transport.create_database] = mock_rpc + + request = {} + client.create_database(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + # Operation methods build a cached wrapper on first rpc call + # subsequent calls should use the cached wrapper + wrapper_fn.reset_mock() + + client.create_database(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 + + def test_create_database_rest_required_fields( request_type=firestore_admin.CreateDatabaseRequest, ): @@ -11219,6 +14323,42 @@ def test_get_database_rest(request_type): assert response.etag == "etag_value" +def test_get_database_rest_use_cached_wrapped_rpc(): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method.wrap_method") as wrapper_fn: + client = FirestoreAdminClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert client._transport.get_database in client._transport._wrapped_methods + + # Replace cached wrapped function with mock + mock_rpc = mock.Mock() + mock_rpc.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) + client._transport._wrapped_methods[client._transport.get_database] = mock_rpc + + request = {} + client.get_database(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + client.get_database(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 + + def test_get_database_rest_required_fields( request_type=firestore_admin.GetDatabaseRequest, ): @@ -11482,6 +14622,42 @@ def test_list_databases_rest(request_type): assert response.unreachable == ["unreachable_value"] +def test_list_databases_rest_use_cached_wrapped_rpc(): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method.wrap_method") as wrapper_fn: + client = FirestoreAdminClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert client._transport.list_databases in client._transport._wrapped_methods + + # Replace cached wrapped function with mock + mock_rpc = mock.Mock() + mock_rpc.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) + client._transport._wrapped_methods[client._transport.list_databases] = mock_rpc + + request = {} + client.list_databases(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + client.list_databases(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 + + def test_list_databases_rest_required_fields( request_type=firestore_admin.ListDatabasesRequest, ): @@ -11509,6 +14685,8 @@ def test_list_databases_rest_required_fields( unset_fields = transport_class( credentials=ga_credentials.AnonymousCredentials() ).list_databases._get_unset_required_fields(jsonified_request) + # Check that path parameters and body parameters are not mixing in. + assert not set(unset_fields) - set(("show_deleted",)) jsonified_request.update(unset_fields) # verify required fields with non-default values are left alone @@ -11562,7 +14740,7 @@ def test_list_databases_rest_unset_required_fields(): ) unset_fields = transport.list_databases._get_unset_required_fields({}) - assert set(unset_fields) == (set(()) & set(("parent",))) + assert set(unset_fields) == (set(("showDeleted",)) & set(("parent",))) @pytest.mark.parametrize("null_interceptor", [True, False]) @@ -11825,6 +15003,46 @@ def get_message_fields(field): assert response.operation.name == "operations/spam" +def test_update_database_rest_use_cached_wrapped_rpc(): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method.wrap_method") as wrapper_fn: + client = FirestoreAdminClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert client._transport.update_database in client._transport._wrapped_methods + + # Replace cached wrapped function with mock + mock_rpc = mock.Mock() + mock_rpc.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) + client._transport._wrapped_methods[client._transport.update_database] = mock_rpc + + request = {} + client.update_database(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + # Operation methods build a cached wrapper on first rpc call + # subsequent calls should use the cached wrapper + wrapper_fn.reset_mock() + + client.update_database(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 + + def test_update_database_rest_required_fields( request_type=firestore_admin.UpdateDatabaseRequest, ): @@ -12083,6 +15301,46 @@ def test_delete_database_rest(request_type): assert response.operation.name == "operations/spam" +def test_delete_database_rest_use_cached_wrapped_rpc(): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method.wrap_method") as wrapper_fn: + client = FirestoreAdminClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert client._transport.delete_database in client._transport._wrapped_methods + + # Replace cached wrapped function with mock + mock_rpc = mock.Mock() + mock_rpc.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) + client._transport._wrapped_methods[client._transport.delete_database] = mock_rpc + + request = {} + client.delete_database(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + # Operation methods build a cached wrapper on first rpc call + # subsequent calls should use the cached wrapper + wrapper_fn.reset_mock() + + client.delete_database(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 + + def test_delete_database_rest_required_fields( request_type=firestore_admin.DeleteDatabaseRequest, ): @@ -12353,6 +15611,42 @@ def test_get_backup_rest(request_type): assert response.state == backup.Backup.State.CREATING +def test_get_backup_rest_use_cached_wrapped_rpc(): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method.wrap_method") as wrapper_fn: + client = FirestoreAdminClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert client._transport.get_backup in client._transport._wrapped_methods + + # Replace cached wrapped function with mock + mock_rpc = mock.Mock() + mock_rpc.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) + client._transport._wrapped_methods[client._transport.get_backup] = mock_rpc + + request = {} + client.get_backup(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + client.get_backup(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 + + def test_get_backup_rest_required_fields(request_type=firestore_admin.GetBackupRequest): transport_class = transports.FirestoreAdminRestTransport @@ -12615,6 +15909,42 @@ def test_list_backups_rest(request_type): assert response.unreachable == ["unreachable_value"] +def test_list_backups_rest_use_cached_wrapped_rpc(): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method.wrap_method") as wrapper_fn: + client = FirestoreAdminClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert client._transport.list_backups in client._transport._wrapped_methods + + # Replace cached wrapped function with mock + mock_rpc = mock.Mock() + mock_rpc.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) + client._transport._wrapped_methods[client._transport.list_backups] = mock_rpc + + request = {} + client.list_backups(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + client.list_backups(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 + + def test_list_backups_rest_required_fields( request_type=firestore_admin.ListBackupsRequest, ): @@ -12876,6 +16206,42 @@ def test_delete_backup_rest(request_type): assert response is None +def test_delete_backup_rest_use_cached_wrapped_rpc(): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method.wrap_method") as wrapper_fn: + client = FirestoreAdminClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert client._transport.delete_backup in client._transport._wrapped_methods + + # Replace cached wrapped function with mock + mock_rpc = mock.Mock() + mock_rpc.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) + client._transport._wrapped_methods[client._transport.delete_backup] = mock_rpc + + request = {} + client.delete_backup(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + client.delete_backup(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 + + def test_delete_backup_rest_required_fields( request_type=firestore_admin.DeleteBackupRequest, ): @@ -13124,6 +16490,48 @@ def test_restore_database_rest(request_type): assert response.operation.name == "operations/spam" +def test_restore_database_rest_use_cached_wrapped_rpc(): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method.wrap_method") as wrapper_fn: + client = FirestoreAdminClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert client._transport.restore_database in client._transport._wrapped_methods + + # Replace cached wrapped function with mock + mock_rpc = mock.Mock() + mock_rpc.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) + client._transport._wrapped_methods[ + client._transport.restore_database + ] = mock_rpc + + request = {} + client.restore_database(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + # Operation methods build a cached wrapper on first rpc call + # subsequent calls should use the cached wrapper + wrapper_fn.reset_mock() + + client.restore_database(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 + + def test_restore_database_rest_required_fields( request_type=firestore_admin.RestoreDatabaseRequest, ): @@ -13428,6 +16836,47 @@ def get_message_fields(field): assert response.name == "name_value" +def test_create_backup_schedule_rest_use_cached_wrapped_rpc(): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method.wrap_method") as wrapper_fn: + client = FirestoreAdminClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert ( + client._transport.create_backup_schedule + in client._transport._wrapped_methods + ) + + # Replace cached wrapped function with mock + mock_rpc = mock.Mock() + mock_rpc.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) + client._transport._wrapped_methods[ + client._transport.create_backup_schedule + ] = mock_rpc + + request = {} + client.create_backup_schedule(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + client.create_backup_schedule(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 + + def test_create_backup_schedule_rest_required_fields( request_type=firestore_admin.CreateBackupScheduleRequest, ): @@ -13708,6 +17157,46 @@ def test_get_backup_schedule_rest(request_type): assert response.name == "name_value" +def test_get_backup_schedule_rest_use_cached_wrapped_rpc(): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method.wrap_method") as wrapper_fn: + client = FirestoreAdminClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert ( + client._transport.get_backup_schedule in client._transport._wrapped_methods + ) + + # Replace cached wrapped function with mock + mock_rpc = mock.Mock() + mock_rpc.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) + client._transport._wrapped_methods[ + client._transport.get_backup_schedule + ] = mock_rpc + + request = {} + client.get_backup_schedule(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + client.get_backup_schedule(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 + + def test_get_backup_schedule_rest_required_fields( request_type=firestore_admin.GetBackupScheduleRequest, ): @@ -13976,6 +17465,47 @@ def test_list_backup_schedules_rest(request_type): assert isinstance(response, firestore_admin.ListBackupSchedulesResponse) +def test_list_backup_schedules_rest_use_cached_wrapped_rpc(): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method.wrap_method") as wrapper_fn: + client = FirestoreAdminClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert ( + client._transport.list_backup_schedules + in client._transport._wrapped_methods + ) + + # Replace cached wrapped function with mock + mock_rpc = mock.Mock() + mock_rpc.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) + client._transport._wrapped_methods[ + client._transport.list_backup_schedules + ] = mock_rpc + + request = {} + client.list_backup_schedules(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + client.list_backup_schedules(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 + + def test_list_backup_schedules_rest_required_fields( request_type=firestore_admin.ListBackupSchedulesRequest, ): @@ -14324,6 +17854,47 @@ def get_message_fields(field): assert response.name == "name_value" +def test_update_backup_schedule_rest_use_cached_wrapped_rpc(): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method.wrap_method") as wrapper_fn: + client = FirestoreAdminClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert ( + client._transport.update_backup_schedule + in client._transport._wrapped_methods + ) + + # Replace cached wrapped function with mock + mock_rpc = mock.Mock() + mock_rpc.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) + client._transport._wrapped_methods[ + client._transport.update_backup_schedule + ] = mock_rpc + + request = {} + client.update_backup_schedule(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + client.update_backup_schedule(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 + + def test_update_backup_schedule_rest_required_fields( request_type=firestore_admin.UpdateBackupScheduleRequest, ): @@ -14596,6 +18167,47 @@ def test_delete_backup_schedule_rest(request_type): assert response is None +def test_delete_backup_schedule_rest_use_cached_wrapped_rpc(): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method.wrap_method") as wrapper_fn: + client = FirestoreAdminClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert ( + client._transport.delete_backup_schedule + in client._transport._wrapped_methods + ) + + # Replace cached wrapped function with mock + mock_rpc = mock.Mock() + mock_rpc.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) + client._transport._wrapped_methods[ + client._transport.delete_backup_schedule + ] = mock_rpc + + request = {} + client.delete_backup_schedule(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + client.delete_backup_schedule(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 + + def test_delete_backup_schedule_rest_required_fields( request_type=firestore_admin.DeleteBackupScheduleRequest, ): @@ -14962,6 +18574,7 @@ def test_firestore_admin_base_transport(): "list_fields", "export_documents", "import_documents", + "bulk_delete_documents", "create_database", "get_database", "list_databases", @@ -15299,6 +18912,9 @@ def test_firestore_admin_client_transport_session_collision(transport_name): session1 = client1.transport.import_documents._session session2 = client2.transport.import_documents._session assert session1 != session2 + session1 = client1.transport.bulk_delete_documents._session + session2 = client2.transport.bulk_delete_documents._session + assert session1 != session2 session1 = client1.transport.create_database._session session2 = client2.transport.create_database._session assert session1 != session2 diff --git a/tests/unit/gapic/firestore_v1/test_firestore.py b/tests/unit/gapic/firestore_v1/test_firestore.py index 2cfa0bfda1..ac1e63e854 100644 --- a/tests/unit/gapic/firestore_v1/test_firestore.py +++ b/tests/unit/gapic/firestore_v1/test_firestore.py @@ -22,44 +22,51 @@ except ImportError: # pragma: NO COVER import mock +import grpc +from grpc.experimental import aio +from collections.abc import Iterable +from google.protobuf import json_format import json import math -from collections.abc import Iterable - -import google.auth -import grpc import pytest -from google.api_core import api_core_version, client_options +from google.api_core import api_core_version +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 -from google.api_core import gapic_v1, grpc_helpers, grpc_helpers_async, path_template +from google.api_core import gapic_v1 +from google.api_core import grpc_helpers +from google.api_core import grpc_helpers_async +from google.api_core import path_template +from google.api_core import retry as retries from google.auth import credentials as ga_credentials from google.auth.exceptions import MutualTLSChannelError +from google.cloud.firestore_v1.services.firestore import FirestoreAsyncClient +from google.cloud.firestore_v1.services.firestore import FirestoreClient +from google.cloud.firestore_v1.services.firestore import pagers +from google.cloud.firestore_v1.services.firestore import transports +from google.cloud.firestore_v1.types import aggregation_result +from google.cloud.firestore_v1.types import common +from google.cloud.firestore_v1.types import document +from google.cloud.firestore_v1.types import document as gf_document +from google.cloud.firestore_v1.types import firestore +from google.cloud.firestore_v1.types import query +from google.cloud.firestore_v1.types import query_profile +from google.cloud.firestore_v1.types import write as gf_write from google.cloud.location import locations_pb2 from google.longrunning import operations_pb2 # type: ignore from google.oauth2 import service_account from google.protobuf import struct_pb2 # type: ignore from google.protobuf import timestamp_pb2 # type: ignore from google.protobuf import wrappers_pb2 # type: ignore -from google.protobuf import json_format from google.rpc import status_pb2 # type: ignore from google.type import latlng_pb2 # type: ignore -from grpc.experimental import aio -from proto.marshal.rules import wrappers -from proto.marshal.rules.dates import DurationRule, TimestampRule -from requests import PreparedRequest, Request, Response -from requests.sessions import Session - -from google.cloud.firestore_v1.services.firestore import ( - FirestoreAsyncClient, - FirestoreClient, - pagers, - transports, -) -from google.cloud.firestore_v1.types import aggregation_result, common -from google.cloud.firestore_v1.types import document -from google.cloud.firestore_v1.types import document as gf_document -from google.cloud.firestore_v1.types import firestore, query, query_profile -from google.cloud.firestore_v1.types import write as gf_write +import google.auth def client_cert_source_callback(): @@ -1131,6 +1138,9 @@ def test_get_document_empty_call(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.get_document), "__call__") as call: + call.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) client.get_document() call.assert_called() _, args, _ = call.mock_calls[0] @@ -1154,6 +1164,9 @@ def test_get_document_non_empty_request_with_auto_populated_field(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.get_document), "__call__") as call: + call.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) client.get_document(request=request) call.assert_called() _, args, _ = call.mock_calls[0] @@ -1162,6 +1175,41 @@ def test_get_document_non_empty_request_with_auto_populated_field(): ) +def test_get_document_use_cached_wrapped_rpc(): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method.wrap_method") as wrapper_fn: + client = FirestoreClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="grpc", + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert client._transport.get_document in client._transport._wrapped_methods + + # Replace cached wrapped function with mock + mock_rpc = mock.Mock() + mock_rpc.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) + client._transport._wrapped_methods[client._transport.get_document] = mock_rpc + request = {} + client.get_document(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + client.get_document(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 + + @pytest.mark.asyncio async def test_get_document_empty_call_async(): # This test is a coverage failsafe to make sure that totally empty calls, @@ -1185,6 +1233,48 @@ async def test_get_document_empty_call_async(): assert args[0] == firestore.GetDocumentRequest() +@pytest.mark.asyncio +async def test_get_document_async_use_cached_wrapped_rpc( + transport: str = "grpc_asyncio", +): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method_async.wrap_method") as wrapper_fn: + client = FirestoreAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert ( + client._client._transport.get_document + in client._client._transport._wrapped_methods + ) + + # Replace cached wrapped function with mock + mock_rpc = mock.AsyncMock() + mock_rpc.return_value = mock.Mock() + client._client._transport._wrapped_methods[ + client._client._transport.get_document + ] = mock_rpc + + request = {} + await client.get_document(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + await client.get_document(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 + + @pytest.mark.asyncio async def test_get_document_async( transport: str = "grpc_asyncio", request_type=firestore.GetDocumentRequest @@ -1329,6 +1419,9 @@ def test_list_documents_empty_call(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.list_documents), "__call__") as call: + call.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) client.list_documents() call.assert_called() _, args, _ = call.mock_calls[0] @@ -1355,6 +1448,9 @@ def test_list_documents_non_empty_request_with_auto_populated_field(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.list_documents), "__call__") as call: + call.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) client.list_documents(request=request) call.assert_called() _, args, _ = call.mock_calls[0] @@ -1366,6 +1462,41 @@ def test_list_documents_non_empty_request_with_auto_populated_field(): ) +def test_list_documents_use_cached_wrapped_rpc(): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method.wrap_method") as wrapper_fn: + client = FirestoreClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="grpc", + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert client._transport.list_documents in client._transport._wrapped_methods + + # Replace cached wrapped function with mock + mock_rpc = mock.Mock() + mock_rpc.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) + client._transport._wrapped_methods[client._transport.list_documents] = mock_rpc + request = {} + client.list_documents(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + client.list_documents(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 + + @pytest.mark.asyncio async def test_list_documents_empty_call_async(): # This test is a coverage failsafe to make sure that totally empty calls, @@ -1389,6 +1520,48 @@ async def test_list_documents_empty_call_async(): assert args[0] == firestore.ListDocumentsRequest() +@pytest.mark.asyncio +async def test_list_documents_async_use_cached_wrapped_rpc( + transport: str = "grpc_asyncio", +): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method_async.wrap_method") as wrapper_fn: + client = FirestoreAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert ( + client._client._transport.list_documents + in client._client._transport._wrapped_methods + ) + + # Replace cached wrapped function with mock + mock_rpc = mock.AsyncMock() + mock_rpc.return_value = mock.Mock() + client._client._transport._wrapped_methods[ + client._client._transport.list_documents + ] = mock_rpc + + request = {} + await client.list_documents(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + await client.list_documents(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 + + @pytest.mark.asyncio async def test_list_documents_async( transport: str = "grpc_asyncio", request_type=firestore.ListDocumentsRequest @@ -1528,8 +1701,10 @@ def test_list_documents_pager(transport_name: str = "grpc"): RuntimeError, ) - metadata = () - metadata = tuple(metadata) + ( + expected_metadata = () + retry = retries.Retry() + timeout = 5 + expected_metadata = tuple(expected_metadata) + ( gapic_v1.routing_header.to_grpc_metadata( ( ("parent", ""), @@ -1537,9 +1712,11 @@ def test_list_documents_pager(transport_name: str = "grpc"): ) ), ) - pager = client.list_documents(request={}) + pager = client.list_documents(request={}, retry=retry, timeout=timeout) - assert pager._metadata == metadata + assert pager._metadata == expected_metadata + assert pager._retry == retry + assert pager._timeout == timeout results = list(pager) assert len(results) == 6 @@ -1732,6 +1909,9 @@ def test_update_document_empty_call(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.update_document), "__call__") as call: + call.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) client.update_document() call.assert_called() _, args, _ = call.mock_calls[0] @@ -1753,12 +1933,50 @@ def test_update_document_non_empty_request_with_auto_populated_field(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.update_document), "__call__") as call: + call.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) client.update_document(request=request) call.assert_called() _, args, _ = call.mock_calls[0] assert args[0] == firestore.UpdateDocumentRequest() +def test_update_document_use_cached_wrapped_rpc(): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method.wrap_method") as wrapper_fn: + client = FirestoreClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="grpc", + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert client._transport.update_document in client._transport._wrapped_methods + + # Replace cached wrapped function with mock + mock_rpc = mock.Mock() + mock_rpc.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) + client._transport._wrapped_methods[client._transport.update_document] = mock_rpc + request = {} + client.update_document(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + client.update_document(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 + + @pytest.mark.asyncio async def test_update_document_empty_call_async(): # This test is a coverage failsafe to make sure that totally empty calls, @@ -1782,6 +2000,48 @@ async def test_update_document_empty_call_async(): assert args[0] == firestore.UpdateDocumentRequest() +@pytest.mark.asyncio +async def test_update_document_async_use_cached_wrapped_rpc( + transport: str = "grpc_asyncio", +): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method_async.wrap_method") as wrapper_fn: + client = FirestoreAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert ( + client._client._transport.update_document + in client._client._transport._wrapped_methods + ) + + # Replace cached wrapped function with mock + mock_rpc = mock.AsyncMock() + mock_rpc.return_value = mock.Mock() + client._client._transport._wrapped_methods[ + client._client._transport.update_document + ] = mock_rpc + + request = {} + await client.update_document(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + await client.update_document(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 + + @pytest.mark.asyncio async def test_update_document_async( transport: str = "grpc_asyncio", request_type=firestore.UpdateDocumentRequest @@ -2017,6 +2277,9 @@ def test_delete_document_empty_call(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.delete_document), "__call__") as call: + call.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) client.delete_document() call.assert_called() _, args, _ = call.mock_calls[0] @@ -2040,6 +2303,9 @@ def test_delete_document_non_empty_request_with_auto_populated_field(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.delete_document), "__call__") as call: + call.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) client.delete_document(request=request) call.assert_called() _, args, _ = call.mock_calls[0] @@ -2048,6 +2314,41 @@ def test_delete_document_non_empty_request_with_auto_populated_field(): ) +def test_delete_document_use_cached_wrapped_rpc(): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method.wrap_method") as wrapper_fn: + client = FirestoreClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="grpc", + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert client._transport.delete_document in client._transport._wrapped_methods + + # Replace cached wrapped function with mock + mock_rpc = mock.Mock() + mock_rpc.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) + client._transport._wrapped_methods[client._transport.delete_document] = mock_rpc + request = {} + client.delete_document(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + client.delete_document(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 + + @pytest.mark.asyncio async def test_delete_document_empty_call_async(): # This test is a coverage failsafe to make sure that totally empty calls, @@ -2067,6 +2368,48 @@ async def test_delete_document_empty_call_async(): assert args[0] == firestore.DeleteDocumentRequest() +@pytest.mark.asyncio +async def test_delete_document_async_use_cached_wrapped_rpc( + transport: str = "grpc_asyncio", +): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method_async.wrap_method") as wrapper_fn: + client = FirestoreAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert ( + client._client._transport.delete_document + in client._client._transport._wrapped_methods + ) + + # Replace cached wrapped function with mock + mock_rpc = mock.AsyncMock() + mock_rpc.return_value = mock.Mock() + client._client._transport._wrapped_methods[ + client._client._transport.delete_document + ] = mock_rpc + + request = {} + await client.delete_document(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + await client.delete_document(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 + + @pytest.mark.asyncio async def test_delete_document_async( transport: str = "grpc_asyncio", request_type=firestore.DeleteDocumentRequest @@ -2288,6 +2631,9 @@ def test_batch_get_documents_empty_call(): with mock.patch.object( type(client.transport.batch_get_documents), "__call__" ) as call: + call.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) client.batch_get_documents() call.assert_called() _, args, _ = call.mock_calls[0] @@ -2313,6 +2659,9 @@ def test_batch_get_documents_non_empty_request_with_auto_populated_field(): with mock.patch.object( type(client.transport.batch_get_documents), "__call__" ) as call: + call.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) client.batch_get_documents(request=request) call.assert_called() _, args, _ = call.mock_calls[0] @@ -2321,6 +2670,45 @@ def test_batch_get_documents_non_empty_request_with_auto_populated_field(): ) +def test_batch_get_documents_use_cached_wrapped_rpc(): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method.wrap_method") as wrapper_fn: + client = FirestoreClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="grpc", + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert ( + client._transport.batch_get_documents in client._transport._wrapped_methods + ) + + # Replace cached wrapped function with mock + mock_rpc = mock.Mock() + mock_rpc.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) + client._transport._wrapped_methods[ + client._transport.batch_get_documents + ] = mock_rpc + request = {} + client.batch_get_documents(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + client.batch_get_documents(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 + + @pytest.mark.asyncio async def test_batch_get_documents_empty_call_async(): # This test is a coverage failsafe to make sure that totally empty calls, @@ -2345,6 +2733,48 @@ async def test_batch_get_documents_empty_call_async(): assert args[0] == firestore.BatchGetDocumentsRequest() +@pytest.mark.asyncio +async def test_batch_get_documents_async_use_cached_wrapped_rpc( + transport: str = "grpc_asyncio", +): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method_async.wrap_method") as wrapper_fn: + client = FirestoreAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert ( + client._client._transport.batch_get_documents + in client._client._transport._wrapped_methods + ) + + # Replace cached wrapped function with mock + mock_rpc = mock.AsyncMock() + mock_rpc.return_value = mock.Mock() + client._client._transport._wrapped_methods[ + client._client._transport.batch_get_documents + ] = mock_rpc + + request = {} + await client.batch_get_documents(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + await client.batch_get_documents(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 + + @pytest.mark.asyncio async def test_batch_get_documents_async( transport: str = "grpc_asyncio", request_type=firestore.BatchGetDocumentsRequest @@ -2501,6 +2931,9 @@ def test_begin_transaction_empty_call(): with mock.patch.object( type(client.transport.begin_transaction), "__call__" ) as call: + call.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) client.begin_transaction() call.assert_called() _, args, _ = call.mock_calls[0] @@ -2526,6 +2959,9 @@ def test_begin_transaction_non_empty_request_with_auto_populated_field(): with mock.patch.object( type(client.transport.begin_transaction), "__call__" ) as call: + call.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) client.begin_transaction(request=request) call.assert_called() _, args, _ = call.mock_calls[0] @@ -2534,6 +2970,43 @@ def test_begin_transaction_non_empty_request_with_auto_populated_field(): ) +def test_begin_transaction_use_cached_wrapped_rpc(): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method.wrap_method") as wrapper_fn: + client = FirestoreClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="grpc", + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert client._transport.begin_transaction in client._transport._wrapped_methods + + # Replace cached wrapped function with mock + mock_rpc = mock.Mock() + mock_rpc.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) + client._transport._wrapped_methods[ + client._transport.begin_transaction + ] = mock_rpc + request = {} + client.begin_transaction(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + client.begin_transaction(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 + + @pytest.mark.asyncio async def test_begin_transaction_empty_call_async(): # This test is a coverage failsafe to make sure that totally empty calls, @@ -2559,6 +3032,48 @@ async def test_begin_transaction_empty_call_async(): assert args[0] == firestore.BeginTransactionRequest() +@pytest.mark.asyncio +async def test_begin_transaction_async_use_cached_wrapped_rpc( + transport: str = "grpc_asyncio", +): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method_async.wrap_method") as wrapper_fn: + client = FirestoreAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert ( + client._client._transport.begin_transaction + in client._client._transport._wrapped_methods + ) + + # Replace cached wrapped function with mock + mock_rpc = mock.AsyncMock() + mock_rpc.return_value = mock.Mock() + client._client._transport._wrapped_methods[ + client._client._transport.begin_transaction + ] = mock_rpc + + request = {} + await client.begin_transaction(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + await client.begin_transaction(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 + + @pytest.mark.asyncio async def test_begin_transaction_async( transport: str = "grpc_asyncio", request_type=firestore.BeginTransactionRequest @@ -2794,6 +3309,9 @@ def test_commit_empty_call(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.commit), "__call__") as call: + call.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) client.commit() call.assert_called() _, args, _ = call.mock_calls[0] @@ -2817,6 +3335,9 @@ def test_commit_non_empty_request_with_auto_populated_field(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.commit), "__call__") as call: + call.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) client.commit(request=request) call.assert_called() _, args, _ = call.mock_calls[0] @@ -2825,13 +3346,48 @@ def test_commit_non_empty_request_with_auto_populated_field(): ) -@pytest.mark.asyncio -async def test_commit_empty_call_async(): - # This test is a coverage failsafe to make sure that totally empty calls, - # i.e. request == None and no flattened fields passed, work. - client = FirestoreAsyncClient( - credentials=ga_credentials.AnonymousCredentials(), - transport="grpc_asyncio", +def test_commit_use_cached_wrapped_rpc(): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method.wrap_method") as wrapper_fn: + client = FirestoreClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="grpc", + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert client._transport.commit in client._transport._wrapped_methods + + # Replace cached wrapped function with mock + mock_rpc = mock.Mock() + mock_rpc.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) + client._transport._wrapped_methods[client._transport.commit] = mock_rpc + request = {} + client.commit(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + client.commit(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 + + +@pytest.mark.asyncio +async def test_commit_empty_call_async(): + # This test is a coverage failsafe to make sure that totally empty calls, + # i.e. request == None and no flattened fields passed, work. + client = FirestoreAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="grpc_asyncio", ) # Mock the actual call within the gRPC stub, and fake the request. @@ -2846,6 +3402,46 @@ async def test_commit_empty_call_async(): assert args[0] == firestore.CommitRequest() +@pytest.mark.asyncio +async def test_commit_async_use_cached_wrapped_rpc(transport: str = "grpc_asyncio"): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method_async.wrap_method") as wrapper_fn: + client = FirestoreAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert ( + client._client._transport.commit + in client._client._transport._wrapped_methods + ) + + # Replace cached wrapped function with mock + mock_rpc = mock.AsyncMock() + mock_rpc.return_value = mock.Mock() + client._client._transport._wrapped_methods[ + client._client._transport.commit + ] = mock_rpc + + request = {} + await client.commit(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + await client.commit(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 + + @pytest.mark.asyncio async def test_commit_async( transport: str = "grpc_asyncio", request_type=firestore.CommitRequest @@ -3078,6 +3674,9 @@ def test_rollback_empty_call(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.rollback), "__call__") as call: + call.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) client.rollback() call.assert_called() _, args, _ = call.mock_calls[0] @@ -3101,6 +3700,9 @@ def test_rollback_non_empty_request_with_auto_populated_field(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.rollback), "__call__") as call: + call.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) client.rollback(request=request) call.assert_called() _, args, _ = call.mock_calls[0] @@ -3109,6 +3711,41 @@ def test_rollback_non_empty_request_with_auto_populated_field(): ) +def test_rollback_use_cached_wrapped_rpc(): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method.wrap_method") as wrapper_fn: + client = FirestoreClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="grpc", + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert client._transport.rollback in client._transport._wrapped_methods + + # Replace cached wrapped function with mock + mock_rpc = mock.Mock() + mock_rpc.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) + client._transport._wrapped_methods[client._transport.rollback] = mock_rpc + request = {} + client.rollback(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + client.rollback(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 + + @pytest.mark.asyncio async def test_rollback_empty_call_async(): # This test is a coverage failsafe to make sure that totally empty calls, @@ -3128,6 +3765,46 @@ async def test_rollback_empty_call_async(): assert args[0] == firestore.RollbackRequest() +@pytest.mark.asyncio +async def test_rollback_async_use_cached_wrapped_rpc(transport: str = "grpc_asyncio"): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method_async.wrap_method") as wrapper_fn: + client = FirestoreAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert ( + client._client._transport.rollback + in client._client._transport._wrapped_methods + ) + + # Replace cached wrapped function with mock + mock_rpc = mock.AsyncMock() + mock_rpc.return_value = mock.Mock() + client._client._transport._wrapped_methods[ + client._client._transport.rollback + ] = mock_rpc + + request = {} + await client.rollback(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + await client.rollback(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 + + @pytest.mark.asyncio async def test_rollback_async( transport: str = "grpc_asyncio", request_type=firestore.RollbackRequest @@ -3355,6 +4032,9 @@ def test_run_query_empty_call(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.run_query), "__call__") as call: + call.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) client.run_query() call.assert_called() _, args, _ = call.mock_calls[0] @@ -3378,6 +4058,9 @@ def test_run_query_non_empty_request_with_auto_populated_field(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.run_query), "__call__") as call: + call.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) client.run_query(request=request) call.assert_called() _, args, _ = call.mock_calls[0] @@ -3386,6 +4069,41 @@ def test_run_query_non_empty_request_with_auto_populated_field(): ) +def test_run_query_use_cached_wrapped_rpc(): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method.wrap_method") as wrapper_fn: + client = FirestoreClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="grpc", + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert client._transport.run_query in client._transport._wrapped_methods + + # Replace cached wrapped function with mock + mock_rpc = mock.Mock() + mock_rpc.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) + client._transport._wrapped_methods[client._transport.run_query] = mock_rpc + request = {} + client.run_query(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + client.run_query(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 + + @pytest.mark.asyncio async def test_run_query_empty_call_async(): # This test is a coverage failsafe to make sure that totally empty calls, @@ -3408,6 +4126,46 @@ async def test_run_query_empty_call_async(): assert args[0] == firestore.RunQueryRequest() +@pytest.mark.asyncio +async def test_run_query_async_use_cached_wrapped_rpc(transport: str = "grpc_asyncio"): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method_async.wrap_method") as wrapper_fn: + client = FirestoreAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert ( + client._client._transport.run_query + in client._client._transport._wrapped_methods + ) + + # Replace cached wrapped function with mock + mock_rpc = mock.AsyncMock() + mock_rpc.return_value = mock.Mock() + client._client._transport._wrapped_methods[ + client._client._transport.run_query + ] = mock_rpc + + request = {} + await client.run_query(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + await client.run_query(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 + + @pytest.mark.asyncio async def test_run_query_async( transport: str = "grpc_asyncio", request_type=firestore.RunQueryRequest @@ -3556,6 +4314,9 @@ def test_run_aggregation_query_empty_call(): with mock.patch.object( type(client.transport.run_aggregation_query), "__call__" ) as call: + call.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) client.run_aggregation_query() call.assert_called() _, args, _ = call.mock_calls[0] @@ -3581,6 +4342,9 @@ def test_run_aggregation_query_non_empty_request_with_auto_populated_field(): with mock.patch.object( type(client.transport.run_aggregation_query), "__call__" ) as call: + call.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) client.run_aggregation_query(request=request) call.assert_called() _, args, _ = call.mock_calls[0] @@ -3589,6 +4353,46 @@ def test_run_aggregation_query_non_empty_request_with_auto_populated_field(): ) +def test_run_aggregation_query_use_cached_wrapped_rpc(): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method.wrap_method") as wrapper_fn: + client = FirestoreClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="grpc", + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert ( + client._transport.run_aggregation_query + in client._transport._wrapped_methods + ) + + # Replace cached wrapped function with mock + mock_rpc = mock.Mock() + mock_rpc.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) + client._transport._wrapped_methods[ + client._transport.run_aggregation_query + ] = mock_rpc + request = {} + client.run_aggregation_query(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + client.run_aggregation_query(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 + + @pytest.mark.asyncio async def test_run_aggregation_query_empty_call_async(): # This test is a coverage failsafe to make sure that totally empty calls, @@ -3613,6 +4417,48 @@ async def test_run_aggregation_query_empty_call_async(): assert args[0] == firestore.RunAggregationQueryRequest() +@pytest.mark.asyncio +async def test_run_aggregation_query_async_use_cached_wrapped_rpc( + transport: str = "grpc_asyncio", +): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method_async.wrap_method") as wrapper_fn: + client = FirestoreAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert ( + client._client._transport.run_aggregation_query + in client._client._transport._wrapped_methods + ) + + # Replace cached wrapped function with mock + mock_rpc = mock.AsyncMock() + mock_rpc.return_value = mock.Mock() + client._client._transport._wrapped_methods[ + client._client._transport.run_aggregation_query + ] = mock_rpc + + request = {} + await client.run_aggregation_query(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + await client.run_aggregation_query(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 + + @pytest.mark.asyncio async def test_run_aggregation_query_async( transport: str = "grpc_asyncio", request_type=firestore.RunAggregationQueryRequest @@ -3765,6 +4611,9 @@ def test_partition_query_empty_call(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.partition_query), "__call__") as call: + call.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) client.partition_query() call.assert_called() _, args, _ = call.mock_calls[0] @@ -3789,6 +4638,9 @@ def test_partition_query_non_empty_request_with_auto_populated_field(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.partition_query), "__call__") as call: + call.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) client.partition_query(request=request) call.assert_called() _, args, _ = call.mock_calls[0] @@ -3798,6 +4650,41 @@ def test_partition_query_non_empty_request_with_auto_populated_field(): ) +def test_partition_query_use_cached_wrapped_rpc(): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method.wrap_method") as wrapper_fn: + client = FirestoreClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="grpc", + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert client._transport.partition_query in client._transport._wrapped_methods + + # Replace cached wrapped function with mock + mock_rpc = mock.Mock() + mock_rpc.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) + client._transport._wrapped_methods[client._transport.partition_query] = mock_rpc + request = {} + client.partition_query(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + client.partition_query(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 + + @pytest.mark.asyncio async def test_partition_query_empty_call_async(): # This test is a coverage failsafe to make sure that totally empty calls, @@ -3821,6 +4708,48 @@ async def test_partition_query_empty_call_async(): assert args[0] == firestore.PartitionQueryRequest() +@pytest.mark.asyncio +async def test_partition_query_async_use_cached_wrapped_rpc( + transport: str = "grpc_asyncio", +): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method_async.wrap_method") as wrapper_fn: + client = FirestoreAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert ( + client._client._transport.partition_query + in client._client._transport._wrapped_methods + ) + + # Replace cached wrapped function with mock + mock_rpc = mock.AsyncMock() + mock_rpc.return_value = mock.Mock() + client._client._transport._wrapped_methods[ + client._client._transport.partition_query + ] = mock_rpc + + request = {} + await client.partition_query(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + await client.partition_query(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 + + @pytest.mark.asyncio async def test_partition_query_async( transport: str = "grpc_asyncio", request_type=firestore.PartitionQueryRequest @@ -3958,13 +4887,17 @@ def test_partition_query_pager(transport_name: str = "grpc"): RuntimeError, ) - metadata = () - metadata = tuple(metadata) + ( + expected_metadata = () + retry = retries.Retry() + timeout = 5 + expected_metadata = tuple(expected_metadata) + ( gapic_v1.routing_header.to_grpc_metadata((("parent", ""),)), ) - pager = client.partition_query(request={}) + pager = client.partition_query(request={}, retry=retry, timeout=timeout) - assert pager._metadata == metadata + assert pager._metadata == expected_metadata + assert pager._retry == retry + assert pager._timeout == timeout results = list(pager) assert len(results) == 6 @@ -4145,6 +5078,81 @@ def test_write(request_type, transport: str = "grpc"): assert isinstance(message, firestore.WriteResponse) +def test_write_use_cached_wrapped_rpc(): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method.wrap_method") as wrapper_fn: + client = FirestoreClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="grpc", + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert client._transport.write in client._transport._wrapped_methods + + # Replace cached wrapped function with mock + mock_rpc = mock.Mock() + mock_rpc.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) + client._transport._wrapped_methods[client._transport.write] = mock_rpc + request = [{}] + client.write(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + client.write(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 + + +@pytest.mark.asyncio +async def test_write_async_use_cached_wrapped_rpc(transport: str = "grpc_asyncio"): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method_async.wrap_method") as wrapper_fn: + client = FirestoreAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert ( + client._client._transport.write + in client._client._transport._wrapped_methods + ) + + # Replace cached wrapped function with mock + mock_rpc = mock.AsyncMock() + mock_rpc.return_value = mock.Mock() + client._client._transport._wrapped_methods[ + client._client._transport.write + ] = mock_rpc + + request = [{}] + await client.write(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + await client.write(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 + + @pytest.mark.asyncio async def test_write_async( transport: str = "grpc_asyncio", request_type=firestore.WriteRequest @@ -4215,6 +5223,81 @@ def test_listen(request_type, transport: str = "grpc"): assert isinstance(message, firestore.ListenResponse) +def test_listen_use_cached_wrapped_rpc(): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method.wrap_method") as wrapper_fn: + client = FirestoreClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="grpc", + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert client._transport.listen in client._transport._wrapped_methods + + # Replace cached wrapped function with mock + mock_rpc = mock.Mock() + mock_rpc.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) + client._transport._wrapped_methods[client._transport.listen] = mock_rpc + request = [{}] + client.listen(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + client.listen(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 + + +@pytest.mark.asyncio +async def test_listen_async_use_cached_wrapped_rpc(transport: str = "grpc_asyncio"): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method_async.wrap_method") as wrapper_fn: + client = FirestoreAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert ( + client._client._transport.listen + in client._client._transport._wrapped_methods + ) + + # Replace cached wrapped function with mock + mock_rpc = mock.AsyncMock() + mock_rpc.return_value = mock.Mock() + client._client._transport._wrapped_methods[ + client._client._transport.listen + ] = mock_rpc + + request = [{}] + await client.listen(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + await client.listen(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 + + @pytest.mark.asyncio async def test_listen_async( transport: str = "grpc_asyncio", request_type=firestore.ListenRequest @@ -4305,6 +5388,9 @@ def test_list_collection_ids_empty_call(): with mock.patch.object( type(client.transport.list_collection_ids), "__call__" ) as call: + call.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) client.list_collection_ids() call.assert_called() _, args, _ = call.mock_calls[0] @@ -4331,6 +5417,9 @@ def test_list_collection_ids_non_empty_request_with_auto_populated_field(): with mock.patch.object( type(client.transport.list_collection_ids), "__call__" ) as call: + call.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) client.list_collection_ids(request=request) call.assert_called() _, args, _ = call.mock_calls[0] @@ -4340,6 +5429,45 @@ def test_list_collection_ids_non_empty_request_with_auto_populated_field(): ) +def test_list_collection_ids_use_cached_wrapped_rpc(): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method.wrap_method") as wrapper_fn: + client = FirestoreClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="grpc", + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert ( + client._transport.list_collection_ids in client._transport._wrapped_methods + ) + + # Replace cached wrapped function with mock + mock_rpc = mock.Mock() + mock_rpc.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) + client._transport._wrapped_methods[ + client._transport.list_collection_ids + ] = mock_rpc + request = {} + client.list_collection_ids(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + client.list_collection_ids(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 + + @pytest.mark.asyncio async def test_list_collection_ids_empty_call_async(): # This test is a coverage failsafe to make sure that totally empty calls, @@ -4366,6 +5494,48 @@ async def test_list_collection_ids_empty_call_async(): assert args[0] == firestore.ListCollectionIdsRequest() +@pytest.mark.asyncio +async def test_list_collection_ids_async_use_cached_wrapped_rpc( + transport: str = "grpc_asyncio", +): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method_async.wrap_method") as wrapper_fn: + client = FirestoreAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert ( + client._client._transport.list_collection_ids + in client._client._transport._wrapped_methods + ) + + # Replace cached wrapped function with mock + mock_rpc = mock.AsyncMock() + mock_rpc.return_value = mock.Mock() + client._client._transport._wrapped_methods[ + client._client._transport.list_collection_ids + ] = mock_rpc + + request = {} + await client.list_collection_ids(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + await client.list_collection_ids(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 + + @pytest.mark.asyncio async def test_list_collection_ids_async( transport: str = "grpc_asyncio", request_type=firestore.ListCollectionIdsRequest @@ -4599,13 +5769,17 @@ def test_list_collection_ids_pager(transport_name: str = "grpc"): RuntimeError, ) - metadata = () - metadata = tuple(metadata) + ( + expected_metadata = () + retry = retries.Retry() + timeout = 5 + expected_metadata = tuple(expected_metadata) + ( gapic_v1.routing_header.to_grpc_metadata((("parent", ""),)), ) - pager = client.list_collection_ids(request={}) + pager = client.list_collection_ids(request={}, retry=retry, timeout=timeout) - assert pager._metadata == metadata + assert pager._metadata == expected_metadata + assert pager._retry == retry + assert pager._timeout == timeout results = list(pager) assert len(results) == 6 @@ -4801,6 +5975,9 @@ def test_batch_write_empty_call(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.batch_write), "__call__") as call: + call.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) client.batch_write() call.assert_called() _, args, _ = call.mock_calls[0] @@ -4824,6 +6001,9 @@ def test_batch_write_non_empty_request_with_auto_populated_field(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.batch_write), "__call__") as call: + call.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) client.batch_write(request=request) call.assert_called() _, args, _ = call.mock_calls[0] @@ -4832,6 +6012,41 @@ def test_batch_write_non_empty_request_with_auto_populated_field(): ) +def test_batch_write_use_cached_wrapped_rpc(): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method.wrap_method") as wrapper_fn: + client = FirestoreClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="grpc", + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert client._transport.batch_write in client._transport._wrapped_methods + + # Replace cached wrapped function with mock + mock_rpc = mock.Mock() + mock_rpc.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) + client._transport._wrapped_methods[client._transport.batch_write] = mock_rpc + request = {} + client.batch_write(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + client.batch_write(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 + + @pytest.mark.asyncio async def test_batch_write_empty_call_async(): # This test is a coverage failsafe to make sure that totally empty calls, @@ -4853,6 +6068,48 @@ async def test_batch_write_empty_call_async(): assert args[0] == firestore.BatchWriteRequest() +@pytest.mark.asyncio +async def test_batch_write_async_use_cached_wrapped_rpc( + transport: str = "grpc_asyncio", +): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method_async.wrap_method") as wrapper_fn: + client = FirestoreAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert ( + client._client._transport.batch_write + in client._client._transport._wrapped_methods + ) + + # Replace cached wrapped function with mock + mock_rpc = mock.AsyncMock() + mock_rpc.return_value = mock.Mock() + client._client._transport._wrapped_methods[ + client._client._transport.batch_write + ] = mock_rpc + + request = {} + await client.batch_write(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + await client.batch_write(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 + + @pytest.mark.asyncio async def test_batch_write_async( transport: str = "grpc_asyncio", request_type=firestore.BatchWriteRequest @@ -4996,6 +6253,9 @@ def test_create_document_empty_call(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.create_document), "__call__") as call: + call.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) client.create_document() call.assert_called() _, args, _ = call.mock_calls[0] @@ -5021,6 +6281,9 @@ def test_create_document_non_empty_request_with_auto_populated_field(): # Mock the actual call within the gRPC stub, and fake the request. with mock.patch.object(type(client.transport.create_document), "__call__") as call: + call.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) client.create_document(request=request) call.assert_called() _, args, _ = call.mock_calls[0] @@ -5031,6 +6294,41 @@ def test_create_document_non_empty_request_with_auto_populated_field(): ) +def test_create_document_use_cached_wrapped_rpc(): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method.wrap_method") as wrapper_fn: + client = FirestoreClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="grpc", + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert client._transport.create_document in client._transport._wrapped_methods + + # Replace cached wrapped function with mock + mock_rpc = mock.Mock() + mock_rpc.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) + client._transport._wrapped_methods[client._transport.create_document] = mock_rpc + request = {} + client.create_document(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + client.create_document(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 + + @pytest.mark.asyncio async def test_create_document_empty_call_async(): # This test is a coverage failsafe to make sure that totally empty calls, @@ -5054,6 +6352,48 @@ async def test_create_document_empty_call_async(): assert args[0] == firestore.CreateDocumentRequest() +@pytest.mark.asyncio +async def test_create_document_async_use_cached_wrapped_rpc( + transport: str = "grpc_asyncio", +): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method_async.wrap_method") as wrapper_fn: + client = FirestoreAsyncClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert ( + client._client._transport.create_document + in client._client._transport._wrapped_methods + ) + + # Replace cached wrapped function with mock + mock_rpc = mock.AsyncMock() + mock_rpc.return_value = mock.Mock() + client._client._transport._wrapped_methods[ + client._client._transport.create_document + ] = mock_rpc + + request = {} + await client.create_document(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + await client.create_document(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 + + @pytest.mark.asyncio async def test_create_document_async( transport: str = "grpc_asyncio", request_type=firestore.CreateDocumentRequest @@ -5196,6 +6536,42 @@ def test_get_document_rest(request_type): assert response.name == "name_value" +def test_get_document_rest_use_cached_wrapped_rpc(): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method.wrap_method") as wrapper_fn: + client = FirestoreClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert client._transport.get_document in client._transport._wrapped_methods + + # Replace cached wrapped function with mock + mock_rpc = mock.Mock() + mock_rpc.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) + client._transport._wrapped_methods[client._transport.get_document] = mock_rpc + + request = {} + client.get_document(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + client.get_document(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 + + def test_get_document_rest_required_fields(request_type=firestore.GetDocumentRequest): transport_class = transports.FirestoreRestTransport @@ -5420,6 +6796,42 @@ def test_list_documents_rest(request_type): assert response.next_page_token == "next_page_token_value" +def test_list_documents_rest_use_cached_wrapped_rpc(): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method.wrap_method") as wrapper_fn: + client = FirestoreClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert client._transport.list_documents in client._transport._wrapped_methods + + # Replace cached wrapped function with mock + mock_rpc = mock.Mock() + mock_rpc.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) + client._transport._wrapped_methods[client._transport.list_documents] = mock_rpc + + request = {} + client.list_documents(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + client.list_documents(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 + + def test_list_documents_rest_required_fields( request_type=firestore.ListDocumentsRequest, ): @@ -5789,6 +7201,42 @@ def get_message_fields(field): assert response.name == "name_value" +def test_update_document_rest_use_cached_wrapped_rpc(): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method.wrap_method") as wrapper_fn: + client = FirestoreClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert client._transport.update_document in client._transport._wrapped_methods + + # Replace cached wrapped function with mock + mock_rpc = mock.Mock() + mock_rpc.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) + client._transport._wrapped_methods[client._transport.update_document] = mock_rpc + + request = {} + client.update_document(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + client.update_document(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 + + def test_update_document_rest_required_fields( request_type=firestore.UpdateDocumentRequest, ): @@ -6072,6 +7520,42 @@ def test_delete_document_rest(request_type): assert response is None +def test_delete_document_rest_use_cached_wrapped_rpc(): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method.wrap_method") as wrapper_fn: + client = FirestoreClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert client._transport.delete_document in client._transport._wrapped_methods + + # Replace cached wrapped function with mock + mock_rpc = mock.Mock() + mock_rpc.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) + client._transport._wrapped_methods[client._transport.delete_document] = mock_rpc + + request = {} + client.delete_document(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + client.delete_document(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 + + def test_delete_document_rest_required_fields( request_type=firestore.DeleteDocumentRequest, ): @@ -6338,6 +7822,46 @@ def test_batch_get_documents_rest(request_type): assert response.transaction == b"transaction_blob" +def test_batch_get_documents_rest_use_cached_wrapped_rpc(): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method.wrap_method") as wrapper_fn: + client = FirestoreClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert ( + client._transport.batch_get_documents in client._transport._wrapped_methods + ) + + # Replace cached wrapped function with mock + mock_rpc = mock.Mock() + mock_rpc.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) + client._transport._wrapped_methods[ + client._transport.batch_get_documents + ] = mock_rpc + + request = {} + client.batch_get_documents(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + client.batch_get_documents(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 + + def test_batch_get_documents_rest_required_fields( request_type=firestore.BatchGetDocumentsRequest, ): @@ -6551,6 +8075,44 @@ def test_begin_transaction_rest(request_type): assert response.transaction == b"transaction_blob" +def test_begin_transaction_rest_use_cached_wrapped_rpc(): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method.wrap_method") as wrapper_fn: + client = FirestoreClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert client._transport.begin_transaction in client._transport._wrapped_methods + + # Replace cached wrapped function with mock + mock_rpc = mock.Mock() + mock_rpc.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) + client._transport._wrapped_methods[ + client._transport.begin_transaction + ] = mock_rpc + + request = {} + client.begin_transaction(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + client.begin_transaction(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 + + def test_begin_transaction_rest_required_fields( request_type=firestore.BeginTransactionRequest, ): @@ -6814,6 +8376,42 @@ def test_commit_rest(request_type): assert isinstance(response, firestore.CommitResponse) +def test_commit_rest_use_cached_wrapped_rpc(): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method.wrap_method") as wrapper_fn: + client = FirestoreClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert client._transport.commit in client._transport._wrapped_methods + + # Replace cached wrapped function with mock + mock_rpc = mock.Mock() + mock_rpc.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) + client._transport._wrapped_methods[client._transport.commit] = mock_rpc + + request = {} + client.commit(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + client.commit(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 + + def test_commit_rest_required_fields(request_type=firestore.CommitRequest): transport_class = transports.FirestoreRestTransport @@ -7073,6 +8671,42 @@ def test_rollback_rest(request_type): assert response is None +def test_rollback_rest_use_cached_wrapped_rpc(): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method.wrap_method") as wrapper_fn: + client = FirestoreClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert client._transport.rollback in client._transport._wrapped_methods + + # Replace cached wrapped function with mock + mock_rpc = mock.Mock() + mock_rpc.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) + client._transport._wrapped_methods[client._transport.rollback] = mock_rpc + + request = {} + client.rollback(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + client.rollback(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 + + def test_rollback_rest_required_fields(request_type=firestore.RollbackRequest): transport_class = transports.FirestoreRestTransport @@ -7346,6 +8980,42 @@ def test_run_query_rest(request_type): assert response.skipped_results == 1633 +def test_run_query_rest_use_cached_wrapped_rpc(): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method.wrap_method") as wrapper_fn: + client = FirestoreClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert client._transport.run_query in client._transport._wrapped_methods + + # Replace cached wrapped function with mock + mock_rpc = mock.Mock() + mock_rpc.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) + client._transport._wrapped_methods[client._transport.run_query] = mock_rpc + + request = {} + client.run_query(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + client.run_query(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 + + def test_run_query_rest_required_fields(request_type=firestore.RunQueryRequest): transport_class = transports.FirestoreRestTransport @@ -7562,6 +9232,47 @@ def test_run_aggregation_query_rest(request_type): assert response.transaction == b"transaction_blob" +def test_run_aggregation_query_rest_use_cached_wrapped_rpc(): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method.wrap_method") as wrapper_fn: + client = FirestoreClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert ( + client._transport.run_aggregation_query + in client._transport._wrapped_methods + ) + + # Replace cached wrapped function with mock + mock_rpc = mock.Mock() + mock_rpc.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) + client._transport._wrapped_methods[ + client._transport.run_aggregation_query + ] = mock_rpc + + request = {} + client.run_aggregation_query(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + client.run_aggregation_query(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 + + def test_run_aggregation_query_rest_required_fields( request_type=firestore.RunAggregationQueryRequest, ): @@ -7775,6 +9486,42 @@ def test_partition_query_rest(request_type): assert response.next_page_token == "next_page_token_value" +def test_partition_query_rest_use_cached_wrapped_rpc(): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method.wrap_method") as wrapper_fn: + client = FirestoreClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert client._transport.partition_query in client._transport._wrapped_methods + + # Replace cached wrapped function with mock + mock_rpc = mock.Mock() + mock_rpc.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) + client._transport._wrapped_methods[client._transport.partition_query] = mock_rpc + + request = {} + client.partition_query(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + client.partition_query(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 + + def test_partition_query_rest_required_fields( request_type=firestore.PartitionQueryRequest, ): @@ -8063,6 +9810,46 @@ def test_list_collection_ids_rest(request_type): assert response.next_page_token == "next_page_token_value" +def test_list_collection_ids_rest_use_cached_wrapped_rpc(): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method.wrap_method") as wrapper_fn: + client = FirestoreClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert ( + client._transport.list_collection_ids in client._transport._wrapped_methods + ) + + # Replace cached wrapped function with mock + mock_rpc = mock.Mock() + mock_rpc.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) + client._transport._wrapped_methods[ + client._transport.list_collection_ids + ] = mock_rpc + + request = {} + client.list_collection_ids(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + client.list_collection_ids(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 + + def test_list_collection_ids_rest_required_fields( request_type=firestore.ListCollectionIdsRequest, ): @@ -8383,6 +10170,42 @@ def test_batch_write_rest(request_type): assert isinstance(response, firestore.BatchWriteResponse) +def test_batch_write_rest_use_cached_wrapped_rpc(): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method.wrap_method") as wrapper_fn: + client = FirestoreClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert client._transport.batch_write in client._transport._wrapped_methods + + # Replace cached wrapped function with mock + mock_rpc = mock.Mock() + mock_rpc.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) + client._transport._wrapped_methods[client._transport.batch_write] = mock_rpc + + request = {} + client.batch_write(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + client.batch_write(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 + + def test_batch_write_rest_required_fields(request_type=firestore.BatchWriteRequest): transport_class = transports.FirestoreRestTransport @@ -8664,6 +10487,42 @@ def get_message_fields(field): assert response.name == "name_value" +def test_create_document_rest_use_cached_wrapped_rpc(): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method.wrap_method") as wrapper_fn: + client = FirestoreClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert client._transport.create_document in client._transport._wrapped_methods + + # Replace cached wrapped function with mock + mock_rpc = mock.Mock() + mock_rpc.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) + client._transport._wrapped_methods[client._transport.create_document] = mock_rpc + + request = {} + client.create_document(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + client.create_document(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 + + def test_create_document_rest_required_fields( request_type=firestore.CreateDocumentRequest, ):