def test_commit(self, mock_create_stub): # Mock gRPC layer grpc_stub = mock.Mock() mock_create_stub.return_value = grpc_stub client = spanner_v1.SpannerClient() # Mock request session = client.session_path('[PROJECT]', '[INSTANCE]', '[DATABASE]', '[SESSION]') mutations = [] # Mock response expected_response = {} expected_response = spanner_pb2.CommitResponse(**expected_response) grpc_stub.Commit.return_value = expected_response response = client.commit(session, mutations) self.assertEqual(expected_response, response) grpc_stub.Commit.assert_called_once() args, kwargs = grpc_stub.Commit.call_args self.assertEqual(len(args), 2) self.assertEqual(len(kwargs), 1) self.assertIn('metadata', kwargs) actual_request = args[0] expected_request = spanner_pb2.CommitRequest(session=session, mutations=mutations) self.assertEqual(expected_request, actual_request)
def test_commit(self): # Setup Expected Response expected_response = {} expected_response = spanner_pb2.CommitResponse(**expected_response) # Mock the API response channel = ChannelStub(responses=[expected_response]) patch = mock.patch("google.api_core.grpc_helpers.create_channel") with patch as create_channel: create_channel.return_value = channel client = spanner_v1.SpannerClient() # Setup Request session = client.session_path("[PROJECT]", "[INSTANCE]", "[DATABASE]", "[SESSION]") mutations = [] response = client.commit(session, mutations) assert expected_response == response assert len(channel.requests) == 1 expected_request = spanner_pb2.CommitRequest(session=session, mutations=mutations) actual_request = channel.requests[0][1] assert expected_request == actual_request
def _transaction(stub): """Probe to test BeginTransaction, Commit and Rollback grpc from Spanner stub. Args: stub: An object of SpannerStub. """ _transaction_tracer = initialize_tracer() with _transaction_tracer.span(name='_transaction') as root_span: root_span.add_annotation('endpoint info available', endpoint=_SPANNER_TARGET) session = None try: with _transaction_tracer.span(name='stub.CreateSession'): session = stub.CreateSession( spanner_pb2.CreateSessionRequest(database=_DATABASE)) txn_options = transaction_pb2.TransactionOptions( read_write=transaction_pb2.TransactionOptions.ReadWrite()) txn_request = spanner_pb2.BeginTransactionRequest( session=session.name, options=txn_options, ) # Probing BeginTransaction call with _transaction_tracer.span(name='stub.BeginTransaction'): txn = stub.BeginTransaction(txn_request) # Probing Commit call commit_request = spanner_pb2.CommitRequest(session=session.name, transaction_id=txn.id) with _transaction_tracer.span(name='stub.Commit'): stub.Commit(commit_request) # Probing Rollback call txn = stub.BeginTransaction(txn_request) rollback_request = spanner_pb2.RollbackRequest( session=session.name, transaction_id=txn.id) with _transaction_tracer.span(name='stub.Rollback'): stub.Rollback(rollback_request) finally: if session is not None: with _transaction_tracer.span(name='stub.DeleteSession'): stub.DeleteSession( spanner_pb2.DeleteSessionRequest(name=session.name))
def test_commit(self): # Setup Expected Response expected_response = {} expected_response = spanner_pb2.CommitResponse(**expected_response) # Mock the API response channel = ChannelStub(responses=[expected_response]) client = spanner_v1.SpannerClient(channel=channel) # Setup Request session = client.session_path('[PROJECT]', '[INSTANCE]', '[DATABASE]', '[SESSION]') mutations = [] response = client.commit(session, mutations) assert expected_response == response assert len(channel.requests) == 1 expected_request = spanner_pb2.CommitRequest(session=session, mutations=mutations) actual_request = channel.requests[0][1] assert expected_request == actual_request
def commit(self, session, mutations, transaction_id=None, single_use_transaction=None, options=None): """ Commits a transaction. The request includes the mutations to be applied to rows in the database. ``Commit`` might return an ``ABORTED`` error. This can occur at any time; commonly, the cause is conflicts with concurrent transactions. However, it can also happen for a variety of other reasons. If ``Commit`` returns ``ABORTED``, the caller should re-attempt the transaction from the beginning, re-using the same session. Example: >>> from google.cloud import spanner_v1 >>> >>> client = spanner_v1.SpannerClient() >>> >>> session = client.session_path('[PROJECT]', '[INSTANCE]', '[DATABASE]', '[SESSION]') >>> mutations = [] >>> >>> response = client.commit(session, mutations) Args: session (str): Required. The session in which the transaction to be committed is running. mutations (list[Union[dict, ~google.cloud.spanner_v1.types.Mutation]]): The mutations to be executed when this transaction commits. All mutations are applied atomically, in the order they appear in this list. If a dict is provided, it must be of the same form as the protobuf message :class:`~google.cloud.spanner_v1.types.Mutation` transaction_id (bytes): Commit a previously-started transaction. single_use_transaction (Union[dict, ~google.cloud.spanner_v1.types.TransactionOptions]): Execute mutations in a temporary transaction. Note that unlike commit of a previously-started transaction, commit with a temporary transaction is non-idempotent. That is, if the ``CommitRequest`` is sent to Cloud Spanner more than once (for instance, due to retries in the application, or in the transport library), it is possible that the mutations are executed more than once. If this is undesirable, use ``BeginTransaction`` and ``Commit`` instead. If a dict is provided, it must be of the same form as the protobuf message :class:`~google.cloud.spanner_v1.types.TransactionOptions` options (~google.gax.CallOptions): Overrides the default settings for this call, e.g, timeout, retries etc. Returns: A :class:`~google.cloud.spanner_v1.types.CommitResponse` instance. Raises: :exc:`google.gax.errors.GaxError` if the RPC is aborted. :exc:`ValueError` if the parameters are invalid. """ # Sanity check: We have some fields which are mutually exclusive; # raise ValueError if more than one is sent. oneof.check_oneof( transaction_id=transaction_id, single_use_transaction=single_use_transaction, ) request = spanner_pb2.CommitRequest( session=session, mutations=mutations, transaction_id=transaction_id, single_use_transaction=single_use_transaction) return self._commit(request, options)
def commit(self, session, mutations, transaction_id=None, single_use_transaction=None, retry=google.api_core.gapic_v1.method.DEFAULT, timeout=google.api_core.gapic_v1.method.DEFAULT, metadata=None): """ Commits a transaction. The request includes the mutations to be applied to rows in the database. ``Commit`` might return an ``ABORTED`` error. This can occur at any time; commonly, the cause is conflicts with concurrent transactions. However, it can also happen for a variety of other reasons. If ``Commit`` returns ``ABORTED``, the caller should re-attempt the transaction from the beginning, re-using the same session. Example: >>> from google.cloud import spanner_v1 >>> >>> client = spanner_v1.SpannerClient() >>> >>> session = client.session_path('[PROJECT]', '[INSTANCE]', '[DATABASE]', '[SESSION]') >>> mutations = [] >>> >>> response = client.commit(session, mutations) Args: session (str): Required. The session in which the transaction to be committed is running. mutations (list[Union[dict, ~google.cloud.spanner_v1.types.Mutation]]): The mutations to be executed when this transaction commits. All mutations are applied atomically, in the order they appear in this list. If a dict is provided, it must be of the same form as the protobuf message :class:`~google.cloud.spanner_v1.types.Mutation` transaction_id (bytes): Commit a previously-started transaction. single_use_transaction (Union[dict, ~google.cloud.spanner_v1.types.TransactionOptions]): Execute mutations in a temporary transaction. Note that unlike commit of a previously-started transaction, commit with a temporary transaction is non-idempotent. That is, if the ``CommitRequest`` is sent to Cloud Spanner more than once (for instance, due to retries in the application, or in the transport library), it is possible that the mutations are executed more than once. If this is undesirable, use ``BeginTransaction`` and ``Commit`` instead. If a dict is provided, it must be of the same form as the protobuf message :class:`~google.cloud.spanner_v1.types.TransactionOptions` retry (Optional[google.api_core.retry.Retry]): A retry object used to retry requests. If ``None`` is specified, requests will not be retried. timeout (Optional[float]): The amount of time, in seconds, to wait for the request to complete. Note that if ``retry`` is specified, the timeout applies to each individual attempt. Returns: A :class:`~google.cloud.spanner_v1.types.CommitResponse` instance. Raises: google.api_core.exceptions.GoogleAPICallError: If the request failed for any reason. google.api_core.exceptions.RetryError: If the request failed due to a retryable error and retry attempts failed. ValueError: If the parameters are invalid. """ # Sanity check: We have some fields which are mutually exclusive; # raise ValueError if more than one is sent. google.api_core.protobuf_helpers.check_oneof( transaction_id=transaction_id, single_use_transaction=single_use_transaction, ) request = spanner_pb2.CommitRequest( session=session, mutations=mutations, transaction_id=transaction_id, single_use_transaction=single_use_transaction, ) return self._commit( request, retry=retry, timeout=timeout, metadata=metadata)