summaryrefslogtreecommitdiff
path: root/openerp/sql_db.py
diff options
context:
space:
mode:
authorRaphael Collet <rco@openerp.com>2014-04-09 16:58:30 +0200
committerRaphael Collet <rco@openerp.com>2014-04-09 16:58:30 +0200
commit5640f3076a98bf8c72a5319abaf4ceb77caa2ffc (patch)
treee7ddbaa8d59dbe337f15c3a3d6bbc7ae273578f8 /openerp/sql_db.py
parentf090689984bcb46f47eab3fdfc5e9a10a21722ab (diff)
parentbe0096c4a753d9eed336f899c18c92f1aaf0223b (diff)
[MERGE] test_cursor: implement a cursor mockup that never commits to database, and use it for http tests
bzr revid: rco@openerp.com-20140409145830-rop8esgic2y435kf
Diffstat (limited to 'openerp/sql_db.py')
-rw-r--r--openerp/sql_db.py58
1 files changed, 58 insertions, 0 deletions
diff --git a/openerp/sql_db.py b/openerp/sql_db.py
index 59841656d8c..ee58503c40b 100644
--- a/openerp/sql_db.py
+++ b/openerp/sql_db.py
@@ -347,6 +347,23 @@ class Cursor(object):
"""
return self._cnx.rollback()
+ def __enter__(self):
+ """ Using the cursor as a contextmanager automatically commits and
+ closes it::
+
+ with cr:
+ cr.execute(...)
+
+ # cr is committed if no failure occurred
+ # cr is closed in any case
+ """
+ return self
+
+ def __exit__(self, exc_type, exc_value, traceback):
+ if exc_type is None:
+ self.commit()
+ self.close()
+
@contextmanager
@check
def savepoint(self):
@@ -364,6 +381,42 @@ class Cursor(object):
def __getattr__(self, name):
return getattr(self._obj, name)
+class TestCursor(Cursor):
+ """ A cursor to be used for tests. It keeps the transaction open across
+ several requests, and simulates committing, rolling back, and closing.
+ """
+ def __init__(self, *args, **kwargs):
+ super(TestCursor, self).__init__(*args, **kwargs)
+ # in order to simulate commit and rollback, the cursor maintains a
+ # savepoint at its last commit
+ self.execute("SAVEPOINT test_cursor")
+ # we use a lock to serialize concurrent requests
+ self._lock = threading.RLock()
+
+ def acquire(self):
+ self._lock.acquire()
+
+ def release(self):
+ self._lock.release()
+
+ def close(self, force=False):
+ if force:
+ super(TestCursor, self).close()
+ elif not self._closed:
+ self.rollback() # for stuff that has not been committed
+ self.release()
+
+ def autocommit(self, on):
+ _logger.debug("TestCursor.autocommit(%r) does nothing", on)
+
+ def commit(self):
+ self.execute("RELEASE SAVEPOINT test_cursor")
+ self.execute("SAVEPOINT test_cursor")
+
+ def rollback(self):
+ self.execute("ROLLBACK TO SAVEPOINT test_cursor")
+ self.execute("SAVEPOINT test_cursor")
+
class PsycoConnection(psycopg2.extensions.connection):
pass
@@ -491,6 +544,11 @@ class Connection(object):
_logger.debug('create %scursor to %r', cursor_type, self.dbname)
return Cursor(self._pool, self.dbname, serialized=serialized)
+ def test_cursor(self, serialized=True):
+ cursor_type = serialized and 'serialized ' or ''
+ _logger.debug('create test %scursor to %r', cursor_type, self.dbname)
+ return TestCursor(self._pool, self.dbname, serialized=serialized)
+
# serialized_cursor is deprecated - cursors are serialized by default
serialized_cursor = cursor