Ejemplo n.º 1
0
    def test__maybe_commit_failure_can_retry(self):
        from google.api_core import exceptions

        wrapped = self._make_one(mock.sentinel.callable_)

        txn_id = b"failed-but-retry"
        transaction = _make_transaction(txn_id)
        transaction._id = txn_id  # We won't call ``begin()``.
        wrapped.current_id = txn_id  # We won't call ``_pre_commit()``.
        wrapped.retry_id = txn_id  # We won't call ``_pre_commit()``.

        # Actually force the ``commit`` to fail.
        exc = exceptions.Aborted("Read-write did a bad.")
        firestore_api = transaction._client._firestore_api
        firestore_api.commit.side_effect = exc

        succeeded = wrapped._maybe_commit(transaction)
        self.assertFalse(succeeded)

        self.assertEqual(transaction._id, txn_id)
        self.assertEqual(wrapped.current_id, txn_id)
        self.assertEqual(wrapped.retry_id, txn_id)

        # Verify mocks.
        firestore_api.begin_transaction.assert_not_called()
        firestore_api.rollback.assert_not_called()
        firestore_api.commit.assert_called_once_with(
            transaction._client._database_string,
            [],
            transaction=txn_id,
            metadata=transaction._client._rpc_metadata,
        )
Ejemplo n.º 2
0
def test__transactional__maybe_commit_failure_can_retry():
    from google.api_core import exceptions

    wrapped = _make__transactional(mock.sentinel.callable_)

    txn_id = b"failed-but-retry"
    transaction = _make_transaction_pb(txn_id)
    transaction._id = txn_id  # We won't call ``begin()``.
    wrapped.current_id = txn_id  # We won't call ``_pre_commit()``.
    wrapped.retry_id = txn_id  # We won't call ``_pre_commit()``.

    # Actually force the ``commit`` to fail.
    exc = exceptions.Aborted("Read-write did a bad.")
    firestore_api = transaction._client._firestore_api
    firestore_api.commit.side_effect = exc

    succeeded = wrapped._maybe_commit(transaction)
    assert not succeeded

    assert transaction._id == txn_id
    assert wrapped.current_id == txn_id
    assert wrapped.retry_id == txn_id

    # Verify mocks.
    firestore_api.begin_transaction.assert_not_called()
    firestore_api.rollback.assert_not_called()
    firestore_api.commit.assert_called_once_with(
        request={
            "database": transaction._client._database_string,
            "writes": [],
            "transaction": txn_id,
        },
        metadata=transaction._client._rpc_metadata,
    )
Ejemplo n.º 3
0
    def test__maybe_commit_failure_read_only(self):
        from google.api_core import exceptions

        wrapped = self._make_one(mock.sentinel.callable_)

        txn_id = b"failed"
        transaction = _make_transaction(txn_id, read_only=True)
        transaction._id = txn_id  # We won't call ``begin()``.
        wrapped.current_id = txn_id  # We won't call ``_pre_commit()``.
        wrapped.retry_id = txn_id  # We won't call ``_pre_commit()``.

        # Actually force the ``commit`` to fail (use ABORTED, but cannot
        # retry since read-only).
        exc = exceptions.Aborted("Read-only did a bad.")
        firestore_api = transaction._client._firestore_api
        firestore_api.commit.side_effect = exc

        with self.assertRaises(exceptions.Aborted) as exc_info:
            wrapped._maybe_commit(transaction)
        self.assertIs(exc_info.exception, exc)

        self.assertEqual(transaction._id, txn_id)
        self.assertEqual(wrapped.current_id, txn_id)
        self.assertEqual(wrapped.retry_id, txn_id)

        # Verify mocks.
        firestore_api.begin_transaction.assert_not_called()
        firestore_api.rollback.assert_not_called()
        firestore_api.commit.assert_called_once_with(
            transaction._client._database_string,
            [],
            transaction=txn_id,
            metadata=transaction._client._rpc_metadata,
        )
