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 ##############################################################################
22 from openerp.tests import common
23 from openerp.tools.html_sanitize import html_sanitize
25 MAIL_TEMPLATE = """Return-Path: <whatever-2a840@postmaster.twitter.com>
27 Received: by mail1.openerp.com (Postfix, from userid 10002)
28 id 5DF9ABFB2A; Fri, 10 Aug 2012 16:16:39 +0200 (CEST)
29 From: Sylvie Lelitre <sylvie.lelitre@agrolait.com>
32 Content-Type: multipart/alternative;
33 boundary="----=_Part_4200734_24778174.1344608186754"
34 Date: Fri, 10 Aug 2012 14:16:26 +0000
35 Message-ID: <1198923581.41972151344608186760.JavaMail@agrolait.com>
37 ------=_Part_4200734_24778174.1344608186754
38 Content-Type: text/plain; charset=utf-8
39 Content-Transfer-Encoding: quoted-printable
41 Please call me as soon as possible this afternoon!
45 ------=_Part_4200734_24778174.1344608186754
46 Content-Type: text/html; charset=utf-8
47 Content-Transfer-Encoding: quoted-printable
49 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
52 <meta http-equiv=3D"Content-Type" content=3D"text/html; charset=3Dutf-8" />
54 <body style=3D"margin: 0; padding: 0; background: #ffffff;-webkit-text-size-adjust: 100%;">=20
56 <p>Please call me as soon as possible this afternoon!</p>
63 ------=_Part_4200734_24778174.1344608186754--
66 MAIL_TEMPLATE_PLAINTEXT = """Return-Path: <whatever-2a840@postmaster.twitter.com>
68 Received: by mail1.openerp.com (Postfix, from userid 10002)
69 id 5DF9ABFB2A; Fri, 10 Aug 2012 16:16:39 +0200 (CEST)
70 From: Sylvie Lelitre <sylvie.lelitre@agrolait.com>
73 Content-Type: text/plain
74 Date: Fri, 10 Aug 2012 14:16:26 +0000
78 Please call me as soon as possible this afternoon!
85 class test_mail(common.TransactionCase):
87 def _mock_smtp_gateway(self, *args, **kwargs):
90 def _mock_build_email(self, *args, **kwargs):
91 self._build_email_args = args
92 self._build_email_kwargs = kwargs
93 return self.build_email_real(*args, **kwargs)
96 super(test_mail, self).setUp()
97 self.ir_model = self.registry('ir.model')
98 self.mail_alias = self.registry('mail.alias')
99 self.mail_thread = self.registry('mail.thread')
100 self.mail_group = self.registry('mail.group')
101 self.mail_mail = self.registry('mail.mail')
102 self.mail_message = self.registry('mail.message')
103 self.mail_notification = self.registry('mail.notification')
104 self.mail_followers = self.registry('mail.followers')
105 self.res_users = self.registry('res.users')
106 self.res_partner = self.registry('res.partner')
108 # Install mock SMTP gateway
109 self.build_email_real = self.registry('ir.mail_server').build_email
110 self.registry('ir.mail_server').build_email = self._mock_build_email
111 self.registry('ir.mail_server').send_email = self._mock_smtp_gateway
113 # groups@.. will cause the creation of new mail groups
114 self.mail_group_model_id = self.ir_model.search(self.cr, self.uid, [('model', '=', 'mail.group')])[0]
115 self.mail_alias.create(self.cr, self.uid, {'alias_name': 'groups',
116 'alias_model_id': self.mail_group_model_id})
117 # create a 'pigs' group that will be used through the various tests
118 self.group_pigs_id = self.mail_group.create(self.cr, self.uid,
119 {'name': 'Pigs', 'description': 'Fans of Pigs, unite !'})
121 def test_00_message_process(self):
122 cr, uid = self.cr, self.uid
123 # Incoming mail creates a new mail_group "frogs"
124 self.assertEqual(self.mail_group.search(cr, uid, [('name', '=', 'frogs')]), [])
125 mail_frogs = MAIL_TEMPLATE.format(to='groups@example.com, other@gmail.com', subject='frogs', extra='')
126 self.mail_thread.message_process(cr, uid, None, mail_frogs)
127 frog_groups = self.mail_group.search(cr, uid, [('name', '=', 'frogs')])
128 self.assertTrue(len(frog_groups) == 1)
130 # Previously-created group can be emailed now - it should have an implicit alias group+frogs@...
131 frog_group = self.mail_group.browse(cr, uid, frog_groups[0])
132 group_messages = frog_group.message_ids
133 self.assertTrue(len(group_messages) == 1, 'New group should only have the original message')
134 mail_frog_news = MAIL_TEMPLATE.format(to='Friendly Frogs <group+frogs@example.com>', subject='news', extra='')
135 self.mail_thread.message_process(cr, uid, None, mail_frog_news)
137 self.assertTrue(len(frog_group.message_ids) == 2, 'Group should contain 2 messages now')
139 # Even with a wrong destination, a reply should end up in the correct thread
140 mail_reply = MAIL_TEMPLATE.format(to='erroneous@example.com>', subject='Re: news',
141 extra='In-Reply-To: <12321321-openerp-%d-mail.group@example.com>\n' % frog_group.id)
142 self.mail_thread.message_process(cr, uid, None, mail_reply)
144 self.assertTrue(len(frog_group.message_ids) == 3, 'Group should contain 3 messages now')
146 # No model passed and no matching alias must raise
147 mail_spam = MAIL_TEMPLATE.format(to='noone@example.com', subject='spam', extra='')
148 self.assertRaises(Exception,
149 self.mail_thread.message_process,
150 cr, uid, None, mail_spam)
152 # plain text content should be wrapped and stored as html
153 test_msg_id = '<deadcafe.1337@smtp.agrolait.com>'
154 mail_text = MAIL_TEMPLATE_PLAINTEXT.format(to='groups@example.com', subject='frogs', extra='', msg_id=test_msg_id)
155 self.mail_thread.message_process(cr, uid, None, mail_text)
156 new_mail = self.mail_message.browse(cr, uid, self.mail_message.search(cr, uid, [('message_id','=',test_msg_id)])[0])
157 self.assertEqual(new_mail.body, '\n<pre>\nPlease call me as soon as possible this afternoon!\n\n--\nSylvie\n</pre>\n',
158 'plaintext mail incorrectly parsed')
160 def test_10_many2many_reference_field(self):
161 """ Tests designed for the many2many_reference field (follower_ids).
162 We will test to perform writes using the many2many commands 0, 3, 4,
164 cr, uid = self.cr, self.uid
165 user_admin = self.res_users.browse(cr, uid, uid)
166 group_pigs = self.mail_group.browse(cr, uid, self.group_pigs_id)
168 # Create partner Bert Poilu
169 partner_bert_id = self.res_partner.create(cr, uid, {'name': 'Bert Poilu'})
171 # Create 'disturbing' values in mail.followers: same res_id, other res_model; same res_model, other res_id
172 group_dummy_id = self.mail_group.create(cr, uid,
173 {'name': 'Dummy group'})
174 self.mail_followers.create(cr, uid,
175 {'res_model': 'mail.thread', 'res_id': self.group_pigs_id, 'partner_id': partner_bert_id})
176 self.mail_followers.create(cr, uid,
177 {'res_model': 'mail.group', 'res_id': group_dummy_id, 'partner_id': partner_bert_id})
179 # Pigs just created: should be only Admin as follower
180 follower_ids = set([follower.id for follower in group_pigs.message_follower_ids])
181 self.assertEqual(follower_ids, set([user_admin.partner_id.id]), 'Admin should be the only Pigs fan')
183 # Subscribe Bert through a '4' command
184 group_pigs.write({'message_follower_ids': [(4, partner_bert_id)]})
186 follower_ids = set([follower.id for follower in group_pigs.message_follower_ids])
187 self.assertEqual(follower_ids, set([partner_bert_id, user_admin.partner_id.id]), 'Bert and Admin should be the only Pigs fans')
189 # Unsubscribe Bert through a '3' command
190 group_pigs.write({'message_follower_ids': [(3, partner_bert_id)]})
192 follower_ids = set([follower.id for follower in group_pigs.message_follower_ids])
193 self.assertEqual(follower_ids, set([user_admin.partner_id.id]), 'Admin should be the only Pigs fan')
195 # Set followers through a '6' command
196 group_pigs.write({'message_follower_ids': [(6, 0, [partner_bert_id])]})
198 follower_ids = set([follower.id for follower in group_pigs.message_follower_ids])
199 self.assertEqual(follower_ids, set([partner_bert_id]), 'Bert should be the only Pigs fan')
201 # Add a follower created on the fly through a '0' command
202 group_pigs.write({'message_follower_ids': [(0, 0, {'name': 'Patrick Fiori'})]})
203 partner_patrick_id = self.res_partner.search(cr, uid, [('name', '=', 'Patrick Fiori')])[0]
205 follower_ids = set([follower.id for follower in group_pigs.message_follower_ids])
206 self.assertEqual(follower_ids, set([partner_bert_id, partner_patrick_id]), 'Bert and Patrick should be the only Pigs fans')
208 # Finally, unlink through a '5' command
209 group_pigs.write({'message_follower_ids': [(5, 0)]})
211 follower_ids = set([follower.id for follower in group_pigs.message_follower_ids])
212 self.assertFalse(follower_ids, 'Pigs group should not have fans anymore')
214 # Test dummy data has not been altered
215 fol_obj_ids = self.mail_followers.search(cr, uid, [('res_model', '=', 'mail.thread'), ('res_id', '=', self.group_pigs_id)])
216 follower_ids = set([follower.partner_id.id for follower in self.mail_followers.browse(cr, uid, fol_obj_ids)])
217 self.assertEqual(follower_ids, set([partner_bert_id]), 'Bert should be the follower of dummy mail.thread data')
218 fol_obj_ids = self.mail_followers.search(cr, uid, [('res_model', '=', 'mail.group'), ('res_id', '=', group_dummy_id)])
219 follower_ids = set([follower.partner_id.id for follower in self.mail_followers.browse(cr, uid, fol_obj_ids)])
220 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')
222 def test_11_message_followers(self):
223 """ Tests designed for the subscriber API. """
224 cr, uid = self.cr, self.uid
225 user_admin = self.res_users.browse(cr, uid, uid)
226 group_pigs = self.mail_group.browse(cr, uid, self.group_pigs_id)
229 user_raoul_id = self.res_users.create(cr, uid, {'name': 'Raoul Grosbedon', 'login': 'raoul'})
230 user_raoul = self.res_users.browse(cr, uid, user_raoul_id)
232 # Subscribe Raoul three times (niak niak) through message_subscribe_users
233 group_pigs.message_subscribe_users([user_raoul_id, user_raoul_id])
234 group_pigs.message_subscribe_users([user_raoul_id])
236 follower_ids = [follower.id for follower in group_pigs.message_follower_ids]
237 self.assertEqual(len(follower_ids), 2, 'There should be 2 Pigs fans')
238 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')
240 # Unsubscribe Raoul twice through message_unsubscribe_users
241 group_pigs.message_unsubscribe_users([user_raoul_id, user_raoul_id])
243 follower_ids = [follower.id for follower in group_pigs.message_follower_ids]
244 self.assertEqual(follower_ids, [user_admin.partner_id.id], 'Admin must be the only Pigs fan')
246 def test_20_message_post(self):
247 """ Tests designed for message_post. """
248 cr, uid = self.cr, self.uid
249 self.res_users.write(cr, uid, [uid], {'signature': 'Admin', 'email': 'a@a'})
250 user_admin = self.res_users.browse(cr, uid, uid)
251 group_pigs = self.mail_group.browse(cr, uid, self.group_pigs_id)
254 p_a_id = user_admin.partner_id.id
255 # 1 - Bert Tartopoils, with email, should receive emails for comments and emails
256 p_b_id = self.res_partner.create(cr, uid, {'name': 'Bert Tartopoils', 'email': 'b@b'})
257 # 2 - Carine Poilvache, with email, should never receive emails
258 p_c_id = self.res_partner.create(cr, uid, {'name': 'Carine Poilvache', 'email': 'c@c', 'notification_email_send': 'email'})
259 # 3 - Dédé Grosbedon, without email, to test email verification; should receive emails for every message
260 p_d_id = self.res_partner.create(cr, uid, {'name': 'Dédé Grosbedon', 'notification_email_send': 'all'})
263 group_pigs.message_subscribe([p_b_id, p_c_id])
267 _mail_subject = '%s posted on %s' % (user_admin.name, group_pigs.name)
268 _body1 = 'Pigs rules'
269 _mail_body1 = 'Pigs rules\n<pre>Admin</pre>\n'
270 _mail_bodyalt1 = 'Pigs rules\nAdmin'
271 _body2 = '<html>Pigs rules</html>'
272 _mail_body2 = html_sanitize('<html>Pigs rules\n<pre>Admin</pre>\n</html>')
273 _mail_bodyalt2 = 'Pigs rules\nAdmin'
274 _attachments = [('First', 'My first attachment'), ('Second', 'My second attachment')]
276 # CASE1: post comment, body and subject specified
277 msg_id = self.mail_group.message_post(cr, uid, self.group_pigs_id, body=_body1, subject=_subject, type='comment')
278 message = self.mail_message.browse(cr, uid, msg_id)
279 sent_email = self._build_email_kwargs
280 # Test: notifications have been deleted
281 self.assertFalse(self.mail_mail.search(cr, uid, [('mail_message_id', '=', msg_id)]), 'mail.mail notifications should have been auto-deleted!')
282 # Test: mail_message: subject is _subject, body is _body1 (no formatting done)
283 self.assertEqual(message.subject, _subject, 'mail.message subject incorrect')
284 self.assertEqual(message.body, _body1, 'mail.message body incorrect')
285 # Test: sent_email: email send by server: correct subject, body; body_alternative
286 self.assertEqual(sent_email['subject'], _subject, 'sent_email subject incorrect')
287 self.assertEqual(sent_email['body'], _mail_body1, 'sent_email body incorrect')
288 self.assertEqual(sent_email['body_alternative'], _mail_bodyalt1, 'sent_email body_alternative is incorrect')
289 # Test: mail_message: partner_ids = group followers
290 message_pids = set([partner.id for partner in message.partner_ids])
291 test_pids = set([p_a_id, p_b_id, p_c_id])
292 self.assertEqual(test_pids, message_pids, 'mail.message partners incorrect')
293 # Test: notification linked to this message = group followers = partner_ids
294 notif_ids = self.mail_notification.search(cr, uid, [('message_id', '=', message.id)])
295 notif_pids = set([notif.partner_id.id for notif in self.mail_notification.browse(cr, uid, notif_ids)])
296 self.assertEqual(notif_pids, test_pids, 'mail.message notification partners incorrect')
297 # Test: sent_email: email_to should contain b@b, not c@c (pref email), not a@a (writer)
298 self.assertEqual(sent_email['email_to'], ['b@b'], 'sent_email email_to is incorrect')
300 # CASE2: post an email with attachments, parent_id, partner_ids
301 # TESTS: automatic subject, signature in body_html, attachments propagation
302 msg_id2 = self.mail_group.message_post(cr, uid, self.group_pigs_id, body=_body2, type='email',
303 partner_ids=[(6, 0, [p_d_id])], parent_id=msg_id, attachments=_attachments)
304 message = self.mail_message.browse(cr, uid, msg_id2)
305 sent_email = self._build_email_kwargs
306 self.assertFalse(self.mail_mail.search(cr, uid, [('mail_message_id', '=', msg_id2)]), 'mail.mail notifications should have been auto-deleted!')
308 # Test: mail_message: subject is False, body is _body2 (no formatting done), parent_id is msg_id
309 self.assertEqual(message.subject, False, 'mail.message subject incorrect')
310 self.assertEqual(message.body, html_sanitize(_body2), 'mail.message body incorrect')
311 self.assertEqual(message.parent_id.id, msg_id, 'mail.message parent_id incorrect')
312 # Test: sent_email: email send by server: correct subject, body, body_alternative
313 self.assertEqual(sent_email['subject'], _mail_subject, 'sent_email subject incorrect')
314 self.assertEqual(sent_email['body'], _mail_body2, 'sent_email body incorrect')
315 self.assertEqual(sent_email['body_alternative'], _mail_bodyalt2, 'sent_email body_alternative incorrect')
316 # Test: mail_message: partner_ids = group followers
317 message_pids = set([partner.id for partner in message.partner_ids])
318 test_pids = set([p_a_id, p_b_id, p_c_id, p_d_id])
319 self.assertEqual(message_pids, test_pids, 'mail.message partners incorrect')
320 # Test: notifications linked to this message = group followers = partner_ids
321 notif_ids = self.mail_notification.search(cr, uid, [('message_id', '=', message.id)])
322 notif_pids = set([notif.partner_id.id for notif in self.mail_notification.browse(cr, uid, notif_ids)])
323 self.assertEqual(notif_pids, test_pids, 'mail.message notification partners incorrect')
324 # Test: sent_email: email_to should contain b@b, c@c, not a@a (writer)
325 self.assertEqual(set(sent_email['email_to']), set(['b@b', 'c@c']), 'sent_email email_to incorrect')
327 for attach in message.attachment_ids:
328 self.assertEqual(attach.res_model, 'mail.group', 'mail.message attachment res_model incorrect')
329 self.assertEqual(attach.res_id, self.group_pigs_id, 'mail.message attachment res_id incorrect')
330 self.assertIn((attach.name, attach.datas.decode('base64')), _attachments,
331 'mail.message attachment name / data incorrect')
333 def test_21_message_compose_wizard(self):
334 """ Tests designed for the mail.compose.message wizard. """
335 cr, uid = self.cr, self.uid
336 mail_compose = self.registry('mail.compose.message')
337 self.res_users.write(cr, uid, [uid], {'signature': 'Admin', 'email': 'a@a'})
338 user_admin = self.res_users.browse(cr, uid, uid)
339 group_pigs = self.mail_group.browse(cr, uid, self.group_pigs_id)
340 group_bird_id = self.mail_group.create(cr, uid, {'name': 'Bird', 'description': 'Bird resistance'})
341 group_bird = self.mail_group.browse(cr, uid, group_bird_id)
345 _body_text = 'Pigs rules'
346 _msg_reply = 'Re: Pigs'
347 _msg_body = '<pre>Pigs rules</pre>'
349 {'name': 'First', 'datas_fname': 'first.txt', 'datas': 'My first attachment'.encode('base64')},
350 {'name': 'Second', 'datas_fname': 'second.txt', 'datas': 'My second attachment'.encode('base64')}
352 _attachments_test = [('first.txt', 'My first attachment'), ('second.txt', 'My second attachment')]
356 p_a_id = user_admin.partner_id.id
357 # 1 - Bert Tartopoils, with email, should receive emails for comments and emails
358 p_b_id = self.res_partner.create(cr, uid, {'name': 'Bert Tartopoils', 'email': 'b@b'})
359 # 2 - Carine Poilvache, with email, should never receive emails
360 p_c_id = self.res_partner.create(cr, uid, {'name': 'Carine Poilvache', 'email': 'c@c', 'notification_email_send': 'email'})
361 # 3 - Dédé Grosbedon, without email, to test email verification; should receive emails for every message
362 p_d_id = self.res_partner.create(cr, uid, {'name': 'Dédé Grosbedon', 'notification_email_send': 'all'})
365 group_pigs.message_subscribe([p_b_id])
367 # ----------------------------------------
368 # CASE1: comment on group_pigs
369 # ----------------------------------------
371 # 1. Comment group_pigs with body_text and subject
372 compose_id = mail_compose.create(cr, uid,
373 {'subject': _subject, 'body_text': _body_text, 'partner_ids': [(4, p_c_id), (4, p_d_id)]},
374 {'default_composition_mode': 'comment', 'default_model': 'mail.group', 'default_res_id': self.group_pigs_id})
375 compose = mail_compose.browse(cr, uid, compose_id)
376 # Test: mail.compose.message: composition_mode, model, res_id
377 self.assertEqual(compose.composition_mode, 'comment', 'mail.compose.message incorrect composition_mode')
378 self.assertEqual(compose.model, 'mail.group', 'mail.compose.message incorrect model')
379 self.assertEqual(compose.res_id, self.group_pigs_id, 'mail.compose.message incorrect res_id')
381 # 2. Post the comment, get created message
382 mail_compose.send_mail(cr, uid, [compose_id])
384 message = group_pigs.message_ids[0]
385 # Test: mail.message: subject, body inside pre
386 self.assertEqual(message.subject, False, 'mail.message incorrect subject')
387 self.assertEqual(message.body, _msg_body, 'mail.message incorrect body')
388 # Test: mail.message: partner_ids = entries in mail.notification: group_pigs fans (a, b) + mail.compose.message partner_ids (c, d)
389 msg_pids = [partner.id for partner in message.partner_ids]
390 test_pids = [p_a_id, p_b_id, p_c_id, p_d_id]
391 notif_ids = self.mail_notification.search(cr, uid, [('message_id', '=', message.id)])
392 self.assertEqual(len(notif_ids), 4, 'mail.message: too much notifications created')
393 self.assertEqual(set(msg_pids), set(test_pids), 'mail.message partner_ids incorrect')
395 # ----------------------------------------
396 # CASE2: reply to last comment with attachments
397 # ----------------------------------------
399 # 1. Update last comment subject, reply with attachments
400 message.write({'subject': _subject})
401 compose_id = mail_compose.create(cr, uid,
402 {'attachment_ids': [(0, 0, _attachments[0]), (0, 0, _attachments[1])]},
403 {'default_composition_mode': 'reply', 'default_model': 'mail.thread', 'default_res_id': self.group_pigs_id, 'default_parent_id': message.id})
404 compose = mail_compose.browse(cr, uid, compose_id)
405 # Test: model, res_id, parent_id, content_subtype
406 self.assertEqual(compose.model, 'mail.group', 'mail.compose.message incorrect model')
407 self.assertEqual(compose.res_id, self.group_pigs_id, 'mail.compose.message incorrect res_id')
408 self.assertEqual(compose.parent_id.id, message.id, 'mail.compose.message incorrect parent_id')
409 self.assertEqual(compose.content_subtype, 'html', 'mail.compose.message incorrect content_subtype')
411 # 2. Post the comment, get created message
412 mail_compose.send_mail(cr, uid, [compose_id])
414 message = group_pigs.message_ids[0]
415 # Test: mail.message: subject as Re:.., body in html
416 self.assertEqual(message.subject, _msg_reply, 'mail.message incorrect subject')
417 self.assertIn('Administrator wrote:<blockquote><pre>Pigs rules</pre></blockquote></div>', message.body, 'mail.message body is incorrect')
418 # Test: mail.message: attachments
419 for attach in message.attachment_ids:
420 self.assertEqual(attach.res_model, 'mail.group', 'mail.message attachment res_model incorrect')
421 self.assertEqual(attach.res_id, self.group_pigs_id, 'mail.message attachment res_id incorrect')
422 self.assertIn((attach.name, attach.datas.decode('base64')), _attachments_test,
423 'mail.message attachment name / data incorrect')
425 # ----------------------------------------
426 # CASE3: mass_mail on Pigs and Bird
427 # ----------------------------------------
429 # 1. mass_mail on pigs and bird
430 compose_id = mail_compose.create(cr, uid,
431 {'subject': _subject, 'body': '${object.description}'},
432 {'default_composition_mode': 'mass_mail', 'default_model': 'mail.group', 'default_res_id': -1,
433 'active_ids': [self.group_pigs_id, group_bird_id]})
434 compose = mail_compose.browse(cr, uid, compose_id)
435 # Test: content_subtype is html
436 self.assertEqual(compose.content_subtype, 'html', 'mail.compose.message content_subtype incorrect')
438 # 2. Post the comment, get created message for each group
439 mail_compose.send_mail(cr, uid, [compose_id],
440 context={'default_res_id': -1, 'active_ids': [self.group_pigs_id, group_bird_id]})
443 message1 = group_pigs.message_ids[0]
444 message2 = group_bird.message_ids[0]
445 # Test: Pigs and Bird did receive their message
446 test_msg_ids = self.mail_message.search(cr, uid, [], limit=2)
447 self.assertIn(message1.id, test_msg_ids, 'Pigs did not receive its mass mailing message')
448 self.assertIn(message2.id, test_msg_ids, 'Bird did not receive its mass mailing message')
449 # Test: mail.message: subject, body
450 self.assertEqual(message1.subject, _subject, 'mail.message subject incorrect')
451 self.assertEqual(message1.body, group_pigs.description, 'mail.message body incorrect')
452 self.assertEqual(message2.subject, _subject, 'mail.message subject incorrect')
453 self.assertEqual(message2.body, group_bird.description, 'mail.message body incorrect')
455 def test_30_message_read(self):
456 """ Tests designed for message_read. """
457 # TDE NOTE: this test is not finished, as the message_read method is not fully specified.
458 # It will be updated as soon as we have fixed specs !
459 cr, uid = self.cr, self.uid
460 group_pigs = self.mail_group.browse(cr, uid, self.group_pigs_id)
461 def _compare_structures(struct1, struct2, n=0):
462 # print '%scompare structure' % ('\t' * n)
463 self.assertEqual(len(struct1), len(struct2), 'message_read structure number of childs incorrect')
464 for x in range(len(struct1)):
465 # print '%s' % ('\t' * n), struct1[x]['id'], struct2[x]['id'], struct1[x].get('subject') or ''
466 self.assertEqual(struct1[x]['id'], struct2[x]['id'], 'message_read failure %s' % struct1[x].get('subject'))
467 _compare_structures(struct1[x]['child_ids'], struct2[x]['child_ids'], n + 1)
468 # print '%send compare' % ('\t' * n)
470 # ----------------------------------------
471 # CASE1: Flattening test
472 # ----------------------------------------
474 # Create dummy message structure
476 tree = [{'id': 2, 'child_ids': [
477 {'id': 6, 'child_ids': [
478 {'id': 8, 'child_ids': []},
481 {'id': 1, 'child_ids':[
482 {'id': 7, 'child_ids': [
483 {'id': 9, 'child_ids': []},
485 {'id': 4, 'child_ids': [
486 {'id': 10, 'child_ids': []},
487 {'id': 5, 'child_ids': []},
489 {'id': 3, 'child_ids': []},
492 # Test: completely flat
493 new_tree = self.mail_message.message_read_tree_flatten(cr, uid, copy.deepcopy(tree), 0, 0)
494 self.assertEqual(len(new_tree), 10, 'message_read_tree_flatten wrong in flat')
495 # Test: 1 thread level
496 tree_test = [{'id': 2, 'child_ids': [
497 {'id': 8, 'child_ids': []}, {'id': 6, 'child_ids': []},
499 {'id': 1, 'child_ids': [
500 {'id': 10, 'child_ids': []}, {'id': 9, 'child_ids': []},
501 {'id': 7, 'child_ids': []}, {'id': 5, 'child_ids': []},
502 {'id': 4, 'child_ids': []}, {'id': 3, 'child_ids': []},
505 new_tree = self.mail_message.message_read_tree_flatten(cr, uid, copy.deepcopy(tree), 0, 1)
506 _compare_structures(new_tree, tree_test)
507 # Test: 2 thread levels
508 new_tree = self.mail_message.message_read_tree_flatten(cr, uid, copy.deepcopy(tree), 0, 2)
509 _compare_structures(new_tree, tree)
511 # ----------------------------------------
512 # CASE2: message_read test
513 # ----------------------------------------
515 # 1. Add a few messages to pigs group
516 msgid1 = group_pigs.message_post(body='1', subject='1', parent_id=False)
517 msgid2 = group_pigs.message_post(body='2', subject='1-1', parent_id=msgid1)
518 msgid3 = group_pigs.message_post(body='3', subject='1-2', parent_id=msgid1)
519 msgid4 = group_pigs.message_post(body='4', subject='2', parent_id=False)
520 msgid5 = group_pigs.message_post(body='5', subject='1-1-1', parent_id=msgid2)
521 msgid6 = group_pigs.message_post(body='6', subject='2-1', parent_id=msgid4)
523 # Test: read all messages flat
524 tree_test = [{'id': msgid6, 'child_ids': []}, {'id': msgid5, 'child_ids': []},
525 {'id': msgid4, 'child_ids': []}, {'id': msgid3, 'child_ids': []},
526 {'id': msgid2, 'child_ids': []}, {'id': msgid1, 'child_ids': []}]
527 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)
528 _compare_structures(tree, tree_test)
529 # Test: read with 1 level of thread
530 tree_test = [{'id': msgid4, 'child_ids': [{'id': msgid6, 'child_ids': []}, ]},
531 {'id': msgid1, 'child_ids': [
532 {'id': msgid5, 'child_ids': []}, {'id': msgid3, 'child_ids': []},
533 {'id': msgid2, 'child_ids': []},
536 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)
537 _compare_structures(tree, tree_test)
538 # Test: read with 2 levels of thread
539 tree_test = [{'id': msgid4, 'child_ids': [{'id': msgid6, 'child_ids': []}, ]},
540 {'id': msgid1, 'child_ids': [
541 {'id': msgid3, 'child_ids': []},
542 {'id': msgid2, 'child_ids': [{'id': msgid5, 'child_ids': []}, ]},
545 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)
546 _compare_structures(tree, tree_test)
548 # 2. Test expandables
549 # TDE FIXME: add those tests when expandables are specified and implemented
551 def test_40_needaction(self):
552 """ Tests for mail.message needaction. """
553 cr, uid = self.cr, self.uid
554 group_pigs = self.mail_group.browse(cr, uid, self.group_pigs_id)
555 user_admin = self.res_users.browse(cr, uid, uid)
557 # Demo values: check unread notification = needaction on mail.message
558 notif_ids = self.mail_notification.search(cr, uid, [
559 ('partner_id', '=', user_admin.partner_id.id),
562 na_count = self.mail_message._needaction_count(cr, uid, domain=[])
563 self.assertEqual(len(notif_ids), na_count, 'unread notifications count does not match needaction count')
565 # Post 4 message on group_pigs
566 for dummy in range(4):
567 group_pigs.message_post(body='My Body')
569 # Check there are 4 new needaction on mail.message
570 notif_ids = self.mail_notification.search(cr, uid, [
571 ('partner_id', '=', user_admin.partner_id.id),
574 na_count = self.mail_message._needaction_count(cr, uid, domain=[])
575 self.assertEqual(len(notif_ids), na_count, 'unread notifications count does not match needaction count')
577 # Check there are 4 needaction on mail.message with particular domain
578 na_count = self.mail_message._needaction_count(cr, uid, domain=[('model', '=', 'mail.group'), ('res_id', '=', self.group_pigs_id)])
579 self.assertEqual(na_count, 4, 'posted message count does not match needaction count')
581 def test_50_thread_parent_resolution(self):
582 """Verify parent/child relationships are correctly established when processing incoming mails"""
583 cr, uid = self.cr, self.uid
584 group_pigs = self.mail_group.browse(cr, uid, self.group_pigs_id)
585 msg1 = group_pigs.message_post(body='My Body', subject='1')
586 msg2 = group_pigs.message_post(body='My Body', subject='2')
587 msg1, msg2 = self.mail_message.browse(cr, uid, [msg1, msg2])
588 self.assertTrue(msg1.message_id, "New message should have a proper message_id")
590 # Reply to msg1, make sure the reply is properly attached using the various reply identification mechanisms
591 # 1. In-Reply-To header
592 reply_msg = MAIL_TEMPLATE.format(to='Pretty Pigs <group+pigs@example.com>, other@gmail.com', subject='Re: 1',
593 extra='In-Reply-To: %s' % msg1.message_id)
594 self.mail_thread.message_process(cr, uid, None, reply_msg)
595 # 2. References header
596 reply_msg2 = MAIL_TEMPLATE.format(to='Pretty Pigs <group+pigs@example.com>, other@gmail.com', subject='Re: Re: 1',
597 extra='References: <2233@a.com>\r\n\t<3edss_dsa@b.com> %s' % msg1.message_id)
598 self.mail_thread.message_process(cr, uid, None, reply_msg2)
599 # 3. Subject contains [<ID>] + model passed to message+process -> only attached to group, not to mail
600 reply_msg3 = MAIL_TEMPLATE.format(to='Pretty Pigs <group+pigs@example.com>, other@gmail.com',
601 extra='', subject='Re: [%s] 1' % self.group_pigs_id)
602 self.mail_thread.message_process(cr, uid, 'mail.group', reply_msg3)
605 self.assertEqual(5, len(group_pigs.message_ids), 'group should contain 5 messages')
606 self.assertEqual(2, len(msg1.child_ids), 'msg1 should have 2 children now')