1 # -*- coding: utf-8 -*-
2 ##############################################################################
4 # OpenERP, Open Source Business Applications
5 # Copyright (c) 2012-TODAY OpenERP S.A. <http://openerp.com>
7 # This program is free software: you can redistribute it and/or modify
8 # it under the terms of the GNU Affero General Public License as
9 # published by the Free Software Foundation, either version 3 of the
10 # License, or (at your option) any later version.
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU Affero General Public License for more details.
17 # You should have received a copy of the GNU Affero General Public License
18 # along with this program. If not, see <http://www.gnu.org/licenses/>.
20 ##############################################################################
24 from openerp.tests import common
25 from openerp.tools.html_sanitize import html_sanitize
27 MAIL_TEMPLATE = """Return-Path: <whatever-2a840@postmaster.twitter.com>
29 Received: by mail1.openerp.com (Postfix, from userid 10002)
30 id 5DF9ABFB2A; Fri, 10 Aug 2012 16:16:39 +0200 (CEST)
31 From: Sylvie Lelitre <sylvie.lelitre@agrolait.com>
34 Content-Type: multipart/alternative;
35 boundary="----=_Part_4200734_24778174.1344608186754"
36 Date: Fri, 10 Aug 2012 14:16:26 +0000
37 Message-ID: <1198923581.41972151344608186760.JavaMail@agrolait.com>
39 ------=_Part_4200734_24778174.1344608186754
40 Content-Type: text/plain; charset=utf-8
41 Content-Transfer-Encoding: quoted-printable
43 Please call me as soon as possible this afternoon!
47 ------=_Part_4200734_24778174.1344608186754
48 Content-Type: text/html; charset=utf-8
49 Content-Transfer-Encoding: quoted-printable
51 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
54 <meta http-equiv=3D"Content-Type" content=3D"text/html; charset=3Dutf-8" />
56 <body style=3D"margin: 0; padding: 0; background: #ffffff;-webkit-text-size-adjust: 100%;">=20
58 <p>Please call me as soon as possible this afternoon!</p>
65 ------=_Part_4200734_24778174.1344608186754--
68 MAIL_TEMPLATE_PLAINTEXT = """Return-Path: <whatever-2a840@postmaster.twitter.com>
70 Received: by mail1.openerp.com (Postfix, from userid 10002)
71 id 5DF9ABFB2A; Fri, 10 Aug 2012 16:16:39 +0200 (CEST)
72 From: Sylvie Lelitre <sylvie.lelitre@agrolait.com>
75 Content-Type: text/plain
76 Date: Fri, 10 Aug 2012 14:16:26 +0000
80 Please call me as soon as possible this afternoon!
87 class TestMailMockups(common.TransactionCase):
89 def _mock_smtp_gateway(self, *args, **kwargs):
92 def _init_mock_build_email(self):
93 self._build_email_args_list = []
94 self._build_email_kwargs_list = []
96 def _mock_build_email(self, *args, **kwargs):
97 self._build_email_args_list.append(args)
98 self._build_email_kwargs_list.append(kwargs)
99 return self._build_email(*args, **kwargs)
102 super(TestMailMockups, self).setUp()
103 # Install mock SMTP gateway
104 self._init_mock_build_email()
105 self._build_email = self.registry('ir.mail_server').build_email
106 self.registry('ir.mail_server').build_email = self._mock_build_email
107 self._send_email = self.registry('ir.mail_server').send_email
108 self.registry('ir.mail_server').send_email = self._mock_smtp_gateway
112 self.registry('ir.mail_server').build_email = self._build_email
113 self.registry('ir.mail_server').send_email = self._send_email
114 super(TestMailMockups, self).tearDown()
117 class test_mail(TestMailMockups):
119 def _mock_send_get_mail_body(self, *args, **kwargs):
120 # def _send_get_mail_body(self, cr, uid, mail, partner=None, context=None)
121 body = tools.append_content_to_html(args[2].body_html, kwargs.get('partner').name if kwargs.get('partner') else 'No specific partner')
125 super(test_mail, self).setUp()
126 self.ir_model = self.registry('ir.model')
127 self.mail_alias = self.registry('mail.alias')
128 self.mail_thread = self.registry('mail.thread')
129 self.mail_group = self.registry('mail.group')
130 self.mail_mail = self.registry('mail.mail')
131 self.mail_message = self.registry('mail.message')
132 self.mail_notification = self.registry('mail.notification')
133 self.mail_followers = self.registry('mail.followers')
134 self.res_users = self.registry('res.users')
135 self.res_partner = self.registry('res.partner')
137 # Mock send_get_mail_body to test its functionality without other addons override
138 self._send_get_mail_body = self.registry('mail.mail').send_get_mail_body
139 self.registry('mail.mail').send_get_mail_body = self._mock_send_get_mail_body
141 # groups@.. will cause the creation of new mail groups
142 self.mail_group_model_id = self.ir_model.search(self.cr, self.uid, [('model', '=', 'mail.group')])[0]
143 self.mail_alias.create(self.cr, self.uid, {'alias_name': 'groups',
144 'alias_model_id': self.mail_group_model_id})
145 # create a 'pigs' group that will be used through the various tests
146 self.group_pigs_id = self.mail_group.create(self.cr, self.uid,
147 {'name': 'Pigs', 'description': 'Fans of Pigs, unite !'})
151 self.registry('mail.mail').send_get_mail_body = self._send_get_mail_body
152 super(test_mail, self).tearDown()
154 def test_00_message_process(self):
155 cr, uid = self.cr, self.uid
156 # Incoming mail creates a new mail_group "frogs"
157 self.assertEqual(self.mail_group.search(cr, uid, [('name', '=', 'frogs')]), [])
158 mail_frogs = MAIL_TEMPLATE.format(to='groups@example.com, other@gmail.com', subject='frogs', extra='')
159 self.mail_thread.message_process(cr, uid, None, mail_frogs)
160 frog_groups = self.mail_group.search(cr, uid, [('name', '=', 'frogs')])
161 self.assertTrue(len(frog_groups) == 1)
163 # Previously-created group can be emailed now - it should have an implicit alias group+frogs@...
164 frog_group = self.mail_group.browse(cr, uid, frog_groups[0])
165 group_messages = frog_group.message_ids
166 self.assertTrue(len(group_messages) == 1, 'New group should only have the original message')
167 mail_frog_news = MAIL_TEMPLATE.format(to='Friendly Frogs <group+frogs@example.com>', subject='news', extra='')
168 self.mail_thread.message_process(cr, uid, None, mail_frog_news)
170 self.assertTrue(len(frog_group.message_ids) == 2, 'Group should contain 2 messages now')
172 # Even with a wrong destination, a reply should end up in the correct thread
173 mail_reply = MAIL_TEMPLATE.format(to='erroneous@example.com>', subject='Re: news',
174 extra='In-Reply-To: <12321321-openerp-%d-mail.group@example.com>\n' % frog_group.id)
175 self.mail_thread.message_process(cr, uid, None, mail_reply)
177 self.assertTrue(len(frog_group.message_ids) == 3, 'Group should contain 3 messages now')
179 # No model passed and no matching alias must raise
180 mail_spam = MAIL_TEMPLATE.format(to='noone@example.com', subject='spam', extra='')
181 self.assertRaises(Exception,
182 self.mail_thread.message_process,
183 cr, uid, None, mail_spam)
185 # plain text content should be wrapped and stored as html
186 test_msg_id = '<deadcafe.1337@smtp.agrolait.com>'
187 mail_text = MAIL_TEMPLATE_PLAINTEXT.format(to='groups@example.com', subject='frogs', extra='', msg_id=test_msg_id)
188 self.mail_thread.message_process(cr, uid, None, mail_text)
189 new_mail = self.mail_message.browse(cr, uid, self.mail_message.search(cr, uid, [('message_id', '=', test_msg_id)])[0])
190 self.assertEqual(new_mail.body, '\n<pre>\nPlease call me as soon as possible this afternoon!\n\n--\nSylvie\n</pre>\n',
191 'plaintext mail incorrectly parsed')
193 def test_10_many2many_reference_field(self):
194 """ Tests designed for the many2many_reference field (follower_ids).
195 We will test to perform writes using the many2many commands 0, 3, 4,
197 cr, uid = self.cr, self.uid
198 user_admin = self.res_users.browse(cr, uid, uid)
199 group_pigs = self.mail_group.browse(cr, uid, self.group_pigs_id)
201 # Create partner Bert Poilu
202 partner_bert_id = self.res_partner.create(cr, uid, {'name': 'Bert Poilu'})
204 # Create 'disturbing' values in mail.followers: same res_id, other res_model; same res_model, other res_id
205 group_dummy_id = self.mail_group.create(cr, uid,
206 {'name': 'Dummy group'})
207 self.mail_followers.create(cr, uid,
208 {'res_model': 'mail.thread', 'res_id': self.group_pigs_id, 'partner_id': partner_bert_id})
209 self.mail_followers.create(cr, uid,
210 {'res_model': 'mail.group', 'res_id': group_dummy_id, 'partner_id': partner_bert_id})
212 # Pigs just created: should be only Admin as follower
213 follower_ids = set([follower.id for follower in group_pigs.message_follower_ids])
214 self.assertEqual(follower_ids, set([user_admin.partner_id.id]), 'Admin should be the only Pigs fan')
216 # Subscribe Bert through a '4' command
217 group_pigs.write({'message_follower_ids': [(4, partner_bert_id)]})
219 follower_ids = set([follower.id for follower in group_pigs.message_follower_ids])
220 self.assertEqual(follower_ids, set([partner_bert_id, user_admin.partner_id.id]), 'Bert and Admin should be the only Pigs fans')
222 # Unsubscribe Bert through a '3' command
223 group_pigs.write({'message_follower_ids': [(3, partner_bert_id)]})
225 follower_ids = set([follower.id for follower in group_pigs.message_follower_ids])
226 self.assertEqual(follower_ids, set([user_admin.partner_id.id]), 'Admin should be the only Pigs fan')
228 # Set followers through a '6' command
229 group_pigs.write({'message_follower_ids': [(6, 0, [partner_bert_id])]})
231 follower_ids = set([follower.id for follower in group_pigs.message_follower_ids])
232 self.assertEqual(follower_ids, set([partner_bert_id]), 'Bert should be the only Pigs fan')
234 # Add a follower created on the fly through a '0' command
235 group_pigs.write({'message_follower_ids': [(0, 0, {'name': 'Patrick Fiori'})]})
236 partner_patrick_id = self.res_partner.search(cr, uid, [('name', '=', 'Patrick Fiori')])[0]
238 follower_ids = set([follower.id for follower in group_pigs.message_follower_ids])
239 self.assertEqual(follower_ids, set([partner_bert_id, partner_patrick_id]), 'Bert and Patrick should be the only Pigs fans')
241 # Finally, unlink through a '5' command
242 group_pigs.write({'message_follower_ids': [(5, 0)]})
244 follower_ids = set([follower.id for follower in group_pigs.message_follower_ids])
245 self.assertFalse(follower_ids, 'Pigs group should not have fans anymore')
247 # Test dummy data has not been altered
248 fol_obj_ids = self.mail_followers.search(cr, uid, [('res_model', '=', 'mail.thread'), ('res_id', '=', self.group_pigs_id)])
249 follower_ids = set([follower.partner_id.id for follower in self.mail_followers.browse(cr, uid, fol_obj_ids)])
250 self.assertEqual(follower_ids, set([partner_bert_id]), 'Bert should be the follower of dummy mail.thread data')
251 fol_obj_ids = self.mail_followers.search(cr, uid, [('res_model', '=', 'mail.group'), ('res_id', '=', group_dummy_id)])
252 follower_ids = set([follower.partner_id.id for follower in self.mail_followers.browse(cr, uid, fol_obj_ids)])
253 self.assertEqual(follower_ids, set([partner_bert_id, user_admin.partner_id.id]), 'Bert and Admin should be the followers of dummy mail.group data')
255 def test_11_message_followers(self):
256 """ Tests designed for the subscriber API. """
257 cr, uid = self.cr, self.uid
258 user_admin = self.res_users.browse(cr, uid, uid)
259 group_pigs = self.mail_group.browse(cr, uid, self.group_pigs_id)
262 user_raoul_id = self.res_users.create(cr, uid, {'name': 'Raoul Grosbedon', 'login': 'raoul'})
263 user_raoul = self.res_users.browse(cr, uid, user_raoul_id)
265 # Subscribe Raoul three times (niak niak) through message_subscribe_users
266 group_pigs.message_subscribe_users([user_raoul_id, user_raoul_id])
267 group_pigs.message_subscribe_users([user_raoul_id])
269 follower_ids = [follower.id for follower in group_pigs.message_follower_ids]
270 self.assertEqual(len(follower_ids), 2, 'There should be 2 Pigs fans')
271 self.assertEqual(set(follower_ids), set([user_raoul.partner_id.id, user_admin.partner_id.id]), 'Admin and Raoul should be the only 2 Pigs fans')
273 # Unsubscribe Raoul twice through message_unsubscribe_users
274 group_pigs.message_unsubscribe_users([user_raoul_id, user_raoul_id])
276 follower_ids = [follower.id for follower in group_pigs.message_follower_ids]
277 self.assertEqual(follower_ids, [user_admin.partner_id.id], 'Admin must be the only Pigs fan')
279 def test_20_message_post(self):
280 """ Tests designed for message_post. """
281 cr, uid = self.cr, self.uid
282 self.res_users.write(cr, uid, [uid], {'signature': 'Admin', 'email': 'a@a'})
283 user_admin = self.res_users.browse(cr, uid, uid)
284 group_pigs = self.mail_group.browse(cr, uid, self.group_pigs_id)
287 p_a_id = user_admin.partner_id.id
288 # 1 - Bert Tartopoils, with email, should receive emails for comments and emails
289 p_b_id = self.res_partner.create(cr, uid, {'name': 'Bert Tartopoils', 'email': 'b@b'})
290 # 2 - Carine Poilvache, with email, should never receive emails
291 p_c_id = self.res_partner.create(cr, uid, {'name': 'Carine Poilvache', 'email': 'c@c', 'notification_email_send': 'email'})
292 # 3 - Dédé Grosbedon, without email, to test email verification; should receive emails for every message
293 p_d_id = self.res_partner.create(cr, uid, {'name': 'Dédé Grosbedon', 'notification_email_send': 'all'})
296 group_pigs.message_subscribe([p_b_id, p_c_id])
300 _mail_subject = '%s posted on %s' % (user_admin.name, group_pigs.name)
301 _body1 = 'Pigs rules'
302 _mail_body1 = 'Pigs rules\n<pre>Admin</pre>\n'
303 _mail_bodyalt1 = 'Pigs rules\nAdmin'
304 _body2 = '<html>Pigs rules</html>'
305 _mail_body2 = html_sanitize('<html>Pigs rules\n<pre>Admin</pre>\n</html>')
306 _mail_bodyalt2 = 'Pigs rules\nAdmin'
307 _attachments = [('First', 'My first attachment'), ('Second', 'My second attachment')]
309 # CASE1: post comment, body and subject specified
310 self._init_mock_build_email()
311 msg_id = self.mail_group.message_post(cr, uid, self.group_pigs_id, body=_body1, subject=_subject, type='comment')
312 message = self.mail_message.browse(cr, uid, msg_id)
313 sent_emails = self._build_email_kwargs_list
314 # Test: notifications have been deleted
315 self.assertFalse(self.mail_mail.search(cr, uid, [('mail_message_id', '=', msg_id)]), 'mail.mail notifications should have been auto-deleted!')
316 # Test: mail_message: subject is _subject, body is _body1 (no formatting done)
317 self.assertEqual(message.subject, _subject, 'mail.message subject incorrect')
318 self.assertEqual(message.body, _body1, 'mail.message body incorrect')
319 # Test: sent_email: email send by server: correct subject, body, body_alternative
320 for sent_email in sent_emails:
321 self.assertEqual(sent_email['subject'], _subject, 'sent_email subject incorrect')
322 self.assertEqual(sent_email['body'], _mail_body1 + '\n<pre>Bert Tartopoils</pre>\n', 'sent_email body incorrect')
323 self.assertEqual(sent_email['body_alternative'], _mail_bodyalt1 + '\nBert Tartopoils', 'sent_email body_alternative is incorrect')
324 # Test: mail_message: partner_ids = group followers
325 message_pids = set([partner.id for partner in message.partner_ids])
326 test_pids = set([p_a_id, p_b_id, p_c_id])
327 self.assertEqual(test_pids, message_pids, 'mail.message partners incorrect')
328 # Test: notification linked to this message = group followers = partner_ids
329 notif_ids = self.mail_notification.search(cr, uid, [('message_id', '=', message.id)])
330 notif_pids = set([notif.partner_id.id for notif in self.mail_notification.browse(cr, uid, notif_ids)])
331 self.assertEqual(notif_pids, test_pids, 'mail.message notification partners incorrect')
332 # Test: sent_email: email_to should contain b@b, not c@c (pref email), not a@a (writer)
333 for sent_email in sent_emails:
334 self.assertEqual(sent_email['email_to'], ['b@b'], 'sent_email email_to is incorrect')
336 # CASE2: post an email with attachments, parent_id, partner_ids
337 # TESTS: automatic subject, signature in body_html, attachments propagation
338 self._init_mock_build_email()
339 msg_id2 = self.mail_group.message_post(cr, uid, self.group_pigs_id, body=_body2, type='email',
340 partner_ids=[(6, 0, [p_d_id])], parent_id=msg_id, attachments=_attachments)
341 message = self.mail_message.browse(cr, uid, msg_id2)
342 sent_emails = self._build_email_kwargs_list
343 self.assertFalse(self.mail_mail.search(cr, uid, [('mail_message_id', '=', msg_id2)]), 'mail.mail notifications should have been auto-deleted!')
345 # Test: mail_message: subject is False, body is _body2 (no formatting done), parent_id is msg_id
346 self.assertEqual(message.subject, False, 'mail.message subject incorrect')
347 self.assertEqual(message.body, html_sanitize(_body2), 'mail.message body incorrect')
348 self.assertEqual(message.parent_id.id, msg_id, 'mail.message parent_id incorrect')
349 # Test: sent_email: email send by server: correct subject, body, body_alternative
350 self.assertEqual(len(sent_emails), 2, 'sent_email number of sent emails incorrect')
351 for sent_email in sent_emails:
352 self.assertEqual(sent_email['subject'], _mail_subject, 'sent_email subject incorrect')
353 self.assertIn(_mail_body2, sent_email['body'], 'sent_email body incorrect')
354 self.assertIn(_mail_bodyalt2, sent_email['body_alternative'], 'sent_email body_alternative incorrect')
355 # Test: mail_message: partner_ids = group followers
356 message_pids = set([partner.id for partner in message.partner_ids])
357 test_pids = set([p_a_id, p_b_id, p_c_id, p_d_id])
358 self.assertEqual(message_pids, test_pids, 'mail.message partners incorrect')
359 # Test: notifications linked to this message = group followers = partner_ids
360 notif_ids = self.mail_notification.search(cr, uid, [('message_id', '=', message.id)])
361 notif_pids = set([notif.partner_id.id for notif in self.mail_notification.browse(cr, uid, notif_ids)])
362 self.assertEqual(notif_pids, test_pids, 'mail.message notification partners incorrect')
363 # Test: sent_email: email_to should contain b@b, c@c, not a@a (writer)
364 for sent_email in sent_emails:
365 self.assertTrue(set(sent_email['email_to']).issubset(set(['b@b', 'c@c'])), 'sent_email email_to incorrect')
367 for attach in message.attachment_ids:
368 self.assertEqual(attach.res_model, 'mail.group', 'mail.message attachment res_model incorrect')
369 self.assertEqual(attach.res_id, self.group_pigs_id, 'mail.message attachment res_id incorrect')
370 self.assertIn((attach.name, attach.datas.decode('base64')), _attachments,
371 'mail.message attachment name / data incorrect')
373 def test_21_message_compose_wizard(self):
374 """ Tests designed for the mail.compose.message wizard. """
375 cr, uid = self.cr, self.uid
376 mail_compose = self.registry('mail.compose.message')
377 self.res_users.write(cr, uid, [uid], {'signature': 'Admin', 'email': 'a@a'})
378 user_admin = self.res_users.browse(cr, uid, uid)
379 group_pigs = self.mail_group.browse(cr, uid, self.group_pigs_id)
380 group_bird_id = self.mail_group.create(cr, uid, {'name': 'Bird', 'description': 'Bird resistance'})
381 group_bird = self.mail_group.browse(cr, uid, group_bird_id)
385 _body_text = 'Pigs rules'
386 _msg_reply = 'Re: Pigs'
387 _msg_body = '<pre>Pigs rules</pre>'
389 {'name': 'First', 'datas_fname': 'first.txt', 'datas': 'My first attachment'.encode('base64')},
390 {'name': 'Second', 'datas_fname': 'second.txt', 'datas': 'My second attachment'.encode('base64')}
392 _attachments_test = [('first.txt', 'My first attachment'), ('second.txt', 'My second attachment')]
396 p_a_id = user_admin.partner_id.id
397 # 1 - Bert Tartopoils, with email, should receive emails for comments and emails
398 p_b_id = self.res_partner.create(cr, uid, {'name': 'Bert Tartopoils', 'email': 'b@b'})
399 # 2 - Carine Poilvache, with email, should never receive emails
400 p_c_id = self.res_partner.create(cr, uid, {'name': 'Carine Poilvache', 'email': 'c@c', 'notification_email_send': 'email'})
401 # 3 - Dédé Grosbedon, without email, to test email verification; should receive emails for every message
402 p_d_id = self.res_partner.create(cr, uid, {'name': 'Dédé Grosbedon', 'notification_email_send': 'all'})
405 group_pigs.message_subscribe([p_b_id])
407 # ----------------------------------------
408 # CASE1: comment on group_pigs
409 # ----------------------------------------
411 # 1. Comment group_pigs with body_text and subject
412 compose_id = mail_compose.create(cr, uid,
413 {'subject': _subject, 'body_text': _body_text, 'partner_ids': [(4, p_c_id), (4, p_d_id)]},
414 {'default_composition_mode': 'comment', 'default_model': 'mail.group', 'default_res_id': self.group_pigs_id})
415 compose = mail_compose.browse(cr, uid, compose_id)
416 # Test: mail.compose.message: composition_mode, model, res_id
417 self.assertEqual(compose.composition_mode, 'comment', 'mail.compose.message incorrect composition_mode')
418 self.assertEqual(compose.model, 'mail.group', 'mail.compose.message incorrect model')
419 self.assertEqual(compose.res_id, self.group_pigs_id, 'mail.compose.message incorrect res_id')
421 # 2. Post the comment, get created message
422 mail_compose.send_mail(cr, uid, [compose_id])
424 message = group_pigs.message_ids[0]
425 # Test: mail.message: subject, body inside pre
426 self.assertEqual(message.subject, False, 'mail.message incorrect subject')
427 self.assertEqual(message.body, _msg_body, 'mail.message incorrect body')
428 # Test: mail.message: partner_ids = entries in mail.notification: group_pigs fans (a, b) + mail.compose.message partner_ids (c, d)
429 msg_pids = [partner.id for partner in message.partner_ids]
430 test_pids = [p_a_id, p_b_id, p_c_id, p_d_id]
431 notif_ids = self.mail_notification.search(cr, uid, [('message_id', '=', message.id)])
432 self.assertEqual(len(notif_ids), 4, 'mail.message: too much notifications created')
433 self.assertEqual(set(msg_pids), set(test_pids), 'mail.message partner_ids incorrect')
435 # ----------------------------------------
436 # CASE2: reply to last comment with attachments
437 # ----------------------------------------
439 # 1. Update last comment subject, reply with attachments
440 message.write({'subject': _subject})
441 compose_id = mail_compose.create(cr, uid,
442 {'attachment_ids': [(0, 0, _attachments[0]), (0, 0, _attachments[1])]},
443 {'default_composition_mode': 'reply', 'default_model': 'mail.thread', 'default_res_id': self.group_pigs_id, 'default_parent_id': message.id})
444 compose = mail_compose.browse(cr, uid, compose_id)
445 # Test: model, res_id, parent_id, content_subtype
446 self.assertEqual(compose.model, 'mail.group', 'mail.compose.message incorrect model')
447 self.assertEqual(compose.res_id, self.group_pigs_id, 'mail.compose.message incorrect res_id')
448 self.assertEqual(compose.parent_id.id, message.id, 'mail.compose.message incorrect parent_id')
449 self.assertEqual(compose.content_subtype, 'html', 'mail.compose.message incorrect content_subtype')
451 # 2. Post the comment, get created message
452 parent_id = message.id
453 mail_compose.send_mail(cr, uid, [compose_id])
455 message = group_pigs.message_ids[0]
456 # Test: mail.message: subject as Re:.., body in html, parent_id
457 self.assertEqual(message.subject, _msg_reply, 'mail.message incorrect subject')
458 self.assertIn('Administrator wrote:<blockquote><pre>Pigs rules</pre></blockquote></div>', message.body, 'mail.message body is incorrect')
459 self.assertEqual(message.parent_id and message.parent_id.id, parent_id, 'mail.message parent_id incorrect')
460 # Test: mail.message: attachments
461 for attach in message.attachment_ids:
462 self.assertEqual(attach.res_model, 'mail.group', 'mail.message attachment res_model incorrect')
463 self.assertEqual(attach.res_id, self.group_pigs_id, 'mail.message attachment res_id incorrect')
464 self.assertIn((attach.name, attach.datas.decode('base64')), _attachments_test,
465 'mail.message attachment name / data incorrect')
467 # ----------------------------------------
468 # CASE3: mass_mail on Pigs and Bird
469 # ----------------------------------------
471 # 1. mass_mail on pigs and bird
472 compose_id = mail_compose.create(cr, uid,
473 {'subject': _subject, 'body': '${object.description}'},
474 {'default_composition_mode': 'mass_mail', 'default_model': 'mail.group', 'default_res_id': -1,
475 'active_ids': [self.group_pigs_id, group_bird_id]})
476 compose = mail_compose.browse(cr, uid, compose_id)
477 # Test: content_subtype is html
478 self.assertEqual(compose.content_subtype, 'html', 'mail.compose.message content_subtype incorrect')
480 # 2. Post the comment, get created message for each group
481 mail_compose.send_mail(cr, uid, [compose_id],
482 context={'default_res_id': -1, 'active_ids': [self.group_pigs_id, group_bird_id]})
485 message1 = group_pigs.message_ids[0]
486 message2 = group_bird.message_ids[0]
487 # Test: Pigs and Bird did receive their message
488 test_msg_ids = self.mail_message.search(cr, uid, [], limit=2)
489 self.assertIn(message1.id, test_msg_ids, 'Pigs did not receive its mass mailing message')
490 self.assertIn(message2.id, test_msg_ids, 'Bird did not receive its mass mailing message')
491 # Test: mail.message: subject, body
492 self.assertEqual(message1.subject, _subject, 'mail.message subject incorrect')
493 self.assertEqual(message1.body, group_pigs.description, 'mail.message body incorrect')
494 self.assertEqual(message2.subject, _subject, 'mail.message subject incorrect')
495 self.assertEqual(message2.body, group_bird.description, 'mail.message body incorrect')
497 def test_30_message_read(self):
498 """ Tests designed for message_read. """
499 # TDE NOTE: this test is not finished, as the message_read method is not fully specified.
500 # It will be updated as soon as we have fixed specs !
501 cr, uid = self.cr, self.uid
502 group_pigs = self.mail_group.browse(cr, uid, self.group_pigs_id)
504 def _compare_structures(struct1, struct2, n=0):
505 # print '%scompare structure' % ('\t' * n)
506 self.assertEqual(len(struct1), len(struct2), 'message_read structure number of childs incorrect')
507 for x in range(len(struct1)):
508 # print '%s' % ('\t' * n), struct1[x]['id'], struct2[x]['id'], struct1[x].get('subject') or ''
509 self.assertEqual(struct1[x]['id'], struct2[x]['id'], 'message_read failure %s' % struct1[x].get('subject'))
510 _compare_structures(struct1[x]['child_ids'], struct2[x]['child_ids'], n + 1)
511 # print '%send compare' % ('\t' * n)
513 # ----------------------------------------
514 # CASE1: Flattening test
515 # ----------------------------------------
517 # Create dummy message structure
519 tree = [{'id': 2, 'child_ids': [
520 {'id': 6, 'child_ids': [
521 {'id': 8, 'child_ids': []},
524 {'id': 1, 'child_ids':[
525 {'id': 7, 'child_ids': [
526 {'id': 9, 'child_ids': []},
528 {'id': 4, 'child_ids': [
529 {'id': 10, 'child_ids': []},
530 {'id': 5, 'child_ids': []},
532 {'id': 3, 'child_ids': []},
535 # Test: completely flat
536 new_tree = self.mail_message.message_read_tree_flatten(cr, uid, copy.deepcopy(tree), 0, 0)
537 self.assertEqual(len(new_tree), 10, 'message_read_tree_flatten wrong in flat')
538 # Test: 1 thread level
539 tree_test = [{'id': 2, 'child_ids': [
540 {'id': 8, 'child_ids': []}, {'id': 6, 'child_ids': []},
542 {'id': 1, 'child_ids': [
543 {'id': 10, 'child_ids': []}, {'id': 9, 'child_ids': []},
544 {'id': 7, 'child_ids': []}, {'id': 5, 'child_ids': []},
545 {'id': 4, 'child_ids': []}, {'id': 3, 'child_ids': []},
548 new_tree = self.mail_message.message_read_tree_flatten(cr, uid, copy.deepcopy(tree), 0, 1)
549 _compare_structures(new_tree, tree_test)
550 # Test: 2 thread levels
551 new_tree = self.mail_message.message_read_tree_flatten(cr, uid, copy.deepcopy(tree), 0, 2)
552 _compare_structures(new_tree, tree)
554 # ----------------------------------------
555 # CASE2: message_read test
556 # ----------------------------------------
558 # 1. Add a few messages to pigs group
559 msgid1 = group_pigs.message_post(body='1', subject='1', parent_id=False)
560 msgid2 = group_pigs.message_post(body='2', subject='1-1', parent_id=msgid1)
561 msgid3 = group_pigs.message_post(body='3', subject='1-2', parent_id=msgid1)
562 msgid4 = group_pigs.message_post(body='4', subject='2', parent_id=False)
563 msgid5 = group_pigs.message_post(body='5', subject='1-1-1', parent_id=msgid2)
564 msgid6 = group_pigs.message_post(body='6', subject='2-1', parent_id=msgid4)
566 # Test: read all messages flat
567 tree_test = [{'id': msgid6, 'child_ids': []}, {'id': msgid5, 'child_ids': []},
568 {'id': msgid4, 'child_ids': []}, {'id': msgid3, 'child_ids': []},
569 {'id': msgid2, 'child_ids': []}, {'id': msgid1, 'child_ids': []}]
570 tree = self.mail_message.message_read(cr, uid, ids=False, domain=[('model', '=', 'mail.group'), ('res_id', '=', self.group_pigs_id)], thread_level=0, limit=10)
571 _compare_structures(tree, tree_test)
572 # Test: read with 1 level of thread
573 tree_test = [{'id': msgid4, 'child_ids': [{'id': msgid6, 'child_ids': []}, ]},
574 {'id': msgid1, 'child_ids': [
575 {'id': msgid5, 'child_ids': []}, {'id': msgid3, 'child_ids': []},
576 {'id': msgid2, 'child_ids': []},
579 tree = self.mail_message.message_read(cr, uid, ids=False, domain=[('model', '=', 'mail.group'), ('res_id', '=', self.group_pigs_id)], thread_level=1, limit=10)
580 _compare_structures(tree, tree_test)
581 # Test: read with 2 levels of thread
582 tree_test = [{'id': msgid4, 'child_ids': [{'id': msgid6, 'child_ids': []}, ]},
583 {'id': msgid1, 'child_ids': [
584 {'id': msgid3, 'child_ids': []},
585 {'id': msgid2, 'child_ids': [{'id': msgid5, 'child_ids': []}, ]},
588 tree = self.mail_message.message_read(cr, uid, ids=False, domain=[('model', '=', 'mail.group'), ('res_id', '=', self.group_pigs_id)], thread_level=2, limit=10)
589 _compare_structures(tree, tree_test)
591 # 2. Test expandables
592 # TDE FIXME: add those tests when expandables are specified and implemented
594 def test_40_needaction(self):
595 """ Tests for mail.message needaction. """
596 cr, uid = self.cr, self.uid
597 group_pigs = self.mail_group.browse(cr, uid, self.group_pigs_id)
598 user_admin = self.res_users.browse(cr, uid, uid)
600 # Demo values: check unread notification = needaction on mail.message
601 notif_ids = self.mail_notification.search(cr, uid, [
602 ('partner_id', '=', user_admin.partner_id.id),
605 na_count = self.mail_message._needaction_count(cr, uid, domain=[])
606 self.assertEqual(len(notif_ids), na_count, 'unread notifications count does not match needaction count')
608 # Post 4 message on group_pigs
609 for dummy in range(4):
610 group_pigs.message_post(body='My Body')
612 # Check there are 4 new needaction on mail.message
613 notif_ids = self.mail_notification.search(cr, uid, [
614 ('partner_id', '=', user_admin.partner_id.id),
617 na_count = self.mail_message._needaction_count(cr, uid, domain=[])
618 self.assertEqual(len(notif_ids), na_count, 'unread notifications count does not match needaction count')
620 # Check there are 4 needaction on mail.message with particular domain
621 na_count = self.mail_message._needaction_count(cr, uid, domain=[('model', '=', 'mail.group'), ('res_id', '=', self.group_pigs_id)])
622 self.assertEqual(na_count, 4, 'posted message count does not match needaction count')
624 def test_50_thread_parent_resolution(self):
625 """Verify parent/child relationships are correctly established when processing incoming mails"""
626 cr, uid = self.cr, self.uid
627 group_pigs = self.mail_group.browse(cr, uid, self.group_pigs_id)
628 msg1 = group_pigs.message_post(body='My Body', subject='1')
629 msg2 = group_pigs.message_post(body='My Body', subject='2')
630 msg1, msg2 = self.mail_message.browse(cr, uid, [msg1, msg2])
631 self.assertTrue(msg1.message_id, "New message should have a proper message_id")
633 # Reply to msg1, make sure the reply is properly attached using the various reply identification mechanisms
634 # 1. In-Reply-To header
635 reply_msg = MAIL_TEMPLATE.format(to='Pretty Pigs <group+pigs@example.com>, other@gmail.com', subject='Re: 1',
636 extra='In-Reply-To: %s' % msg1.message_id)
637 self.mail_thread.message_process(cr, uid, None, reply_msg)
638 # 2. References header
639 reply_msg2 = MAIL_TEMPLATE.format(to='Pretty Pigs <group+pigs@example.com>, other@gmail.com', subject='Re: Re: 1',
640 extra='References: <2233@a.com>\r\n\t<3edss_dsa@b.com> %s' % msg1.message_id)
641 self.mail_thread.message_process(cr, uid, None, reply_msg2)
642 # 3. Subject contains [<ID>] + model passed to message+process -> only attached to group, not to mail
643 reply_msg3 = MAIL_TEMPLATE.format(to='Pretty Pigs <group+pigs@example.com>, other@gmail.com',
644 extra='', subject='Re: [%s] 1' % self.group_pigs_id)
645 self.mail_thread.message_process(cr, uid, 'mail.group', reply_msg3)
648 self.assertEqual(5, len(group_pigs.message_ids), 'group should contain 5 messages')
649 self.assertEqual(2, len(msg1.child_ids), 'msg1 should have 2 children now')
651 def test_60_vote(self):
652 """ Test designed for the vote/unvote feature. """
653 cr, uid = self.cr, self.uid
654 group_pigs = self.mail_group.browse(cr, uid, self.group_pigs_id)
655 user_admin = self.res_users.browse(cr, uid, uid)
656 msg1 = group_pigs.message_post(body='My Body', subject='1')
657 msg1 = self.mail_message.browse(cr, uid, msg1)
659 # Create user Bert Tartopoils
660 user_bert_id = self.res_users.create(cr, uid, {'name': 'Bert', 'login': 'bert'})
661 user_bert = self.res_users.browse(cr, uid, user_bert_id)
663 # Test: msg1 and msg2 have void vote_user_ids
664 self.assertFalse(msg1.vote_user_ids, 'newly created message msg1 has not void vote_user_ids')
665 # Do: Admin vote for msg1
666 self.mail_message.vote_toggle(cr, uid, [msg1.id])
668 # Test: msg1 has Admin as voter
669 self.assertEqual(set(msg1.vote_user_ids), set([user_admin]), 'after voting, Admin is not the voter')
670 # Do: Bert vote for msg1
671 self.mail_message.vote_toggle(cr, uid, [msg1.id], [user_bert_id])
673 # Test: msg1 has Admin and Bert as voters
674 self.assertEqual(set(msg1.vote_user_ids), set([user_admin, user_bert]), 'after voting, Admin and Bert are not the voters')
675 # Do: Admin unvote for msg1
676 self.mail_message.vote_toggle(cr, uid, [msg1.id])
678 # Test: msg1 has Bert as voter
679 self.assertEqual(set(msg1.vote_user_ids), set([user_bert]), 'after unvoting for Admin, Bert is not the voter')