Ejemplo n.º 4
0
    async def test___call__success_second_attempt(self):
        from google.api_core import exceptions
        from google.cloud.firestore_v1.types import common
        from google.cloud.firestore_v1.types import firestore
        from google.cloud.firestore_v1.types import write

        to_wrap = AsyncMock(return_value=mock.sentinel.result, spec=[])
        wrapped = self._make_one(to_wrap)

        txn_id = b"whole-enchilada"
        transaction = _make_transaction(txn_id)

        # Actually force the ``commit`` to fail on first / succeed on second.
        exc = exceptions.Aborted("Contention junction.")
        firestore_api = transaction._client._firestore_api
        firestore_api.commit.side_effect = [
            exc,
            firestore.CommitResponse(write_results=[write.WriteResult()]),
        ]

        # Call the __call__-able ``wrapped``.
        result = await wrapped(transaction, "a", b="c")
        self.assertIs(result, mock.sentinel.result)

        self.assertIsNone(transaction._id)
        self.assertEqual(wrapped.current_id, txn_id)
        self.assertEqual(wrapped.retry_id, txn_id)

        # Verify mocks.
        wrapped_call = mock.call(transaction, "a", b="c")
        self.assertEqual(to_wrap.mock_calls, [wrapped_call, wrapped_call])
        firestore_api = transaction._client._firestore_api
        db_str = transaction._client._database_string
        options_ = common.TransactionOptions(
            read_write=common.TransactionOptions.ReadWrite(retry_transaction=txn_id)
        )
        self.assertEqual(
            firestore_api.begin_transaction.mock_calls,
            [
                mock.call(
                    request={"database": db_str, "options": None},
                    metadata=transaction._client._rpc_metadata,
                ),
                mock.call(
                    request={"database": db_str, "options": options_},
                    metadata=transaction._client._rpc_metadata,
                ),
            ],
        )
        firestore_api.rollback.assert_not_called()
        commit_call = mock.call(
            request={"database": db_str, "writes": [], "transaction": txn_id},
            metadata=transaction._client._rpc_metadata,
        )
        self.assertEqual(firestore_api.commit.mock_calls, [commit_call, commit_call])
Ejemplo n.º 5
0
    def test___call__success_second_attempt(self):
        from google.api_core import exceptions
        from google.cloud.firestore_v1beta1.proto import common_pb2
        from google.cloud.firestore_v1beta1.proto import firestore_pb2
        from google.cloud.firestore_v1beta1.proto import write_pb2

        to_wrap = mock.Mock(return_value=mock.sentinel.result, spec=[])
        wrapped = self._make_one(to_wrap)

        txn_id = b'whole-enchilada'
        transaction = _make_transaction(txn_id)

        # Actually force the ``commit`` to fail on first / succeed on second.
        exc = exceptions.Aborted('Contention junction.')
        firestore_api = transaction._client._firestore_api
        firestore_api.commit.side_effect = [
            exc,
            firestore_pb2.CommitResponse(write_results=[
                write_pb2.WriteResult(),
            ], ),
        ]

        # Call the __call__-able ``wrapped``.
        result = wrapped(transaction, 'a', b='c')
        self.assertIs(result, mock.sentinel.result)

        self.assertIsNone(transaction._id)
        self.assertEqual(wrapped.current_id, txn_id)
        self.assertEqual(wrapped.retry_id, txn_id)

        # Verify mocks.
        wrapped_call = mock.call(transaction, 'a', b='c')
        self.assertEqual(to_wrap.mock_calls, [wrapped_call, wrapped_call])
        firestore_api = transaction._client._firestore_api
        db_str = transaction._client._database_string
        options_ = common_pb2.TransactionOptions(
            read_write=common_pb2.TransactionOptions.ReadWrite(
                retry_transaction=txn_id, ), )
        self.assertEqual(
            firestore_api.begin_transaction.mock_calls,
            [
                mock.call(db_str,
                          options_=None,
                          metadata=transaction._client._rpc_metadata),
                mock.call(db_str,
                          options_=options_,
                          metadata=transaction._client._rpc_metadata),
            ],
        )
        firestore_api.rollback.assert_not_called()
        commit_call = mock.call(db_str, [],
                                transaction=txn_id,
                                metadata=transaction._client._rpc_metadata)
        self.assertEqual(firestore_api.commit.mock_calls,
                         [commit_call, commit_call])
