Skip to content

Commit

Permalink
Adding system test for datastore failed transactions.
Browse files Browse the repository at this point in the history
This intentionally forces data contention in a transaction (by
updating the entity outside of the transaction).

This is to prevent regressions like googleapis#903.
  • Loading branch information
dhermes committed Aug 11, 2015
1 parent 2d017de commit 41230aa
Showing 1 changed file with 43 additions and 0 deletions.
43 changes: 43 additions & 0 deletions system_tests/datastore.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
from gcloud import datastore
from gcloud.datastore import client
from gcloud.environment_vars import TESTS_DATASET
from gcloud.exceptions import Conflict
# This assumes the command is being run via tox hence the
# repository root is the current directory.
from system_tests import populate_datastore
Expand Down Expand Up @@ -341,3 +342,45 @@ def test_transaction(self):
retrieved_entity = CLIENT.get(entity.key)
self.case_entities_to_delete.append(retrieved_entity)
self.assertEqual(retrieved_entity, entity)

def test_failure_with_contention(self):
CONTENTION_KEY = 'baz'

# Insert an entity which will be retrieved in a transaction
# and updated outside it with a contentious value.
key = CLIENT.key('BreakTxn', 1234)
orig_entity = datastore.Entity(key=key)
orig_entity['foo'] = u'bar'
CLIENT.put(orig_entity)
self.case_entities_to_delete.append(orig_entity)

# Make sure we are not yet in a transaction.
self.assertEqual(CLIENT.current_transaction, None)

# Artificially set a transaction on the client's stack, but don't
# enter the context manager (we want to make an upsert outside
# of the transaction).
txn = CLIENT.transaction()
CLIENT._push_batch(txn)
self.assertEqual(CLIENT.current_transaction, txn)
# Since current_transaction == txn, this will occur transactionally.
txn.begin()
entity_in_txn = CLIENT.get(key)

# Update the original entity outside the transaction.
CLIENT._pop_batch()
self.assertEqual(CLIENT.current_transaction, None)
orig_entity[CONTENTION_KEY] = u'outside'
CLIENT.put(orig_entity)

# Put the transaction back in context and try to update the entity
# which we already updated outside the transaction.
CLIENT._push_batch(txn)
self.assertEqual(CLIENT.current_transaction, txn)
entity_in_txn[CONTENTION_KEY] = u'inside'
txn.put(entity_in_txn)

with self.assertRaises(Conflict):
txn.commit()

CLIENT._pop_batch()

0 comments on commit 41230aa

Please sign in to comment.