diff options
| author | Raphael Collet <rco@odoo.com> | 2018-02-06 13:42:40 +0100 |
|---|---|---|
| committer | Raphael Collet <rco@odoo.com> | 2018-02-12 10:31:59 +0100 |
| commit | 7ea4f13f16671b4361a42d668fb81c941a552468 (patch) | |
| tree | 6c4049fb6ae0fa3044bb5f0ebf994b0e98aea1b2 /odoo/sql_db.py | |
| parent | 459a53ddb5b64eb689a4546ed95cbbae9e802a92 (diff) | |
[REF] tests: `TestCursor` is now a proxy to a real `Cursor`
This allows rpc requests in `HttpCase` to use the cursor `self.cr`, which is
now shared between the Python test and the rpc requests. This simplifies code
to prepare a JS test, and code to check the result of a JS tour.
Fixes #12237
Diffstat (limited to 'odoo/sql_db.py')
| -rw-r--r-- | odoo/sql_db.py | 78 |
1 files changed, 50 insertions, 28 deletions
diff --git a/odoo/sql_db.py b/odoo/sql_db.py index 50e4ac5dce7..8414dcf3dcc 100644 --- a/odoo/sql_db.py +++ b/odoo/sql_db.py @@ -10,6 +10,7 @@ the ORM does, in fact. from contextlib import contextmanager from functools import wraps +import itertools import logging import time import uuid @@ -425,42 +426,68 @@ class Cursor(object): def closed(self): return self._closed -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() +class TestCursor(object): + """ A pseudo-cursor to be used for tests, on top of a real cursor. It keeps + the transaction open across requests, and simulates committing, rolling + back, and closing: + + test cursor | queries on actual cursor + ------------------------+--------------------------------------- + cr = TestCursor(...) | SAVEPOINT test_cursor_N + | + cr.execute(query) | query + | + cr.commit() | SAVEPOINT test_cursor_N + | + cr.rollback() | ROLLBACK TO SAVEPOINT test_cursor_N + | + cr.close() | ROLLBACK TO SAVEPOINT test_cursor_N + | - def release(self): - self._lock.release() + """ + _savepoint_seq = itertools.count() - def force_close(self): - super(TestCursor, self).close() + def __init__(self, cursor, lock): + self._closed = False + self._cursor = cursor + # we use a lock to serialize concurrent requests + self._lock = lock + self._lock.acquire() + # in order to simulate commit and rollback, the cursor maintains a + # savepoint at its last commit + self._savepoint = "test_cursor_%s" % next(self._savepoint_seq) + self._cursor.execute('SAVEPOINT "%s"' % self._savepoint) def close(self): if not self._closed: - self.rollback() # for stuff that has not been committed - self.release() + self._closed = True + self._cursor.execute('ROLLBACK TO SAVEPOINT "%s"' % self._savepoint) + self._lock.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") + self._cursor.execute('SAVEPOINT "%s"' % self._savepoint) def rollback(self): - self.execute("ROLLBACK TO SAVEPOINT test_cursor") - self.execute("SAVEPOINT test_cursor") + self._cursor.execute('ROLLBACK TO SAVEPOINT "%s"' % self._savepoint) + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_value, traceback): + if exc_type is None: + self.commit() + self.close() + + def __getattr__(self, name): + value = getattr(self._cursor, name) + if callable(value) and self._closed: + raise psycopg2.OperationalError('Unable to use a closed cursor.') + return value + class LazyCursor(object): """ A proxy object to a cursor. The cursor itself is allocated only if it is @@ -633,11 +660,6 @@ class Connection(object): _logger.debug('create %scursor to %r', cursor_type, self.dsn) return Cursor(self.__pool, self.dbname, self.dsn, serialized=serialized) - def test_cursor(self, serialized=True): - cursor_type = serialized and 'serialized ' or '' - _logger.debug('create test %scursor to %r', cursor_type, self.dsn) - return TestCursor(self.__pool, self.dbname, self.dsn, serialized=serialized) - # serialized_cursor is deprecated - cursors are serialized by default serialized_cursor = cursor |