Ejemplo n.º 6
0
    async def test___call__failure(self):
        from google.api_core import exceptions
        from google.cloud.firestore_v1.async_transaction import (
            _EXCEED_ATTEMPTS_TEMPLATE,
        )

        to_wrap = AsyncMock(return_value=mock.sentinel.result, spec=[])
        wrapped = self._make_one(to_wrap)

        txn_id = b"only-one-shot"
        transaction = _make_transaction(txn_id, max_attempts=1)

        # Actually force the ``commit`` to fail.
        exc = exceptions.Aborted("Contention just once.")
        firestore_api = transaction._client._firestore_api
        firestore_api.commit.side_effect = exc

        # Call the __call__-able ``wrapped``.
        with self.assertRaises(ValueError) as exc_info:
            await wrapped(transaction, "here", there=1.5)

        err_msg = _EXCEED_ATTEMPTS_TEMPLATE.format(transaction._max_attempts)
        self.assertEqual(exc_info.exception.args, (err_msg,))

        self.assertIsNone(transaction._id)
        self.assertEqual(wrapped.current_id, txn_id)
        self.assertEqual(wrapped.retry_id, txn_id)

        # Verify mocks.
        to_wrap.assert_called_once_with(transaction, "here", there=1.5)
        firestore_api.begin_transaction.assert_called_once_with(
            request={
                "database": transaction._client._database_string,
                "options": None,
            },
            metadata=transaction._client._rpc_metadata,
        )
        firestore_api.rollback.assert_called_once_with(
            request={
                "database": transaction._client._database_string,
                "transaction": txn_id,
            },
            metadata=transaction._client._rpc_metadata,
        )
        firestore_api.commit.assert_called_once_with(
            request={
                "database": transaction._client._database_string,
                "writes": [],
                "transaction": txn_id,
            },
            metadata=transaction._client._rpc_metadata,
        )
Ejemplo n.º 7
0
def test_retry_idempotent(identity):
    # Define our error and OK responses.
    err409 = exceptions.Aborted(message='derp de derp')
    err503 = exceptions.ServiceUnavailable(message='whups')
    errwtf = exceptions.Unknown(message='huh?')
    ok = showcase_v1alpha3.User(name='users/0', display_name='Guido')
    server = mock.Mock(side_effect=(err409, err503, errwtf, ok))

    # Mock the transport to send back the error responses followed by a
    # success response.
    transport = type(identity).get_transport_class()
    with mock.patch.object(
            transport,
            'get_user',
            new_callable=mock.PropertyMock(return_value=server)):
        with mock.patch.object(time, 'sleep'):
            response = identity.get_user({'name': 'users/0'})
        assert response.name == 'users/0'
        assert response.display_name == 'Guido'
        assert server.call_count == 4
Ejemplo n.º 8
0
def test__transactional__maybe_commit_failure_read_only():
    from google.api_core import exceptions

    wrapped = _make__transactional(mock.sentinel.callable_)

    txn_id = b"failed"
    transaction = _make_transaction_pb(txn_id, read_only=True)
    transaction._id = txn_id  # We won't call ``begin()``.
    wrapped.current_id = txn_id  # We won't call ``_pre_commit()``.
    wrapped.retry_id = txn_id  # We won't call ``_pre_commit()``.

    # Actually force the ``commit`` to fail (use ABORTED, but cannot
    # retry since read-only).
    exc = exceptions.Aborted("Read-only did a bad.")
    firestore_api = transaction._client._firestore_api
    firestore_api.commit.side_effect = exc

    with pytest.raises(exceptions.Aborted) as exc_info:
        wrapped._maybe_commit(transaction)
    assert exc_info.value is exc

    assert transaction._id == txn_id
    assert wrapped.current_id == txn_id
    assert wrapped.retry_id == txn_id

    # Verify mocks.
    firestore_api.begin_transaction.assert_not_called()
    firestore_api.rollback.assert_not_called()
    firestore_api.commit.assert_called_once_with(
        request={
            "database": transaction._client._database_string,
            "writes": [],
            "transaction": txn_id,
        },
        metadata=transaction._client._rpc_metadata,
    )
Ejemplo n.º 9
0
 def test_aborted(core_retry):
     error = core_exceptions.Aborted("testing")
     core_retry.if_transient_error.return_value = False
     assert _retry.is_transient_error(error) is True
     core_retry.if_transient_error.assert_called_once_with(error)