diff --git a/addons/mass_mailing/tests/test_mailing_controllers.py b/addons/mass_mailing/tests/test_mailing_controllers.py index a7777616ab8..49ad26ef02b 100644 --- a/addons/mass_mailing/tests/test_mailing_controllers.py +++ b/addons/mass_mailing/tests/test_mailing_controllers.py @@ -35,7 +35,8 @@ class TestMailingControllers(MassMailCommon, HttpCase): # freeze time base value cls._reference_now = datetime.datetime(2022, 6, 14, 10, 0, 0) - def _request_handler(self, s: Session, r: PreparedRequest, /, **kw): + @classmethod + def _request_handler(cls, s: Session, r: PreparedRequest, /, **kw): if r.url.startswith('https://www.example.com/foo/bar'): r = Response() r.status_code = 200 diff --git a/odoo/tests/common.py b/odoo/tests/common.py index ab381bad1c3..d70fef9337c 100644 --- a/odoo/tests/common.py +++ b/odoo/tests/common.py @@ -244,6 +244,8 @@ def _normalize_arch_for_assert(arch_string, parser_method="xml"): arch_string = etree.fromstring(arch_string, parser=parser) return etree.tostring(arch_string, pretty_print=True, encoding='unicode') +class BlockedRequest(requests.exceptions.ConnectionError): + pass _super_send = requests.Session.send class BaseCase(case.TestCase, metaclass=MetaCase): """ Subclass of TestCase for Odoo-specific code. This class is abstract and @@ -258,21 +260,9 @@ class BaseCase(case.TestCase, metaclass=MetaCase): super().__init__(methodName) self.addTypeEqualityFunc(etree._Element, self.assertTreesEqual) self.addTypeEqualityFunc(html.HtmlElement, self.assertTreesEqual) - self.request_mock = None - def setUp(self): - super().setUp() - if 'external' not in self.test_tags: - # if the method is passed directly `patch` discards the session - # object which we need - # pylint: disable=unnecessary-lambda - self.patch( - requests.sessions.Session, - 'send', - lambda s, r, **kwargs: self._request_handler(s, r, **kwargs), - ) - - def _request_handler(self, s: Session, r: PreparedRequest, /, **kw): + @classmethod + def _request_handler(cls, s: Session, r: PreparedRequest, /, **kw): # allow localhost requests # TODO: also check port? url = werkzeug.urls.url_parse(r.url) @@ -283,8 +273,7 @@ class BaseCase(case.TestCase, metaclass=MetaCase): _logger.getChild('requests').info( "Blocking un-mocked external HTTP request %s %s", r.method, r.url) - raise requests.exceptions.ConnectionError( - f"External requests verboten (was {r.method} {r.url})") + raise BlockedRequest(f"External requests verboten (was {r.method} {r.url})") def run(self, result): testMethod = getattr(self, self._testMethodName) @@ -318,6 +307,17 @@ class BaseCase(case.TestCase, metaclass=MetaCase): patcher.stop() cls.addClassCleanup(check_remaining_patchers) super().setUpClass() + if 'standard' in cls.test_tags: + # if the method is passed directly `patch` discards the session + # object which we need + # pylint: disable=unnecessary-lambda + patcher = patch.object( + requests.sessions.Session, + 'send', + lambda s, r, **kwargs: cls._request_handler(s, r, **kwargs), + ) + patcher.start() + cls.addClassCleanup(patcher.stop) def cursor(self): return self.registry.cursor() @@ -792,8 +792,6 @@ class TransactionCase(BaseCase): self.cr.execute('SAVEPOINT test_%d' % self._savepoint_id) self.addCleanup(self.cr.execute, 'ROLLBACK TO SAVEPOINT test_%d' % self._savepoint_id) - self.patch(self.registry['res.partner'], '_get_gravatar_image', lambda *a: False) - class SingleTransactionCase(BaseCase): """ TestCase in which all test methods are run in the same transaction,