def _post_teardown(self): _post_teardown(self) super(TransactionQueryCacheBase, self)._post_teardown() if transaction.is_dirty(): transaction.rollback() if is_managed(): managed(False)
def test_savepoint_localstore_flush(self): """ This is a very simple test to see if savepoints will actually be committed, i.e. flushed out from localstore into cache. """ transaction.enter_transaction_management() managed() TABLE_NAME = 'test_table' cache_backend = cache.get_backend() cache_backend.patch() keyhandler = cache_backend.keyhandler keygen = keyhandler.keygen tm = cache_backend.cache_backend # First, we set one key-val pair generated for our non-existing table. table_key = keygen.gen_table_key(TABLE_NAME) tm.set(table_key, 'val1') # Then we create a savepoint. # The key-value pair is moved into 'trans_sids' item of localstore. tm._create_savepoint('savepoint1') # We then commit all the savepoints (i.e. only one in this case) # The items stored in 'trans_sids' should be moved back to the # top-level dictionary of our localstore tm._commit_all_savepoints() # And this checks if it actually happened. self.assertTrue(table_key in tm.local)
def test_savepoint_rollback(self): """Tests rollbacks of savepoints""" if not connection.features.uses_savepoints or connection.vendor == 'sqlite': return self.assertFalse(is_managed()) self.assertFalse(transaction.is_dirty()) cache.local.clear() managed() g = Genre.objects.get(pk=1) start_title = g.title g.title = "Adventures in Savepoint World" g.save() g = Genre.objects.get(pk=1) self.assertEqual(g.title, "Adventures in Savepoint World") sid = transaction.savepoint() g.title = "In the Void" g.save() g = Genre.objects.get(pk=1) self.assertEqual(g.title, "In the Void") transaction.savepoint_rollback(sid) g = Genre.objects.get(pk=1) self.assertEqual(g.title, "Adventures in Savepoint World") transaction.rollback() g = Genre.objects.get(pk=1) self.assertEqual(g.title, start_title)
def test_savepoint_rollback(self): """Tests rollbacks of savepoints""" if not connection.features.uses_savepoints: return self.assertFalse(is_managed()) self.assertFalse(transaction.is_dirty()) cache.local.clear() managed() transaction.enter_transaction_management() g = Genre.objects.get(pk=1) start_title = g.title g.title = "Adventures in Savepoint World" g.save() g = Genre.objects.get(pk=1) self.assertEqual(g.title, "Adventures in Savepoint World") sid = transaction.savepoint() g.title = "In the Void" g.save() g = Genre.objects.get(pk=1) self.assertEqual(g.title, "In the Void") transaction.savepoint_rollback(sid) g = Genre.objects.get(pk=1) self.assertEqual(g.title, "Adventures in Savepoint World") transaction.rollback() g = Genre.objects.get(pk=1) self.assertEqual(g.title, start_title)
def test_transaction_rollback(self): """Tests johnny's handling of transaction rollbacks. Similar to the commit, this sets up a write to a db in a transaction, reads from it (to force a cache write of sometime), then rolls back.""" if not is_multithreading_safe(db_using='default'): print("\n Skipping test requiring multiple threads.") return self.assertFalse(is_managed()) self.assertFalse(transaction.is_dirty()) cache.local.clear() q = Queue() other = lambda x: self._run_threaded(x, q) # load some data start = Genre.objects.get(id=1) other('Genre.objects.get(id=1)') hit, ostart = q.get() # these should be the same and should have hit cache self.assertTrue(hit) self.assertEqual(ostart, start) # enter manual transaction management transaction.enter_transaction_management() managed() start.title = 'Jackie Chan Novels' # local invalidation, this key should hit the localstore! nowlen = len(cache.local) start.save() self.assertNotEqual(nowlen, len(cache.local)) # perform a read OUTSIDE this transaction... it should still see the # old gen key, and should still find the "old" data other('Genre.objects.get(id=1)') hit, ostart = q.get() self.assertTrue(hit) self.assertNotEqual(ostart.title, start.title) # perform a READ inside the transaction; this should hit the localstore # but not the outside! nowlen = len(cache.local) start2 = Genre.objects.get(id=1) self.assertEqual(start2.title, start.title) self.assertTrue(len(cache.local) > nowlen) transaction.rollback() # we rollback, and flush all johnny keys related to this transaction # subsequent gets should STILL hit the cache in the other thread # and indeed, in this thread. self.assertFalse(transaction.is_dirty()) other('Genre.objects.get(id=1)') hit, ostart = q.get() self.assertTrue(hit) start = Genre.objects.get(id=1) self.assertEqual(ostart.title, start.title) managed(False) transaction.leave_transaction_management()
def test_transaction_commit(self): """Test transaction support in Johnny.""" if not is_multithreading_safe(db_using='default'): print("\n Skipping test requiring multiple threads.") return self.assertFalse(is_managed()) self.assertFalse(transaction.is_dirty()) cache.local.clear() q = Queue() other = lambda x: self._run_threaded(x, q) # load some data start = Genre.objects.get(id=1) other('Genre.objects.get(id=1)') hit, ostart = q.get() # these should be the same and should have hit cache self.assertTrue(hit) self.assertEqual(ostart, start) # enter manual transaction management transaction.enter_transaction_management() managed() start.title = 'Jackie Chan Novels' # local invalidation, this key should hit the localstore! nowlen = len(cache.local) start.save() self.assertNotEqual(nowlen, len(cache.local)) # perform a read OUTSIDE this transaction... it should still see the # old gen key, and should still find the "old" data other('Genre.objects.get(id=1)') hit, ostart = q.get() self.assertTrue(hit) self.assertNotEqual(ostart.title, start.title) transaction.commit() # now that we commit, we push the localstore keys out; this should be # a cache miss, because we never read it inside the previous transaction other('Genre.objects.get(id=1)') hit, ostart = q.get() self.assertFalse(hit) self.assertEqual(ostart.title, start.title) managed(False) transaction.leave_transaction_management()
def test_savepoint_commit(self): """Tests a transaction commit (release) The release actually pushes the savepoint back into the dirty stack, but at the point it was saved in the transaction""" if not connection.features.uses_savepoints: return self.assertFalse(is_managed()) self.assertFalse(transaction.is_dirty()) cache.local.clear() transaction.enter_transaction_management() managed() g = Genre.objects.get(pk=1) start_title = g.title g.title = "Adventures in Savepoint World" g.save() g = Genre.objects.get(pk=1) self.assertEqual(g.title, "Adventures in Savepoint World") sid = transaction.savepoint() g.title = "In the Void" g.save() #should be a database hit because of save in savepoint with self.assertNumQueries(1): g = Genre.objects.get(pk=1) self.assertEqual(g.title, "In the Void") transaction.savepoint_commit(sid) #should be a cache hit against the dirty store with self.assertNumQueries(0): g = Genre.objects.get(pk=1) self.assertEqual(g.title, "In the Void") transaction.commit() #should have been pushed up to cache store with self.assertNumQueries(0): g = Genre.objects.get(pk=1) self.assertEqual(g.title, "In the Void") managed(False) transaction.leave_transaction_management()
def tearDown(self): if is_managed(): if transaction.is_dirty(): transaction.rollback() managed(False) transaction.leave_transaction_management()
def setUp(self): super(TransactionSupportTest, self).setUp() managed(False)
def test_savepoints(self): """tests savepoints for multiple db's""" q = Queue() other = lambda x: self._run_threaded(x, q, {'Genre': Genre}) if len(getattr(settings, "DATABASES", [])) <= 1: print("\n Skipping multi database tests") return if not is_multithreading_safe(): print("\n Skipping test requiring multiple threads.") return for name, db in settings.DATABASES.items(): con = connections[name] if not con.features.uses_savepoints: print("\n Skipping test requiring savepoints.") return # sanity check self.assertFalse(is_managed()) self.assertFalse(transaction.is_dirty()) self.assertTrue("default" in getattr(settings, "DATABASES")) self.assertTrue("second" in getattr(settings, "DATABASES")) g1 = Genre.objects.using("default").get(pk=1) start_g1 = g1.title g2 = Genre.objects.using("second").get(pk=1) transaction.enter_transaction_management(using='default') managed(using='default') transaction.enter_transaction_management(using='second') managed(using='second') g1.title = "Rollback savepoint" g1.save() g2.title = "Committed savepoint" g2.save(using="second") sid2 = transaction.savepoint(using="second") sid = transaction.savepoint(using="default") g1.title = "Dirty text" g1.save() #other thread should see the original key and cache object from memcache, #not the local cache version other("Genre.objects.using('default').get(pk=1)") hit, ostart = q.get() self.assertTrue(hit) self.assertEqual(ostart.title, start_g1) #should not be a hit due to rollback transaction.savepoint_rollback(sid, using="default") g1 = Genre.objects.using("default").get(pk=1) # i think it should be "Rollback Savepoint" here self.assertEqual(g1.title, start_g1) #will be pushed to dirty in commit g2 = Genre.objects.using("second").get(pk=1) self.assertEqual(g2.title, "Committed savepoint") transaction.savepoint_commit(sid2, using="second") #other thread should still see original version even #after savepoint commit other("Genre.objects.using('second').get(pk=1)") hit, ostart = q.get() self.assertTrue(hit) self.assertEqual(ostart.title, start_g1) with self.assertNumQueries(0, using='second'): g2 = Genre.objects.using("second").get(pk=1) transaction.commit(using="second") managed(False, using='second') with self.assertNumQueries(0, using='second'): g2 = Genre.objects.using("second").get(pk=1) self.assertEqual(g2.title, "Committed savepoint") #now committed and cached, other thread should reflect new title #without a hit to the db other("Genre.objects.using('second').get(pk=1)") hit, ostart = q.get() self.assertEqual(ostart.title, g2.title) self.assertTrue(hit) managed(False, 'default') transaction.leave_transaction_management("default") transaction.leave_transaction_management("second")
def tearDown(self): if is_managed(): if transaction.is_dirty(): transaction.rollback() managed(False)
def tearDown(self): if is_managed(): managed(False)
def test_savepoints(self): """tests savepoints for multiple db's""" q = Queue() other = lambda x: self._run_threaded(x, q, {'Genre': Genre}) if len(getattr(settings, "DATABASES", [])) <= 1: print("\n Skipping multi database tests") return if not is_multithreading_safe(): print("\n Skipping test requiring multiple threads.") return for name, db in settings.DATABASES.items(): con = connections[name] if not con.features.uses_savepoints: print("\n Skipping test requiring savepoints.") return # sanity check self.assertFalse(is_managed()) self.assertFalse(transaction.is_dirty()) self.assertTrue("default" in getattr(settings, "DATABASES")) self.assertTrue("second" in getattr(settings, "DATABASES")) g1 = Genre.objects.using("default").get(pk=1) start_g1 = g1.title g2 = Genre.objects.using("second").get(pk=1) start_g2 = g2.title transaction.enter_transaction_management(using='default') managed(using='default') transaction.enter_transaction_management(using='second') managed(using='second') g1.title = "Rollback savepoint" g1.save() g2.title = "Committed savepoint" g2.save(using="second") sid2 = transaction.savepoint(using="second") sid = transaction.savepoint(using="default") g1.title = "Dirty text" g1.save() #other thread should see the original key and cache object from memcache, #not the local cache version other("Genre.objects.using('default').get(pk=1)") hit, ostart = q.get() self.assertTrue(hit) self.assertEqual(ostart.title, start_g1) #should not be a hit due to rollback transaction.savepoint_rollback(sid, using="default") g1 = Genre.objects.using("default").get(pk=1) # i think it should be "Rollback Savepoint" here self.assertEqual(g1.title, start_g1) #will be pushed to dirty in commit g2 = Genre.objects.using("second").get(pk=1) self.assertEqual(g2.title, "Committed savepoint") transaction.savepoint_commit(sid2, using="second") #other thread should still see original version even #after savepoint commit other("Genre.objects.using('second').get(pk=1)") hit, ostart = q.get() self.assertTrue(hit) self.assertEqual(ostart.title, start_g2) with self.assertNumQueries(0, using='second'): g2 = Genre.objects.using("second").get(pk=1) transaction.commit(using="second") managed(False, using='second') with self.assertNumQueries(0, using='second'): g2 = Genre.objects.using("second").get(pk=1) self.assertEqual(g2.title, "Committed savepoint") #now committed and cached, other thread should reflect new title #without a hit to the db other("Genre.objects.using('second').get(pk=1)") hit, ostart = q.get() self.assertEqual(ostart.title, g2.title) self.assertTrue(hit) transaction.commit(using="default") managed(False, 'default') transaction.leave_transaction_management("default") transaction.leave_transaction_management("second")
def setUp(self): super(TransactionSupportTest, self).setUp() if is_managed(): managed(False)
def test_transactions(self): """Tests transaction rollbacks and local cache for multiple dbs""" if len(getattr(settings, "DATABASES", [])) <= 1: print("\n Skipping multi database tests") return if not is_multithreading_safe(): print("\n Skipping test requiring multiple threads.") return for conname in connections: con = connections[conname] if not base.supports_transactions(con): print("\n Skipping test requiring transactions.") return q = Queue() other = lambda x: self._run_threaded(x, q, {'Genre': Genre}) # sanity check self.assertFalse(is_managed()) self.assertFalse(transaction.is_dirty()) self.assertTrue("default" in getattr(settings, "DATABASES")) self.assertTrue("second" in getattr(settings, "DATABASES")) # this should seed this fetch in the global cache g1 = Genre.objects.using("default").get(pk=1) g2 = Genre.objects.using("second").get(pk=1) start_g1 = g1.title transaction.enter_transaction_management(using='default') managed(using='default') transaction.enter_transaction_management(using='second') managed(using='second') g1.title = "Testing a rollback" g2.title = "Testing a commit" g1.save() g2.save() # test outside of transaction, should be cache hit and # not contain the local changes other("Genre.objects.using('default').get(pk=1)") hit, ostart = q.get() self.assertEqual(ostart.title, start_g1) self.assertTrue(hit) transaction.rollback(using='default') transaction.commit(using='second') managed(False, using='default') managed(False, using='second') #other thread should have seen rollback other("Genre.objects.using('default').get(pk=1)") hit, ostart = q.get() self.assertEqual(ostart.title, start_g1) self.assertTrue(hit) #should be a cache hit due to rollback with self.assertNumQueries(0, using='default'): g1 = Genre.objects.using("default").get(pk=1) #should be a db hit due to commit with self.assertNumQueries(1, using='second'): g2 = Genre.objects.using("second").get(pk=1) #other thread sould now be accessing the cache after the get #from the commit. other("Genre.objects.using('second').get(pk=1)") hit, ostart = q.get() self.assertEqual(ostart.title, g2.title) self.assertTrue(hit) self.assertEqual(g1.title, start_g1) self.assertEqual(g2.title, "Testing a commit") transaction.leave_transaction_management("default") transaction.leave_transaction_management("second")