def test_nested_tx(self): with local_db.Transaction() as tx1: tx1.execute('INSERT INTO tests VALUES (:k, :v)', k='foo', v='bar') with local_db.Transaction() as tx2: tx2.execute('UPDATE tests SET value=:v WHERE key=:k', k='foo', v='baz') with local_db.Transaction() as tx: row = tx.query_one('SELECT value FROM tests WHERE key=:k', k='foo') self.assertEqual('baz', row['value'])
def test_write_write_rollback_read_first_value(self): with local_db.Transaction() as tx: tx.execute('INSERT INTO tests VALUES (:k, :v)', k='foo', v='bar') try: with local_db.Transaction() as tx: tx.execute('UPDATE tests SET value=:v WHERE key=:k', k='foo', v='baz') raise RuntimeError() except RuntimeError: pass with local_db.Transaction() as tx: row = tx.query_one('SELECT value FROM tests WHERE key=:k', k='foo') self.assertEqual('bar', row['value'])
def setUp(self): super(LocalDbTestCase, self).setUp() with local_db.Transaction() as tx: tx.execute("""CREATE TABLE IF NOT EXISTS tests ( key TEXT, value TEXT, PRIMARY KEY (key) )""")
def execute_stage(class_name, config, force=False): """ Execute stage specified by `class_name` argument. :param class_name: fully qualified stage class name :param config: config.Configuration instance """ # Create stage object cls = importutils.import_class(class_name) assert issubclass(cls, Stage) stage = cls(config) # Execute dependency stages for dependency in stage.dependencies: execute_stage(dependency, config) # Check if there is data from this stage in local DB new_signature = stage.signature() old_signature = None need_invalidate = False need_execute = False with local_db.Transaction() as tx: row = tx.query_one('SELECT signature FROM stages WHERE stage=:stage', stage=class_name) if row is None: need_execute = True else: old_signature = row['signature'].data need_invalidate = (old_signature != new_signature) # Run invalidate and execute if needed with local_db.Transaction() as tx: if need_invalidate or force: stage.invalidate(old_signature, new_signature, force=force) tx.execute('DELETE FROM stages WHERE stage=:stage', stage=class_name) need_execute = True if need_execute: stage.execute() tx.execute('INSERT INTO stages VALUES (:stage, :signature)', stage=class_name, signature=local_db.Json(new_signature)) LOG.info('Stage %s executed successfully', class_name) else: LOG.info('Skipping stage %s', class_name)
def __enter__(self): # pylint: disable=protected-access self.previous = self._tls.current self._tls.current = self if self.previous is not None: # Store outer TX values for savepoint self.previous._dump_objects() self.tx = local_db.Transaction() self.tx.__enter__() self.session = {} return self
def test_nested_tx_rollback_outer(self): # Prepare state with local_db.Transaction() as tx: tx.execute('INSERT INTO tests VALUES (:k, :v)', k='foo', v='bar') # Run outer rollback from inner tx try: with local_db.Transaction() as tx1: tx1.execute('UPDATE tests SET value=:v WHERE key=:k', k='foo', v='baz') with local_db.Transaction() as tx2: tx2.execute('UPDATE tests SET value=:v WHERE key=:k', k='foo', v='qux') raise RuntimeError() except RuntimeError: pass with local_db.Transaction() as tx: row = tx.query_one('SELECT value FROM tests WHERE key=:k', k='foo') self.assertEqual('bar', row['value'])
def test_write_read_different_tx(self): with local_db.Transaction() as tx: tx.execute('INSERT INTO tests VALUES (:k, :v)', k='foo', v='bar') with local_db.Transaction() as tx: row = tx.query_one('SELECT value FROM tests WHERE key=:k', k='foo') self.assertEqual('bar', row['value'])