Better tag selection ==================== The block was originally hooked onto the `external` tag under the assumption that this was the tag used to allow external requests. It's not, it's the tag for the "external" test suite, which is only one of the test suites allowed to perform external calls. Hook again onto `standard`, this might have some false positives (allow requests which we'd rather block), but it should have a lot less false negatives (block requests we want to allow). Make Overrides Easier ===================== Currently `_request_handler` raises a regular `ConnectionError`, this is an issue because it passes some requests through, which could themselves trigger genuine `ConnectionError`. When overriding `_request_handler` to implement fallbacks for bespoke URL mocks, these two cases need to be distinguishable as overrides likely want to handle blocked requests, not actual failures. Therefore `_request_handler` should a dedicated exception. This exception should be a subclass of `ConnectionError`, so that blocked requests are treated as regular connection failures by normal Odoo code. Class-scope =========== Originally `_request_handler` was scoped on the instance with the idea that it'd be a `mock` object, which individual tests could `configure_mock`. This turned out not to work correctly, because `Mock.side_effect` does not receive a `self`, hence the `Session` was inaccessible and it was not possible to passthrough local requests. While I moved to a regular `lambda` (because a direct method didn't work either), I forgot to remove the `request_mock` attribute, and didn't think that the block could now be lifted up to the class scope. Doing this, requests performed during a "standard" test case's `setUpClass` are now also blocked, which they very much should be. closes odoo/odoo#128977 Signed-off-by: Xavier Morel (xmo) <xmo@odoo.com>
108 lines
4.3 KiB
Python
108 lines
4.3 KiB
Python
# -*- coding: utf-8 -*-
|
|
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
|
|
|
from freezegun import freeze_time
|
|
|
|
import datetime
|
|
import werkzeug
|
|
|
|
from odoo.addons.mass_mailing.tests.common import MassMailCommon
|
|
from requests import Session, PreparedRequest, Response
|
|
|
|
from odoo.tests.common import HttpCase
|
|
from odoo.tests import tagged
|
|
|
|
|
|
@tagged('link_tracker')
|
|
class TestMailingControllers(MassMailCommon, HttpCase):
|
|
|
|
@classmethod
|
|
def setUpClass(cls):
|
|
super(TestMailingControllers, cls).setUpClass()
|
|
cls._create_mailing_list()
|
|
cls.test_mailing = cls.env['mailing.mailing'].create({
|
|
'body_html': '<p>Hello <t t-out="object.name"/><br />Go to <a id="url" href="https://www.example.com/foo/bar?baz=qux">this link</a></p>',
|
|
'contact_list_ids': [(4, cls.mailing_list_1.id), (4, cls.mailing_list_2.id)],
|
|
'mailing_model_id': cls.env['ir.model']._get('mailing.list').id,
|
|
'mailing_type': 'mail',
|
|
'name': 'TestMailing',
|
|
'reply_to': cls.email_reply_to,
|
|
'subject': 'Test',
|
|
})
|
|
|
|
cls.test_contact = cls.mailing_list_1.contact_ids[0]
|
|
|
|
# freeze time base value
|
|
cls._reference_now = datetime.datetime(2022, 6, 14, 10, 0, 0)
|
|
|
|
@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
|
|
return r
|
|
return super()._request_handler(s, r, **kw)
|
|
|
|
def test_tracking_short_code(self):
|
|
""" Test opening short code linked to a mailing trace: should set the
|
|
trace as opened and clicked, create a click record. """
|
|
mailing = self.test_mailing.with_env(self.env)
|
|
with self.mock_mail_gateway(mail_unlink_sent=False):
|
|
mailing.action_send_mail()
|
|
|
|
mail = self._find_mail_mail_wrecord(self.test_contact)
|
|
mailing_trace = mail.mailing_trace_ids
|
|
link_tracker_code = self._get_code_from_short_url(
|
|
self._get_href_from_anchor_id(mail.body, 'url')
|
|
)
|
|
self.assertEqual(len(link_tracker_code), 1)
|
|
self.assertEqual(link_tracker_code.link_id.count, 0)
|
|
self.assertEqual(mail.state, 'sent')
|
|
self.assertEqual(len(mailing_trace), 1)
|
|
self.assertFalse(mailing_trace.links_click_datetime)
|
|
self.assertFalse(mailing_trace.open_datetime)
|
|
self.assertEqual(mailing_trace.trace_status, 'sent')
|
|
|
|
short_link_url = werkzeug.urls.url_join(
|
|
mail.get_base_url(),
|
|
f'r/{link_tracker_code.code}/m/{mailing_trace.id}'
|
|
)
|
|
with freeze_time(self._reference_now):
|
|
_response = self.url_open(short_link_url)
|
|
|
|
self.assertEqual(link_tracker_code.link_id.count, 1)
|
|
self.assertEqual(mailing_trace.links_click_datetime, self._reference_now)
|
|
self.assertEqual(mailing_trace.open_datetime, self._reference_now)
|
|
self.assertEqual(mailing_trace.trace_status, 'open')
|
|
|
|
def test_tracking_url_token(self):
|
|
""" Test tracking of mails linked to a mailing trace: should set the
|
|
trace as opened. """
|
|
mailing = self.test_mailing.with_env(self.env)
|
|
with self.mock_mail_gateway(mail_unlink_sent=False):
|
|
mailing.action_send_mail()
|
|
|
|
mail = self._find_mail_mail_wrecord(self.test_contact)
|
|
mail_id_int = mail.id
|
|
mail_tracking_url = mail._get_tracking_url()
|
|
mailing_trace = mail.mailing_trace_ids
|
|
self.assertEqual(mail.state, 'sent')
|
|
self.assertEqual(len(mailing_trace), 1)
|
|
self.assertFalse(mailing_trace.open_datetime)
|
|
self.assertEqual(mailing_trace.trace_status, 'sent')
|
|
mail.unlink() # the mail might be removed during the email sending
|
|
self.env.flush_all()
|
|
|
|
with freeze_time(self._reference_now):
|
|
response = self.url_open(mail_tracking_url)
|
|
self.assertEqual(response.status_code, 200)
|
|
self.assertEqual(mailing_trace.open_datetime, self._reference_now)
|
|
self.assertEqual(mailing_trace.trace_status, 'open')
|
|
|
|
track_url = werkzeug.urls.url_join(
|
|
mailing.get_base_url(),
|
|
f'mail/track/{mail_id_int}/fake_token/blank.gif'
|
|
)
|
|
response = self.url_open(track_url)
|
|
self.assertEqual(response.status_code, 400)
|