diff options
| -rw-r--r-- | odoo/addons/base/tests/test_db_cursor.py | 58 | ||||
| -rw-r--r-- | odoo/sql_db.py | 26 |
2 files changed, 76 insertions, 8 deletions
diff --git a/odoo/addons/base/tests/test_db_cursor.py b/odoo/addons/base/tests/test_db_cursor.py index 37026cc967a..648e0f04beb 100644 --- a/odoo/addons/base/tests/test_db_cursor.py +++ b/odoo/addons/base/tests/test_db_cursor.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. +from functools import partial import odoo from odoo.sql_db import TestCursor @@ -115,3 +116,60 @@ class TestTestCursor(common.TransactionCase): self.cr.rollback() self.check(self.record, 'A') + + +class TestCursorHooks(common.TransactionCase): + def setUp(self): + super().setUp() + self.log = [] + + def prepare_hooks(self, cr, precommit_msg, postcommit_msg, prerollback_msg, postrollback_msg): + cr.precommit.add(partial(self.log.append, precommit_msg)) + cr.postcommit.add(partial(self.log.append, postcommit_msg)) + cr.prerollback.add(partial(self.log.append, prerollback_msg)) + cr.postrollback.add(partial(self.log.append, postrollback_msg)) + + def test_hooks(self): + cr = self.registry.cursor() + + # check hook on commit() + self.prepare_hooks(cr, 'C1a', 'C1b', 'R1a', 'R1b') + self.assertEqual(self.log, []) + cr.commit() + self.assertEqual(self.log, ['C1a', 'C1b']) + + # check hook on rollback() + self.prepare_hooks(cr, 'C2a', 'C2b', 'R2a', 'R2b') + self.assertEqual(self.log, ['C1a', 'C1b']) + cr.rollback() + self.assertEqual(self.log, ['C1a', 'C1b', 'R2a', 'R2b']) + + # check hook on close() + self.prepare_hooks(cr, 'C3a', 'C3b', 'R3a', 'R3b') + self.assertEqual(self.log, ['C1a', 'C1b', 'R2a', 'R2b']) + cr.close() + self.assertEqual(self.log, ['C1a', 'C1b', 'R2a', 'R2b', 'R3a', 'R3b']) + + def test_hooks_on_testcursor(self): + self.registry.enter_test_mode(self.cr) + self.addCleanup(self.registry.leave_test_mode) + + cr = self.registry.cursor() + + # check hook on commit(); post-commit hooks are ignored + self.prepare_hooks(cr, 'C1a', 'C1b', 'R1a', 'R1b') + self.assertEqual(self.log, []) + cr.commit() + self.assertEqual(self.log, ['C1a']) + + # check hook on rollback() + self.prepare_hooks(cr, 'C2a', 'C2b', 'R2a', 'R2b') + self.assertEqual(self.log, ['C1a']) + cr.rollback() + self.assertEqual(self.log, ['C1a', 'R2a', 'R2b']) + + # check hook on close() + self.prepare_hooks(cr, 'C3a', 'C3b', 'R3a', 'R3b') + self.assertEqual(self.log, ['C1a', 'R2a', 'R2b']) + cr.close() + self.assertEqual(self.log, ['C1a', 'R2a', 'R2b', 'R3a', 'R3b']) diff --git a/odoo/sql_db.py b/odoo/sql_db.py index 1c15f4e4a2d..c5af069728e 100644 --- a/odoo/sql_db.py +++ b/odoo/sql_db.py @@ -107,6 +107,8 @@ class BaseCursor: def __init__(self): self.precommit = tools.Callbacks() self.postcommit = tools.Callbacks() + self.prerollback = tools.Callbacks() + self.postrollback = tools.Callbacks() @contextmanager @check @@ -378,10 +380,11 @@ class Cursor(BaseCursor): # collected as fast as they should). The problem is probably due in # part because browse records keep a reference to the cursor. del self._obj - self._closed = True - # Clean the underlying connection. - self._cnx.rollback() + # Clean the underlying connection, and run rollback hooks. + self.rollback() + + self._closed = True if leak: self._cnx.leaked = True @@ -433,7 +436,7 @@ class Cursor(BaseCursor): if event == 'commit': self.postcommit.add(func) elif event == 'rollback': - raise NotImplementedError() + self.postrollback.add(func) @check def commit(self): @@ -441,6 +444,8 @@ class Cursor(BaseCursor): flush_env(self) self.precommit.run() result = self._cnx.commit() + self.prerollback.clear() + self.postrollback.clear() self.postcommit.run() return result @@ -450,7 +455,9 @@ class Cursor(BaseCursor): clear_env(self) self.precommit.clear() self.postcommit.clear() + self.prerollback.run() result = self._cnx.rollback() + self.postrollback.run() return result @check @@ -496,8 +503,8 @@ class TestCursor(BaseCursor): def close(self): if not self._closed: + self.rollback() self._closed = True - self._cursor.execute('ROLLBACK TO SAVEPOINT "%s"' % self._savepoint) self._lock.release() def autocommit(self, on): @@ -509,16 +516,19 @@ class TestCursor(BaseCursor): flush_env(self) self.precommit.run() self._cursor.execute('SAVEPOINT "%s"' % self._savepoint) - # ignore post-commit hooks - self.postcommit.clear() + self.prerollback.clear() + self.postrollback.clear() + self.postcommit.clear() # TestCursor ignores post-commit hooks @check def rollback(self): """ Perform an SQL `ROLLBACK` """ clear_env(self) self.precommit.clear() - self._cursor.execute('ROLLBACK TO SAVEPOINT "%s"' % self._savepoint) self.postcommit.clear() + self.prerollback.run() + self._cursor.execute('ROLLBACK TO SAVEPOINT "%s"' % self._savepoint) + self.postrollback.run() def __getattr__(self, name): value = getattr(self._cursor, name) |
