You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

353 lines
12 KiB

# No need to translate tests
# pylint: disable=translation-required
from email.message import EmailMessage
import mock
import odoo
from odoo import SUPERUSER_ID
from odoo.tests import TransactionCase
from odoo.addons.base.models.ir_mail_server import IrMailServer
from ..models.mail import (
MESSAGE_PREFIX,
encode_msg_id,
encode_msg_id_legacy,
random_string,
)
@odoo.tests.tagged("post_install", "-at_install")
class TestEmail(TransactionCase):
def setUp(self):
super(TestEmail, self).setUp()
self.partner = self.env["res.partner"].create({"name": "Test Dude"})
self.partner2 = self.env["res.partner"].create({"name": "Dudette"})
self.demo_user = self.env.ref("base.user_demo")
self.subtype_comment = self.env.ref("mail.mt_comment")
self.subtype_note = self.env.ref("mail.mt_note")
self.MailMessage = self.env["mail.message"]
self.ConfigParam = self.env["ir.config_parameter"]
# Create server configuration
self.outgoing_server = self.env["ir.mail_server"].create(
{
"name": "Outgoing SMTP Server for Unit Tests",
"sequence": 1,
"smtp_host": "localhost",
"smtp_port": "9999",
"smtp_encryption": "none",
"smtp_user": "doesnt",
"smtp_pass": "exist",
"reply_to_method": "msg_id",
"force_email_reply_to_domain": "example.com",
"force_email_from": "odoo@example.com",
}
)
@staticmethod
def create_email_message():
message = EmailMessage()
message[
"Content-Type"
] = 'multipart/mixed; boundary="===============2590914155756834027=="'
message["MIME-Version"] = "1.0"
message[
"Message-Id"
] = "<CAD-eYi=a264_3DcrYSDU5yc_fwYoHonZ3H+{}@mail.gmail.com>".format(
random_string(6)
)
message["Subject"] = "1"
message["From"] = "Miku Laitinen <miku@avoin.systems>"
message["Reply-To"] = "YourCompany Eurooppa <sales@avoin.onmicrosoft.com>"
message["To"] = '"Erik N. French" <ErikNFrench@armyspy.com>'
message["Date"] = "Mon, 06 May 2019 14:16:38 -0000"
return message
def test_reply_to_method_msg_id(self):
# Make administrator follow the partner
self.partner.message_subscribe([self.env.user.partner_id.id])
# Send a message to the followers of the partner
thread_msg = self.partner.with_user(self.demo_user).message_post(
body="dummy message.", message_type="comment", subtype="mail.mt_comment"
)
# Make sure the message headers look right.. or not
# mail_msg = thread_msg.notification_ids[0]
# Get the encoded message address
encoded_msg_id = encode_msg_id(thread_msg.id, self.env)
# Try to read an incoming email
message = self.create_email_message()
del message["To"]
message["To"] = '"Erik N. French" <ErikNFrench+{}{}@armyspy.com>'.format(
MESSAGE_PREFIX, encoded_msg_id
)
thread_id = self.env["mail.thread"].message_process(
model=False, message=message.as_string()
)
self.assertEqual(
thread_msg.res_id,
thread_id,
"The incoming email wasn't connected to the correct thread",
)
# Make sure the message is a comment
incoming_msg1 = self.MailMessage.search(
[("message_id", "=", message["Message-Id"])]
)
self.assertEqual(
incoming_msg1.message_type,
"email",
"The incoming message was created as a type {} instead of a email.".format(
incoming_msg1.message_type
),
)
self.assertEqual(
incoming_msg1.subtype_id,
self.subtype_comment,
"The incoming message was created as a subtype {} instead of a comment.".format(
incoming_msg1.subtype_id
),
)
# Try to read another incoming email
message = self.create_email_message()
del message["To"]
message["To"] = '"Erik N. French" <ErikNFrench+{}HURDURLUR@armyspy.com>'.format(
MESSAGE_PREFIX
)
message["In-Reply-To"] = thread_msg.message_id
thread_id = self.env["mail.thread"].message_process(
model=False, message=message.as_string()
)
self.assertEqual(
thread_msg.res_id,
thread_id,
"The incoming email wasn't connected to the correct thread",
)
# Make sure the message is a comment
incoming_msg2 = self.MailMessage.search(
[("message_id", "=", message["Message-Id"])]
)
self.assertEqual(
incoming_msg2.message_type,
"email",
"The incoming message was created as a type {} instead of a email.".format(
incoming_msg2.message_type
),
)
self.assertEqual(
incoming_msg2.subtype_id,
self.subtype_comment,
"The incoming message was created as a subtype {} instead of a comment.".format(
incoming_msg2.subtype_id
),
)
def test_reply_to_method_msg_id_priority(self):
"""
In this test we will inject the wrong Message-Id to the incoming
email messages References-header and see if Odoo will prioritize
the custom Reply-To address over the References-header. It should.
:return:
"""
# Make administrator follow the partner
self.partner.message_subscribe([self.env.user.partner_id.id])
# Send a message to the followers of the partner
thread_msg = self.partner.with_user(self.demo_user).message_post(
body="dummy message X.", message_type="comment", subtype="mail.mt_comment"
)
# Get the encoded message address
encoded_msg_id = encode_msg_id(thread_msg.id, self.env)
# Send another message to the followers of the partner
thread_msg2 = self.partner2.with_user(self.demo_user).message_post(
body="dummy message X.", message_type="comment", subtype="mail.mt_comment"
)
# Try to read an incoming email
message = self.create_email_message()
del message["To"]
del message["References"]
message["To"] = '"Erik N. French" <ErikNFrench+{}{}@armyspy.com>'.format(
MESSAGE_PREFIX, encoded_msg_id
)
# Inject the wrong References
message["References"] = thread_msg2.message_id
thread_id = self.env["mail.thread"].message_process(
model=False, message=message.as_string()
)
self.assertEqual(
thread_msg.res_id,
thread_id,
"The incoming email wasn't connected to the correct thread",
)
def test_reply_to_method_msg_id_notification(self):
# Make administrator follow the partner
self.partner2.message_subscribe([self.env.user.partner_id.id])
# Send a message to the followers of the partner
thread_msg = self.partner2.with_user(self.demo_user).message_post(
body="dummy message 2.", message_type="comment", subtype="mail.mt_note"
)
# Get the encoded message address
encoded_msg_id = encode_msg_id(thread_msg.id, self.env)
# Try to read an incoming email
message = self.create_email_message()
del message["To"]
message["To"] = '"Erik N. French" <ErikNFrench+{}{}@armyspy.com>'.format(
MESSAGE_PREFIX, encoded_msg_id
)
thread_id = self.env["mail.thread"].message_process(
model=False, message=message.as_string()
)
self.assertEqual(
thread_msg.res_id,
thread_id,
"The incoming email wasn't connected to the correct thread",
)
# Make sure the message is a note
incoming_msg1 = self.MailMessage.search(
[("message_id", "=", message["Message-Id"])]
)
self.assertEqual(
incoming_msg1.message_type,
"email",
"The incoming message was created as a type {} instead of a email.".format(
incoming_msg1.message_type
),
)
self.assertEqual(
incoming_msg1.subtype_id,
self.subtype_note,
"The incoming message was created as a subtype {} instead of a note.".format(
incoming_msg1.subtype_id
),
)
def test_reply_to_method_msg_id_legacy(self):
# REMOVE this test when porting to Odoo 14
# Make administrator follow the partner
self.partner2.message_subscribe([self.env.user.partner_id.id])
# Send a message to the followers of the partner
thread_msg = self.partner2.with_user(self.demo_user).message_post(
body="dummy message 2.", message_type="comment", subtype="mail.mt_note"
)
# Get the encoded message address
encoded_msg_id = encode_msg_id_legacy(thread_msg.id, self.env)
# Try to read an incoming email
message = self.create_email_message()
del message["To"]
message["To"] = '"Erik N. French" <ErikNFrench+{}{}@armyspy.com>'.format(
MESSAGE_PREFIX, encoded_msg_id
)
thread_id = self.env["mail.thread"].message_process(
model=False, message=message.as_string()
)
self.assertEqual(
thread_msg.res_id,
thread_id,
"The incoming email wasn't connected to the correct thread",
)
def test_reply_to_method_msg_id_lowercase(self):
# Make administrator follow the partner
self.partner2.message_subscribe([self.env.user.partner_id.id])
# Send a message to the followers of the partner
thread_msg = self.partner2.with_user(self.demo_user).message_post(
body="dummy message 2.", message_type="comment", subtype="mail.mt_note"
)
# Get the encoded message address
encoded_msg_id = encode_msg_id(thread_msg.id, self.env).lower()
# Try to read an incoming email
message = self.create_email_message()
del message["To"]
message["To"] = '"Erik N. French" <ErikNFrench+{}{}@armyspy.com>'.format(
MESSAGE_PREFIX, encoded_msg_id
)
thread_id = self.env["mail.thread"].message_process(
model=False, message=message.as_string()
)
self.assertEqual(
thread_msg.res_id,
thread_id,
"The incoming email wasn't connected to the correct thread",
)
def test_outgoing_msg_id(self):
# Make administrator follow the partner
self.partner2.message_subscribe([SUPERUSER_ID])
with mock.patch.object(IrMailServer, "send_email") as send_email:
# Send a message to the followers of the partner
thread_msg = self.partner2.with_user(self.demo_user).message_post(
body="dummy message 3.",
message_type="comment",
subtype="mail.mt_comment",
)
# Get the encoded message address
encoded_msg_id = encode_msg_id(thread_msg.id, self.env)
self.assertTrue(
send_email.called,
"IrMailServer.send_email wasn't called when sending outgoing email",
)
message = send_email.call_args[0][0]
reply_to_address = "{}{}@{}".format(
MESSAGE_PREFIX,
encoded_msg_id,
self.outgoing_server.force_email_reply_to_domain,
)
# Make sure the subaddress is correct in the Reply-To field
self.assertIn(
reply_to_address,
message["Reply-To"],
"Reply-To address didn't contain the correct subaddress",
)
# Make sure the author name is in the Reply-To field
self.assertIn(
thread_msg.author_id.name,
message["Reply-To"],
"Reply-To address didn't contain the author name",
)
self.assertIn(
self.outgoing_server.force_email_from,
message["From"],
"From address didn't contain the configure From-address",
)