diff --git a/odoo/addons/test_testing_utilities/tests/test_methods.py b/odoo/addons/test_testing_utilities/tests/test_methods.py index 005914391d1..49e19bce8ac 100644 --- a/odoo/addons/test_testing_utilities/tests/test_methods.py +++ b/odoo/addons/test_testing_utilities/tests/test_methods.py @@ -51,7 +51,7 @@ class TestBasic(common.TransactionCase): self.env.cr.execute("SHOW test_testing_utilities.a_flag") self.assertEqual(self.env.cr.fetchone(), ('',)) - def test_assertRaises_error(self): + def test_assertRaises_error_at_setup(self): """Checks that an exception raised during the *setup* of assertRaises bubbles up correctly. @@ -63,6 +63,19 @@ class TestBasic(common.TransactionCase): with self.assertRaises(CustomError): raise NotImplementedError + def test_assertRaises_error_at_exit(self): + """Checks that a "correctly" executing assertRaises (where the expected + exception has been raised and caught) will properly rollback when the + error is raised by flush() while exiting the savepoint. + """ + self.env.cr.execute("SET LOCAL test_testing_utilities.a_flag = ''") + with mock.patch.object(BaseCursor, 'flush', side_effect=[None, CustomError]): + with self.assertRaises(CustomError): + self.env.cr.execute("SET LOCAL test_testing_utilities.a_flag = 'yes'") + + self.env.cr.execute("SHOW test_testing_utilities.a_flag") + self.assertEqual(self.env.cr.fetchone(), ('',)) + @mute_logger('odoo.sql_db') def test_assertRaises_clear_recovery(self): """Checks that the savepoint is correctly rolled back if an error occurs diff --git a/odoo/sql_db.py b/odoo/sql_db.py index ed7edcfa130..6f5c3a88367 100644 --- a/odoo/sql_db.py +++ b/odoo/sql_db.py @@ -96,6 +96,7 @@ class Savepoint: self._cr.execute(SQL('RELEASE SAVEPOINT {}').format(self._name)) self.closed = True + class _FlushingSavepoint(Savepoint): def __init__(self, cr): cr.flush() @@ -106,9 +107,15 @@ class _FlushingSavepoint(Savepoint): super().rollback() def _close(self, rollback): - if not rollback: - self._cr.flush() - super()._close(rollback) + try: + if not rollback: + self._cr.flush() + except Exception: + rollback = True + raise + finally: + super()._close(rollback) + class BaseCursor: """ Base class for cursors that manage pre/post commit hooks. """