Code

- new mailgw config item unpack_rfc822 that unpacks message attachments
[roundup.git] / test / test_mailgw.py
1 # -*- encoding: utf-8 -*-
2 #
3 # Copyright (c) 2001 Richard Jones, richard@bofh.asn.au.
4 # This module is free software, and you may redistribute it and/or modify
5 # under the same terms as Python, so long as this copyright message and
6 # disclaimer are retained in their original form.
7 #
8 # This module is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11 #
12 # $Id: test_mailgw.py,v 1.96 2008-08-19 01:40:59 richard Exp $
14 # TODO: test bcc
16 import unittest, tempfile, os, shutil, errno, imp, sys, difflib, rfc822, time
18 from cStringIO import StringIO
20 if not os.environ.has_key('SENDMAILDEBUG'):
21     os.environ['SENDMAILDEBUG'] = 'mail-test.log'
22 SENDMAILDEBUG = os.environ['SENDMAILDEBUG']
24 from roundup import mailgw, i18n, roundupdb
25 from roundup.mailgw import MailGW, Unauthorized, uidFromAddress, \
26     parseContent, IgnoreLoop, IgnoreBulk, MailUsageError, MailUsageHelp
27 from roundup import init, instance, password, rfc2822, __version__
28 from roundup.anypy.sets_ import set
30 #import db_test_base
31 import memorydb
33 class Message(rfc822.Message):
34     """String-based Message class with equivalence test."""
35     def __init__(self, s):
36         rfc822.Message.__init__(self, StringIO(s.strip()))
38     def __eq__(self, other):
39         return (self.dict == other.dict and
40                 self.fp.read() == other.fp.read())
42 class Tracker(object):
43     def open(self, journaltag):
44         return self.db
46 class DiffHelper:
47     def compareMessages(self, new, old):
48         """Compare messages for semantic equivalence."""
49         new, old = Message(new), Message(old)
51         # all Roundup-generated messages have "Precedence: bulk"
52         old['Precedence'] = 'bulk'
54         # don't try to compare the date
55         del new['date'], old['date']
57         if not new == old:
58             res = []
60             replace = {}
61             for key in new.keys():
62                 if key.startswith('from '):
63                     # skip the unix from line
64                     continue
65                 if key.lower() == 'x-roundup-version':
66                     # version changes constantly, so handle it specially
67                     if new[key] != __version__:
68                         res.append('  %s: %r != %r' % (key, __version__,
69                             new[key]))
70                 elif key.lower() == 'content-type' and 'boundary=' in new[key]:
71                     # handle mime messages
72                     newmime = new[key].split('=',1)[-1].strip('"')
73                     oldmime = old.get(key, '').split('=',1)[-1].strip('"')
74                     replace ['--' + newmime] = '--' + oldmime
75                     replace ['--' + newmime + '--'] = '--' + oldmime + '--'
76                 elif new.get(key, '') != old.get(key, ''):
77                     res.append('  %s: %r != %r' % (key, old.get(key, ''),
78                         new.get(key, '')))
80             body_diff = self.compareStrings(new.fp.read(), old.fp.read(),
81                 replace=replace)
82             if body_diff:
83                 res.append('')
84                 res.extend(body_diff)
86             if res:
87                 res.insert(0, 'Generated message not correct (diff follows, expected vs. actual):')
88                 raise AssertionError, '\n'.join(res)
90     def compareStrings(self, s2, s1, replace={}):
91         '''Note the reversal of s2 and s1 - difflib.SequenceMatcher wants
92            the first to be the "original" but in the calls in this file,
93            the second arg is the original. Ho hum.
94            Do replacements over the replace dict -- used for mime boundary
95         '''
96         l1 = s1.strip().split('\n')
97         l2 = [replace.get(i,i) for i in s2.strip().split('\n')]
98         if l1 == l2:
99             return
100         s = difflib.SequenceMatcher(None, l1, l2)
101         res = []
102         for value, s1s, s1e, s2s, s2e in s.get_opcodes():
103             if value == 'equal':
104                 for i in range(s1s, s1e):
105                     res.append('  %s'%l1[i])
106             elif value == 'delete':
107                 for i in range(s1s, s1e):
108                     res.append('- %s'%l1[i])
109             elif value == 'insert':
110                 for i in range(s2s, s2e):
111                     res.append('+ %s'%l2[i])
112             elif value == 'replace':
113                 for i, j in zip(range(s1s, s1e), range(s2s, s2e)):
114                     res.append('- %s'%l1[i])
115                     res.append('+ %s'%l2[j])
117         return res
119 class MailgwTestCase(unittest.TestCase, DiffHelper):
120     count = 0
121     schema = 'classic'
122     def setUp(self):
123         self.old_translate_ = mailgw._
124         roundupdb._ = mailgw._ = i18n.get_translation(language='C').gettext
125         MailgwTestCase.count = MailgwTestCase.count + 1
127         # and open the database / "instance"
128         self.db = memorydb.create('admin')
129         self.instance = Tracker()
130         self.instance.db = self.db
131         self.instance.config = self.db.config
132         self.instance.MailGW = MailGW
134         self.chef_id = self.db.user.create(username='Chef',
135             address='chef@bork.bork.bork', realname='Bork, Chef', roles='User')
136         self.richard_id = self.db.user.create(username='richard',
137             address='richard@test.test', roles='User')
138         self.mary_id = self.db.user.create(username='mary',
139             address='mary@test.test', roles='User', realname='Contrary, Mary')
140         self.john_id = self.db.user.create(username='john',
141             address='john@test.test', roles='User', realname='John Doe',
142             alternate_addresses='jondoe@test.test\njohn.doe@test.test')
143         self.rgg_id = self.db.user.create(username='rgg',
144             address='rgg@test.test', roles='User')
146     def tearDown(self):
147         roundupdb._ = mailgw._ = self.old_translate_
148         if os.path.exists(SENDMAILDEBUG):
149             os.remove(SENDMAILDEBUG)
150         self.db.close()
152     def _create_mailgw(self, message):
153         class MailGW(self.instance.MailGW):
154             def handle_message(self, message):
155                 return self._handle_message(message)
156         handler = MailGW(self.instance)
157         handler.db = self.db
158         return handler
160     def _handle_mail(self, message):
161         handler = self._create_mailgw(message)
162         handler.trapExceptions = 0
163         return handler.main(StringIO(message))
165     def _get_mail(self):
166         f = open(SENDMAILDEBUG)
167         try:
168             return f.read()
169         finally:
170             f.close()
172     def testEmptyMessage(self):
173         nodeid = self._handle_mail('''Content-Type: text/plain;
174   charset="iso-8859-1"
175 From: Chef <chef@bork.bork.bork>
176 To: issue_tracker@your.tracker.email.domain.example
177 Cc: richard@test.test
178 Reply-To: chef@bork.bork.bork
179 Message-Id: <dummy_test_message_id>
180 Subject: [issue] Testing...
182 ''')
183         assert not os.path.exists(SENDMAILDEBUG)
184         self.assertEqual(self.db.issue.get(nodeid, 'title'), 'Testing...')
186     def testMessageWithFromInIt(self):
187         nodeid = self._handle_mail('''Content-Type: text/plain;
188   charset="iso-8859-1"
189 From: Chef <chef@bork.bork.bork>
190 To: issue_tracker@your.tracker.email.domain.example
191 Cc: richard@test.test
192 Reply-To: chef@bork.bork.bork
193 Message-Id: <dummy_test_message_id>
194 Subject: [issue] Testing...
196 From here to there!
197 ''')
198         assert not os.path.exists(SENDMAILDEBUG)
199         msgid = self.db.issue.get(nodeid, 'messages')[0]
200         self.assertEqual(self.db.msg.get(msgid, 'content'), 'From here to there!')
202     def doNewIssue(self):
203         nodeid = self._handle_mail('''Content-Type: text/plain;
204   charset="iso-8859-1"
205 From: Chef <chef@bork.bork.bork>
206 To: issue_tracker@your.tracker.email.domain.example
207 Cc: richard@test.test
208 Message-Id: <dummy_test_message_id>
209 Subject: [issue] Testing...
211 This is a test submission of a new issue.
212 ''')
213         assert not os.path.exists(SENDMAILDEBUG)
214         l = self.db.issue.get(nodeid, 'nosy')
215         l.sort()
216         self.assertEqual(l, [self.chef_id, self.richard_id])
217         return nodeid
219     def testNewIssue(self):
220         self.doNewIssue()
222     def testNewIssueNosy(self):
223         self.instance.config.ADD_AUTHOR_TO_NOSY = 'yes'
224         nodeid = self._handle_mail('''Content-Type: text/plain;
225   charset="iso-8859-1"
226 From: Chef <chef@bork.bork.bork>
227 To: issue_tracker@your.tracker.email.domain.example
228 Cc: richard@test.test
229 Message-Id: <dummy_test_message_id>
230 Subject: [issue] Testing...
232 This is a test submission of a new issue.
233 ''')
234         assert not os.path.exists(SENDMAILDEBUG)
235         l = self.db.issue.get(nodeid, 'nosy')
236         l.sort()
237         self.assertEqual(l, [self.chef_id, self.richard_id])
239     def testAlternateAddress(self):
240         self._handle_mail('''Content-Type: text/plain;
241   charset="iso-8859-1"
242 From: John Doe <john.doe@test.test>
243 To: issue_tracker@your.tracker.email.domain.example
244 Message-Id: <dummy_test_message_id>
245 Subject: [issue] Testing...
247 This is a test submission of a new issue.
248 ''')
249         userlist = self.db.user.list()
250         assert not os.path.exists(SENDMAILDEBUG)
251         self.assertEqual(userlist, self.db.user.list(),
252             "user created when it shouldn't have been")
254     def testNewIssueNoClass(self):
255         self._handle_mail('''Content-Type: text/plain;
256   charset="iso-8859-1"
257 From: Chef <chef@bork.bork.bork>
258 To: issue_tracker@your.tracker.email.domain.example
259 Cc: richard@test.test
260 Message-Id: <dummy_test_message_id>
261 Subject: Testing...
263 This is a test submission of a new issue.
264 ''')
265         assert not os.path.exists(SENDMAILDEBUG)
267     def testNewIssueAuthMsg(self):
268         # TODO: fix the damn config - this is apalling
269         self.db.config.MESSAGES_TO_AUTHOR = 'yes'
270         self._handle_mail('''Content-Type: text/plain;
271   charset="iso-8859-1"
272 From: Chef <chef@bork.bork.bork>
273 To: issue_tracker@your.tracker.email.domain.example
274 Message-Id: <dummy_test_message_id>
275 Subject: [issue] Testing... [nosy=mary; assignedto=richard]
277 This is a test submission of a new issue.
278 ''')
279         self.compareMessages(self._get_mail(),
280 '''FROM: roundup-admin@your.tracker.email.domain.example
281 TO: chef@bork.bork.bork, mary@test.test, richard@test.test
282 Content-Type: text/plain; charset="utf-8"
283 Subject: [issue1] Testing...
284 To: chef@bork.bork.bork, mary@test.test, richard@test.test
285 From: "Bork, Chef" <issue_tracker@your.tracker.email.domain.example>
286 Reply-To: Roundup issue tracker
287  <issue_tracker@your.tracker.email.domain.example>
288 MIME-Version: 1.0
289 Message-Id: <dummy_test_message_id>
290 X-Roundup-Name: Roundup issue tracker
291 X-Roundup-Loop: hello
292 X-Roundup-Issue-Status: unread
293 Content-Transfer-Encoding: quoted-printable
296 New submission from Bork, Chef <chef@bork.bork.bork>:
298 This is a test submission of a new issue.
300 ----------
301 assignedto: richard
302 messages: 1
303 nosy: Chef, mary, richard
304 status: unread
305 title: Testing...
307 _______________________________________________________________________
308 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
309 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
310 _______________________________________________________________________
311 ''')
313     def testNewIssueNoAuthorInfo(self):
314         self.db.config.MAIL_ADD_AUTHORINFO = 'no'
315         self._handle_mail('''Content-Type: text/plain;
316   charset="iso-8859-1"
317 From: Chef <chef@bork.bork.bork>
318 To: issue_tracker@your.tracker.email.domain.example
319 Message-Id: <dummy_test_message_id>
320 Subject: [issue] Testing... [nosy=mary; assignedto=richard]
322 This is a test submission of a new issue.
323 ''')
324         self.compareMessages(self._get_mail(),
325 '''FROM: roundup-admin@your.tracker.email.domain.example
326 TO: chef@bork.bork.bork, mary@test.test, richard@test.test
327 Content-Type: text/plain; charset="utf-8"
328 Subject: [issue1] Testing...
329 To: mary@test.test, richard@test.test
330 From: "Bork, Chef" <issue_tracker@your.tracker.email.domain.example>
331 Reply-To: Roundup issue tracker
332  <issue_tracker@your.tracker.email.domain.example>
333 MIME-Version: 1.0
334 Message-Id: <dummy_test_message_id>
335 X-Roundup-Name: Roundup issue tracker
336 X-Roundup-Loop: hello
337 X-Roundup-Issue-Status: unread
338 Content-Transfer-Encoding: quoted-printable
340 This is a test submission of a new issue.
342 ----------
343 assignedto: richard
344 messages: 1
345 nosy: Chef, mary, richard
346 status: unread
347 title: Testing...
349 _______________________________________________________________________
350 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
351 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
352 _______________________________________________________________________
353 ''')
355     def testNewIssueNoAuthorEmail(self):
356         self.db.config.MAIL_ADD_AUTHOREMAIL = 'no'
357         self._handle_mail('''Content-Type: text/plain;
358   charset="iso-8859-1"
359 From: Chef <chef@bork.bork.bork>
360 To: issue_tracker@your.tracker.email.domain.example
361 Message-Id: <dummy_test_message_id>
362 Subject: [issue] Testing... [nosy=mary; assignedto=richard]
364 This is a test submission of a new issue.
365 ''')
366         self.compareMessages(self._get_mail(),
367 '''FROM: roundup-admin@your.tracker.email.domain.example
368 TO: chef@bork.bork.bork, mary@test.test, richard@test.test
369 Content-Type: text/plain; charset="utf-8"
370 Subject: [issue1] Testing...
371 To: mary@test.test, richard@test.test
372 From: "Bork, Chef" <issue_tracker@your.tracker.email.domain.example>
373 Reply-To: Roundup issue tracker
374  <issue_tracker@your.tracker.email.domain.example>
375 MIME-Version: 1.0
376 Message-Id: <dummy_test_message_id>
377 X-Roundup-Name: Roundup issue tracker
378 X-Roundup-Loop: hello
379 X-Roundup-Issue-Status: unread
380 Content-Transfer-Encoding: quoted-printable
382 New submission from Bork, Chef:
384 This is a test submission of a new issue.
386 ----------
387 assignedto: richard
388 messages: 1
389 nosy: Chef, mary, richard
390 status: unread
391 title: Testing...
393 _______________________________________________________________________
394 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
395 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
396 _______________________________________________________________________
397 ''')
399     multipart_msg = '''From: mary <mary@test.test>
400 To: issue_tracker@your.tracker.email.domain.example
401 Message-Id: <followup_dummy_id>
402 In-Reply-To: <dummy_test_message_id>
403 Subject: [issue1] Testing...
404 Content-Type: multipart/mixed; boundary="bxyzzy"
405 Content-Disposition: inline
408 --bxyzzy
409 Content-Type: multipart/alternative; boundary="bCsyhTFzCvuiizWE"
410 Content-Disposition: inline
412 --bCsyhTFzCvuiizWE
413 Content-Type: text/plain; charset=us-ascii
414 Content-Disposition: inline
416 test attachment first text/plain
418 --bCsyhTFzCvuiizWE
419 Content-Type: application/octet-stream
420 Content-Disposition: attachment; filename="first.dvi"
421 Content-Transfer-Encoding: base64
423 SnVzdCBhIHRlc3QgAQo=
425 --bCsyhTFzCvuiizWE
426 Content-Type: text/plain; charset=us-ascii
427 Content-Disposition: inline
429 test attachment second text/plain
431 --bCsyhTFzCvuiizWE
432 Content-Type: text/html
433 Content-Disposition: inline
435 <html>
436 to be ignored.
437 </html>
439 --bCsyhTFzCvuiizWE--
441 --bxyzzy
442 Content-Type: multipart/alternative; boundary="bCsyhTFzCvuiizWF"
443 Content-Disposition: inline
445 --bCsyhTFzCvuiizWF
446 Content-Type: text/plain; charset=us-ascii
447 Content-Disposition: inline
449 test attachment third text/plain
451 --bCsyhTFzCvuiizWF
452 Content-Type: application/octet-stream
453 Content-Disposition: attachment; filename="second.dvi"
454 Content-Transfer-Encoding: base64
456 SnVzdCBhIHRlc3QK
458 --bCsyhTFzCvuiizWF--
460 --bxyzzy--
461 '''
463     multipart_msg_latin1 = '''From: mary <mary@test.test>
464 To: issue_tracker@your.tracker.email.domain.example
465 Message-Id: <followup_dummy_id>
466 In-Reply-To: <dummy_test_message_id>
467 Subject: [issue1] Testing...
468 Content-Type: multipart/alternative; boundary=001485f339f8f361fb049188dbba
471 --001485f339f8f361fb049188dbba
472 Content-Type: text/plain; charset=ISO-8859-1
473 Content-Transfer-Encoding: quoted-printable
475 umlaut =E4=F6=FC=C4=D6=DC=DF
477 --001485f339f8f361fb049188dbba
478 Content-Type: text/html; charset=ISO-8859-1
479 Content-Transfer-Encoding: quoted-printable
481 <html>umlaut =E4=F6=FC=C4=D6=DC=DF</html>
483 --001485f339f8f361fb049188dbba--
484 '''
486     multipart_msg_rfc822 = '''From: mary <mary@test.test>
487 To: issue_tracker@your.tracker.email.domain.example
488 Message-Id: <followup_dummy_id>
489 In-Reply-To: <dummy_test_message_id>
490 Subject: [issue1] Testing...
491 Content-Type: multipart/mixed; boundary=001485f339f8f361fb049188dbba
493 This is a multi-part message in MIME format.
494 --001485f339f8f361fb049188dbba
495 Content-Type: text/plain; charset=ISO-8859-15
496 Content-Transfer-Encoding: 7bit
498 First part: Text
500 --001485f339f8f361fb049188dbba
501 Content-Type: message/rfc822; name="Fwd: Original email subject.eml"
502 Content-Transfer-Encoding: 7bit
503 Content-Disposition: attachment; filename="Fwd: Original email subject.eml"
505 Message-Id: <followup_dummy_id_2>
506 In-Reply-To: <dummy_test_message_id_2>
507 MIME-Version: 1.0
508 Subject: Fwd: Original email subject
509 Date: Mon, 23 Aug 2010 08:23:33 +0200
510 Content-Type: multipart/alternative; boundary="090500050101020406060002"
512 This is a multi-part message in MIME format.
513 --090500050101020406060002
514 Content-Type: text/plain; charset=ISO-8859-15; format=flowed
515 Content-Transfer-Encoding: 7bit
517 some text in inner email
518 ========================
520 --090500050101020406060002
521 Content-Type: text/html; charset=ISO-8859-15
522 Content-Transfer-Encoding: 7bit
524 <html>
525 some text in inner email
526 ========================
527 </html>
529 --090500050101020406060002--
531 --001485f339f8f361fb049188dbba--
532 '''
534     def testMultipartKeepAlternatives(self):
535         self.doNewIssue()
536         self._handle_mail(self.multipart_msg)
537         messages = self.db.issue.get('1', 'messages')
538         messages.sort()
539         msg = self.db.msg.getnode (messages[-1])
540         assert(len(msg.files) == 5)
541         names = {0 : 'first.dvi', 4 : 'second.dvi'}
542         content = {3 : 'test attachment third text/plain\n',
543                    4 : 'Just a test\n'}
544         for n, id in enumerate (msg.files):
545             f = self.db.file.getnode (id)
546             self.assertEqual(f.name, names.get (n, 'unnamed'))
547             if n in content :
548                 self.assertEqual(f.content, content [n])
549         self.assertEqual(msg.content, 'test attachment second text/plain')
551     def testMultipartDropAlternatives(self):
552         self.doNewIssue()
553         self.db.config.MAILGW_IGNORE_ALTERNATIVES = True
554         self._handle_mail(self.multipart_msg)
555         messages = self.db.issue.get('1', 'messages')
556         messages.sort()
557         msg = self.db.msg.getnode (messages[-1])
558         assert(len(msg.files) == 2)
559         names = {1 : 'second.dvi'}
560         content = {0 : 'test attachment third text/plain\n',
561                    1 : 'Just a test\n'}
562         for n, id in enumerate (msg.files):
563             f = self.db.file.getnode (id)
564             self.assertEqual(f.name, names.get (n, 'unnamed'))
565             if n in content :
566                 self.assertEqual(f.content, content [n])
567         self.assertEqual(msg.content, 'test attachment second text/plain')
569     def testMultipartCharsetUTF8NoAttach(self):
570         c = 'umlaut \xc3\xa4\xc3\xb6\xc3\xbc\xc3\x84\xc3\x96\xc3\x9c\xc3\x9f'
571         self.doNewIssue()
572         self.db.config.NOSY_MAX_ATTACHMENT_SIZE = 0
573         self._handle_mail(self.multipart_msg_latin1)
574         messages = self.db.issue.get('1', 'messages')
575         messages.sort()
576         msg = self.db.msg.getnode (messages[-1])
577         assert(len(msg.files) == 1)
578         name = 'unnamed'
579         content = '<html>' + c + '</html>\n'
580         for n, id in enumerate (msg.files):
581             f = self.db.file.getnode (id)
582             self.assertEqual(f.name, name)
583             self.assertEqual(f.content, content)
584         self.assertEqual(msg.content, c)
585         self.compareMessages(self._get_mail(),
586 '''FROM: roundup-admin@your.tracker.email.domain.example
587 TO: chef@bork.bork.bork, richard@test.test
588 Content-Type: text/plain; charset="utf-8"
589 Subject: [issue1] Testing...
590 To: chef@bork.bork.bork, richard@test.test
591 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
592 Reply-To: Roundup issue tracker
593  <issue_tracker@your.tracker.email.domain.example>
594 MIME-Version: 1.0
595 Message-Id: <followup_dummy_id>
596 In-Reply-To: <dummy_test_message_id>
597 X-Roundup-Name: Roundup issue tracker
598 X-Roundup-Loop: hello
599 X-Roundup-Issue-Status: chatting
600 X-Roundup-Issue-Files: unnamed
601 Content-Transfer-Encoding: quoted-printable
604 Contrary, Mary <mary@test.test> added the comment:
606 umlaut =C3=A4=C3=B6=C3=BC=C3=84=C3=96=C3=9C=C3=9F
607 File 'unnamed' not attached - you can download it from http://tracker.examp=
608 le/cgi-bin/roundup.cgi/bugs/file1.
610 ----------
611 status: unread -> chatting
613 _______________________________________________________________________
614 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
615 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
616 _______________________________________________________________________
617 ''')
619     def testMultipartCharsetLatin1NoAttach(self):
620         c = 'umlaut \xc3\xa4\xc3\xb6\xc3\xbc\xc3\x84\xc3\x96\xc3\x9c\xc3\x9f'
621         self.doNewIssue()
622         self.db.config.NOSY_MAX_ATTACHMENT_SIZE = 0
623         self.db.config.MAIL_CHARSET = 'iso-8859-1'
624         self._handle_mail(self.multipart_msg_latin1)
625         messages = self.db.issue.get('1', 'messages')
626         messages.sort()
627         msg = self.db.msg.getnode (messages[-1])
628         assert(len(msg.files) == 1)
629         name = 'unnamed'
630         content = '<html>' + c + '</html>\n'
631         for n, id in enumerate (msg.files):
632             f = self.db.file.getnode (id)
633             self.assertEqual(f.name, name)
634             self.assertEqual(f.content, content)
635         self.assertEqual(msg.content, c)
636         self.compareMessages(self._get_mail(),
637 '''FROM: roundup-admin@your.tracker.email.domain.example
638 TO: chef@bork.bork.bork, richard@test.test
639 Content-Type: text/plain; charset="iso-8859-1"
640 Subject: [issue1] Testing...
641 To: chef@bork.bork.bork, richard@test.test
642 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
643 Reply-To: Roundup issue tracker
644  <issue_tracker@your.tracker.email.domain.example>
645 MIME-Version: 1.0
646 Message-Id: <followup_dummy_id>
647 In-Reply-To: <dummy_test_message_id>
648 X-Roundup-Name: Roundup issue tracker
649 X-Roundup-Loop: hello
650 X-Roundup-Issue-Status: chatting
651 X-Roundup-Issue-Files: unnamed
652 Content-Transfer-Encoding: quoted-printable
655 Contrary, Mary <mary@test.test> added the comment:
657 umlaut =E4=F6=FC=C4=D6=DC=DF
658 File 'unnamed' not attached - you can download it from http://tracker.examp=
659 le/cgi-bin/roundup.cgi/bugs/file1.
661 ----------
662 status: unread -> chatting
664 _______________________________________________________________________
665 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
666 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
667 _______________________________________________________________________
668 ''')
670     def testMultipartCharsetUTF8AttachFile(self):
671         c = 'umlaut \xc3\xa4\xc3\xb6\xc3\xbc\xc3\x84\xc3\x96\xc3\x9c\xc3\x9f'
672         self.doNewIssue()
673         self._handle_mail(self.multipart_msg_latin1)
674         messages = self.db.issue.get('1', 'messages')
675         messages.sort()
676         msg = self.db.msg.getnode (messages[-1])
677         assert(len(msg.files) == 1)
678         name = 'unnamed'
679         content = '<html>' + c + '</html>\n'
680         for n, id in enumerate (msg.files):
681             f = self.db.file.getnode (id)
682             self.assertEqual(f.name, name)
683             self.assertEqual(f.content, content)
684         self.assertEqual(msg.content, c)
685         self.compareMessages(self._get_mail(),
686 '''FROM: roundup-admin@your.tracker.email.domain.example
687 TO: chef@bork.bork.bork, richard@test.test
688 Content-Type: multipart/mixed; boundary="utf-8"
689 Subject: [issue1] Testing...
690 To: chef@bork.bork.bork, richard@test.test
691 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
692 Reply-To: Roundup issue tracker
693  <issue_tracker@your.tracker.email.domain.example>
694 MIME-Version: 1.0
695 Message-Id: <followup_dummy_id>
696 In-Reply-To: <dummy_test_message_id>
697 X-Roundup-Name: Roundup issue tracker
698 X-Roundup-Loop: hello
699 X-Roundup-Issue-Status: chatting
700 X-Roundup-Issue-Files: unnamed
701 Content-Transfer-Encoding: quoted-printable
704 --utf-8
705 MIME-Version: 1.0
706 Content-Type: text/plain; charset="utf-8"
707 Content-Transfer-Encoding: quoted-printable
710 Contrary, Mary <mary@test.test> added the comment:
712 umlaut =C3=A4=C3=B6=C3=BC=C3=84=C3=96=C3=9C=C3=9F
714 ----------
715 status: unread -> chatting
717 _______________________________________________________________________
718 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
719 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
720 _______________________________________________________________________
721 --utf-8
722 Content-Type: text/html
723 MIME-Version: 1.0
724 Content-Transfer-Encoding: base64
725 Content-Disposition: attachment;
726  filename="unnamed"
728 PGh0bWw+dW1sYXV0IMOkw7bDvMOEw5bDnMOfPC9odG1sPgo=
730 --utf-8--
731 ''')
733     def testMultipartCharsetLatin1AttachFile(self):
734         c = 'umlaut \xc3\xa4\xc3\xb6\xc3\xbc\xc3\x84\xc3\x96\xc3\x9c\xc3\x9f'
735         self.doNewIssue()
736         self.db.config.MAIL_CHARSET = 'iso-8859-1'
737         self._handle_mail(self.multipart_msg_latin1)
738         messages = self.db.issue.get('1', 'messages')
739         messages.sort()
740         msg = self.db.msg.getnode (messages[-1])
741         assert(len(msg.files) == 1)
742         name = 'unnamed'
743         content = '<html>' + c + '</html>\n'
744         for n, id in enumerate (msg.files):
745             f = self.db.file.getnode (id)
746             self.assertEqual(f.name, name)
747             self.assertEqual(f.content, content)
748         self.assertEqual(msg.content, c)
749         self.compareMessages(self._get_mail(),
750 '''FROM: roundup-admin@your.tracker.email.domain.example
751 TO: chef@bork.bork.bork, richard@test.test
752 Content-Type: multipart/mixed; boundary="utf-8"
753 Subject: [issue1] Testing...
754 To: chef@bork.bork.bork, richard@test.test
755 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
756 Reply-To: Roundup issue tracker
757  <issue_tracker@your.tracker.email.domain.example>
758 MIME-Version: 1.0
759 Message-Id: <followup_dummy_id>
760 In-Reply-To: <dummy_test_message_id>
761 X-Roundup-Name: Roundup issue tracker
762 X-Roundup-Loop: hello
763 X-Roundup-Issue-Status: chatting
764 X-Roundup-Issue-Files: unnamed
765 Content-Transfer-Encoding: quoted-printable
768 --utf-8
769 MIME-Version: 1.0
770 Content-Type: text/plain; charset="iso-8859-1"
771 Content-Transfer-Encoding: quoted-printable
774 Contrary, Mary <mary@test.test> added the comment:
776 umlaut =E4=F6=FC=C4=D6=DC=DF
778 ----------
779 status: unread -> chatting
781 _______________________________________________________________________
782 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
783 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
784 _______________________________________________________________________
785 --utf-8
786 Content-Type: text/html
787 MIME-Version: 1.0
788 Content-Transfer-Encoding: base64
789 Content-Disposition: attachment;
790  filename="unnamed"
792 PGh0bWw+dW1sYXV0IMOkw7bDvMOEw5bDnMOfPC9odG1sPgo=
794 --utf-8--
795 ''')
797     def testMultipartRFC822(self):
798         self.doNewIssue()
799         self._handle_mail(self.multipart_msg_rfc822)
800         messages = self.db.issue.get('1', 'messages')
801         messages.sort()
802         msg = self.db.msg.getnode (messages[-1])
803         assert(len(msg.files) == 1)
804         name = "Fwd: Original email subject.eml"
805         for n, id in enumerate (msg.files):
806             f = self.db.file.getnode (id)
807             self.assertEqual(f.name, name)
808         self.assertEqual(msg.content, 'First part: Text')
809         self.compareMessages(self._get_mail(),
810 '''TO: chef@bork.bork.bork, richard@test.test
811 Content-Type: text/plain; charset="utf-8"
812 Subject: [issue1] Testing...
813 To: chef@bork.bork.bork, richard@test.test
814 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
815 Reply-To: Roundup issue tracker
816  <issue_tracker@your.tracker.email.domain.example>
817 MIME-Version: 1.0
818 Message-Id: <followup_dummy_id>
819 In-Reply-To: <dummy_test_message_id>
820 X-Roundup-Name: Roundup issue tracker
821 X-Roundup-Loop: hello
822 X-Roundup-Issue-Status: chatting
823 X-Roundup-Issue-Files: Fwd: Original email subject.eml
824 Content-Transfer-Encoding: quoted-printable
827 --utf-8
828 MIME-Version: 1.0
829 Content-Type: text/plain; charset="utf-8"
830 Content-Transfer-Encoding: quoted-printable
833 Contrary, Mary <mary@test.test> added the comment:
835 First part: Text
837 ----------
838 status: unread -> chatting
840 _______________________________________________________________________
841 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
842 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
843 _______________________________________________________________________
844 --utf-8
845 Content-Type: message/rfc822
846 MIME-Version: 1.0
847 Content-Disposition: attachment;
848  filename="Fwd: Original email subject.eml"
850 Message-Id: <followup_dummy_id_2>
851 In-Reply-To: <dummy_test_message_id_2>
852 MIME-Version: 1.0
853 Subject: Fwd: Original email subject
854 Date: Mon, 23 Aug 2010 08:23:33 +0200
855 Content-Type: multipart/alternative; boundary="090500050101020406060002"
857 This is a multi-part message in MIME format.
858 --090500050101020406060002
859 Content-Type: text/plain; charset=ISO-8859-15; format=flowed
860 Content-Transfer-Encoding: 7bit
862 some text in inner email
863 ========================
865 --090500050101020406060002
866 Content-Type: text/html; charset=ISO-8859-15
867 Content-Transfer-Encoding: 7bit
869 <html>
870 some text in inner email
871 ========================
872 </html>
874 --090500050101020406060002--
876 --utf-8--
877 ''')
879     def testMultipartRFC822Unpack(self):
880         self.doNewIssue()
881         self.db.config.MAILGW_UNPACK_RFC822 = True
882         self._handle_mail(self.multipart_msg_rfc822)
883         messages = self.db.issue.get('1', 'messages')
884         messages.sort()
885         msg = self.db.msg.getnode (messages[-1])
886         self.assertEqual(len(msg.files), 2)
887         t = 'some text in inner email\n========================\n'
888         content = {0 : t, 1 : '<html>\n' + t + '</html>\n'}
889         for n, id in enumerate (msg.files):
890             f = self.db.file.getnode (id)
891             self.assertEqual(f.name, 'unnamed')
892             if n in content :
893                 self.assertEqual(f.content, content [n])
894         self.assertEqual(msg.content, 'First part: Text')
896     def testSimpleFollowup(self):
897         self.doNewIssue()
898         self._handle_mail('''Content-Type: text/plain;
899   charset="iso-8859-1"
900 From: mary <mary@test.test>
901 To: issue_tracker@your.tracker.email.domain.example
902 Message-Id: <followup_dummy_id>
903 In-Reply-To: <dummy_test_message_id>
904 Subject: [issue1] Testing...
906 This is a second followup
907 ''')
908         self.compareMessages(self._get_mail(),
909 '''FROM: roundup-admin@your.tracker.email.domain.example
910 TO: chef@bork.bork.bork, richard@test.test
911 Content-Type: text/plain; charset="utf-8"
912 Subject: [issue1] Testing...
913 To: chef@bork.bork.bork, richard@test.test
914 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
915 Reply-To: Roundup issue tracker
916  <issue_tracker@your.tracker.email.domain.example>
917 MIME-Version: 1.0
918 Message-Id: <followup_dummy_id>
919 In-Reply-To: <dummy_test_message_id>
920 X-Roundup-Name: Roundup issue tracker
921 X-Roundup-Loop: hello
922 X-Roundup-Issue-Status: chatting
923 Content-Transfer-Encoding: quoted-printable
926 Contrary, Mary <mary@test.test> added the comment:
928 This is a second followup
930 ----------
931 status: unread -> chatting
933 _______________________________________________________________________
934 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
935 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
936 _______________________________________________________________________
937 ''')
939     def testFollowup(self):
940         self.doNewIssue()
942         self._handle_mail('''Content-Type: text/plain;
943   charset="iso-8859-1"
944 From: richard <richard@test.test>
945 To: issue_tracker@your.tracker.email.domain.example
946 Message-Id: <followup_dummy_id>
947 In-Reply-To: <dummy_test_message_id>
948 Subject: [issue1] Testing... [assignedto=mary; nosy=+john]
950 This is a followup
951 ''')
952         l = self.db.issue.get('1', 'nosy')
953         l.sort()
954         self.assertEqual(l, [self.chef_id, self.richard_id, self.mary_id,
955             self.john_id])
957         self.compareMessages(self._get_mail(),
958 '''FROM: roundup-admin@your.tracker.email.domain.example
959 TO: chef@bork.bork.bork, john@test.test, mary@test.test
960 Content-Type: text/plain; charset="utf-8"
961 Subject: [issue1] Testing...
962 To: chef@bork.bork.bork, john@test.test, mary@test.test
963 From: richard <issue_tracker@your.tracker.email.domain.example>
964 Reply-To: Roundup issue tracker
965  <issue_tracker@your.tracker.email.domain.example>
966 MIME-Version: 1.0
967 Message-Id: <followup_dummy_id>
968 In-Reply-To: <dummy_test_message_id>
969 X-Roundup-Name: Roundup issue tracker
970 X-Roundup-Loop: hello
971 X-Roundup-Issue-Status: chatting
972 Content-Transfer-Encoding: quoted-printable
975 richard <richard@test.test> added the comment:
977 This is a followup
979 ----------
980 assignedto:  -> mary
981 nosy: +john, mary
982 status: unread -> chatting
984 _______________________________________________________________________
985 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
986 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
987 _______________________________________________________________________
988 ''')
990     def testFollowupNoSubjectChange(self):
991         self.db.config.MAILGW_SUBJECT_UPDATES_TITLE = 'no'
992         self.doNewIssue()
994         self._handle_mail('''Content-Type: text/plain;
995   charset="iso-8859-1"
996 From: richard <richard@test.test>
997 To: issue_tracker@your.tracker.email.domain.example
998 Message-Id: <followup_dummy_id>
999 In-Reply-To: <dummy_test_message_id>
1000 Subject: [issue1] Wrzlbrmft... [assignedto=mary; nosy=+john]
1002 This is a followup
1003 ''')
1004         l = self.db.issue.get('1', 'nosy')
1005         l.sort()
1006         self.assertEqual(l, [self.chef_id, self.richard_id, self.mary_id,
1007             self.john_id])
1009         self.compareMessages(self._get_mail(),
1010 '''FROM: roundup-admin@your.tracker.email.domain.example
1011 TO: chef@bork.bork.bork, john@test.test, mary@test.test
1012 Content-Type: text/plain; charset="utf-8"
1013 Subject: [issue1] Testing...
1014 To: chef@bork.bork.bork, john@test.test, mary@test.test
1015 From: richard <issue_tracker@your.tracker.email.domain.example>
1016 Reply-To: Roundup issue tracker
1017  <issue_tracker@your.tracker.email.domain.example>
1018 MIME-Version: 1.0
1019 Message-Id: <followup_dummy_id>
1020 In-Reply-To: <dummy_test_message_id>
1021 X-Roundup-Name: Roundup issue tracker
1022 X-Roundup-Loop: hello
1023 X-Roundup-Issue-Status: chatting
1024 Content-Transfer-Encoding: quoted-printable
1027 richard <richard@test.test> added the comment:
1029 This is a followup
1031 ----------
1032 assignedto:  -> mary
1033 nosy: +john, mary
1034 status: unread -> chatting
1036 _______________________________________________________________________
1037 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1038 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1039 _______________________________________________________________________
1040 ''')
1041         self.assertEqual(self.db.issue.get('1','title'), 'Testing...')
1043     def testFollowupExplicitSubjectChange(self):
1044         self.doNewIssue()
1046         self._handle_mail('''Content-Type: text/plain;
1047   charset="iso-8859-1"
1048 From: richard <richard@test.test>
1049 To: issue_tracker@your.tracker.email.domain.example
1050 Message-Id: <followup_dummy_id>
1051 In-Reply-To: <dummy_test_message_id>
1052 Subject: [issue1] Wrzlbrmft... [assignedto=mary; nosy=+john; title=new title]
1054 This is a followup
1055 ''')
1056         l = self.db.issue.get('1', 'nosy')
1057         l.sort()
1058         self.assertEqual(l, [self.chef_id, self.richard_id, self.mary_id,
1059             self.john_id])
1061         self.compareMessages(self._get_mail(),
1062 '''FROM: roundup-admin@your.tracker.email.domain.example
1063 TO: chef@bork.bork.bork, john@test.test, mary@test.test
1064 Content-Type: text/plain; charset="utf-8"
1065 Subject: [issue1] new title
1066 To: chef@bork.bork.bork, john@test.test, mary@test.test
1067 From: richard <issue_tracker@your.tracker.email.domain.example>
1068 Reply-To: Roundup issue tracker
1069  <issue_tracker@your.tracker.email.domain.example>
1070 MIME-Version: 1.0
1071 Message-Id: <followup_dummy_id>
1072 In-Reply-To: <dummy_test_message_id>
1073 X-Roundup-Name: Roundup issue tracker
1074 X-Roundup-Loop: hello
1075 X-Roundup-Issue-Status: chatting
1076 Content-Transfer-Encoding: quoted-printable
1079 richard <richard@test.test> added the comment:
1081 This is a followup
1083 ----------
1084 assignedto:  -> mary
1085 nosy: +john, mary
1086 status: unread -> chatting
1087 title: Testing... -> new title
1089 _______________________________________________________________________
1090 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1091 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1092 _______________________________________________________________________
1093 ''')
1095     def testNosyGeneration(self):
1096         self.db.issue.create(title='test')
1098         # create a nosy message
1099         msg = self.db.msg.create(content='This is a test',
1100             author=self.richard_id, messageid='<dummy_test_message_id>')
1101         self.db.journaltag = 'richard'
1102         l = self.db.issue.create(title='test', messages=[msg],
1103             nosy=[self.chef_id, self.mary_id, self.john_id])
1105         self.compareMessages(self._get_mail(),
1106 '''FROM: roundup-admin@your.tracker.email.domain.example
1107 TO: chef@bork.bork.bork, john@test.test, mary@test.test
1108 Content-Type: text/plain; charset="utf-8"
1109 Subject: [issue2] test
1110 To: chef@bork.bork.bork, john@test.test, mary@test.test
1111 From: richard <issue_tracker@your.tracker.email.domain.example>
1112 Reply-To: Roundup issue tracker
1113  <issue_tracker@your.tracker.email.domain.example>
1114 MIME-Version: 1.0
1115 Message-Id: <dummy_test_message_id>
1116 X-Roundup-Name: Roundup issue tracker
1117 X-Roundup-Loop: hello
1118 X-Roundup-Issue-Status: unread
1119 Content-Transfer-Encoding: quoted-printable
1122 New submission from richard <richard@test.test>:
1124 This is a test
1126 ----------
1127 messages: 1
1128 nosy: Chef, john, mary, richard
1129 status: unread
1130 title: test
1132 _______________________________________________________________________
1133 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1134 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue2>
1135 _______________________________________________________________________
1136 ''')
1138     def testPropertyChangeOnly(self):
1139         self.doNewIssue()
1140         oldvalues = self.db.getnode('issue', '1').copy()
1141         oldvalues['assignedto'] = None
1142         # reconstruct old behaviour: This would reuse the
1143         # database-handle from the doNewIssue above which has committed
1144         # as user "Chef". So we close and reopen the db as that user.
1145         #self.db.close() actually don't close 'cos this empties memorydb
1146         self.db = self.instance.open('Chef')
1147         self.db.issue.set('1', assignedto=self.chef_id)
1148         self.db.commit()
1149         self.db.issue.nosymessage('1', None, oldvalues)
1151         new_mail = ""
1152         for line in self._get_mail().split("\n"):
1153             if "Message-Id: " in line:
1154                 continue
1155             if "Date: " in line:
1156                 continue
1157             new_mail += line+"\n"
1159         self.compareMessages(new_mail, """
1160 FROM: roundup-admin@your.tracker.email.domain.example
1161 TO: chef@bork.bork.bork, richard@test.test
1162 Content-Type: text/plain; charset="utf-8"
1163 Subject: [issue1] Testing...
1164 To: chef@bork.bork.bork, richard@test.test
1165 From: "Bork, Chef" <issue_tracker@your.tracker.email.domain.example>
1166 X-Roundup-Name: Roundup issue tracker
1167 X-Roundup-Loop: hello
1168 X-Roundup-Issue-Status: unread
1169 X-Roundup-Version: 1.3.3
1170 In-Reply-To: <dummy_test_message_id>
1171 MIME-Version: 1.0
1172 Reply-To: Roundup issue tracker
1173  <issue_tracker@your.tracker.email.domain.example>
1174 Content-Transfer-Encoding: quoted-printable
1177 Change by Bork, Chef <chef@bork.bork.bork>:
1180 ----------
1181 assignedto:  -> Chef
1183 _______________________________________________________________________
1184 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1185 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1186 _______________________________________________________________________
1187 """)
1190     #
1191     # FOLLOWUP TITLE MATCH
1192     #
1193     def testFollowupTitleMatch(self):
1194         self.doNewIssue()
1195         self._handle_mail('''Content-Type: text/plain;
1196   charset="iso-8859-1"
1197 From: richard <richard@test.test>
1198 To: issue_tracker@your.tracker.email.domain.example
1199 Message-Id: <followup_dummy_id>
1200 Subject: Re: Testing... [assignedto=mary; nosy=+john]
1202 This is a followup
1203 ''')
1204         self.compareMessages(self._get_mail(),
1205 '''FROM: roundup-admin@your.tracker.email.domain.example
1206 TO: chef@bork.bork.bork, john@test.test, mary@test.test
1207 Content-Type: text/plain; charset="utf-8"
1208 Subject: [issue1] Testing...
1209 To: chef@bork.bork.bork, john@test.test, mary@test.test
1210 From: richard <issue_tracker@your.tracker.email.domain.example>
1211 Reply-To: Roundup issue tracker
1212  <issue_tracker@your.tracker.email.domain.example>
1213 MIME-Version: 1.0
1214 Message-Id: <followup_dummy_id>
1215 In-Reply-To: <dummy_test_message_id>
1216 X-Roundup-Name: Roundup issue tracker
1217 X-Roundup-Loop: hello
1218 X-Roundup-Issue-Status: chatting
1219 Content-Transfer-Encoding: quoted-printable
1222 richard <richard@test.test> added the comment:
1224 This is a followup
1226 ----------
1227 assignedto:  -> mary
1228 nosy: +john, mary
1229 status: unread -> chatting
1231 _______________________________________________________________________
1232 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1233 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1234 _______________________________________________________________________
1235 ''')
1237     def testFollowupTitleMatchMultiRe(self):
1238         nodeid1 = self.doNewIssue()
1239         nodeid2 = self._handle_mail('''Content-Type: text/plain;
1240   charset="iso-8859-1"
1241 From: richard <richard@test.test>
1242 To: issue_tracker@your.tracker.email.domain.example
1243 Message-Id: <followup_dummy_id>
1244 Subject: Re: Testing... [assignedto=mary; nosy=+john]
1246 This is a followup
1247 ''')
1249         nodeid3 = self._handle_mail('''Content-Type: text/plain;
1250   charset="iso-8859-1"
1251 From: richard <richard@test.test>
1252 To: issue_tracker@your.tracker.email.domain.example
1253 Message-Id: <followup2_dummy_id>
1254 Subject: Ang: Re: Testing...
1256 This is a followup
1257 ''')
1258         self.assertEqual(nodeid1, nodeid2)
1259         self.assertEqual(nodeid1, nodeid3)
1261     def testFollowupTitleMatchNever(self):
1262         nodeid = self.doNewIssue()
1263         self.db.config.MAILGW_SUBJECT_CONTENT_MATCH = 'never'
1264         self.assertNotEqual(self._handle_mail('''Content-Type: text/plain;
1265   charset="iso-8859-1"
1266 From: richard <richard@test.test>
1267 To: issue_tracker@your.tracker.email.domain.example
1268 Message-Id: <followup_dummy_id>
1269 Subject: Re: Testing...
1271 This is a followup
1272 '''), nodeid)
1274     def testFollowupTitleMatchNeverInterval(self):
1275         nodeid = self.doNewIssue()
1276         # force failure of the interval
1277         time.sleep(2)
1278         self.db.config.MAILGW_SUBJECT_CONTENT_MATCH = 'creation 00:00:01'
1279         self.assertNotEqual(self._handle_mail('''Content-Type: text/plain;
1280   charset="iso-8859-1"
1281 From: richard <richard@test.test>
1282 To: issue_tracker@your.tracker.email.domain.example
1283 Message-Id: <followup_dummy_id>
1284 Subject: Re: Testing...
1286 This is a followup
1287 '''), nodeid)
1290     def testFollowupTitleMatchInterval(self):
1291         nodeid = self.doNewIssue()
1292         self.db.config.MAILGW_SUBJECT_CONTENT_MATCH = 'creation +1d'
1293         self.assertEqual(self._handle_mail('''Content-Type: text/plain;
1294   charset="iso-8859-1"
1295 From: richard <richard@test.test>
1296 To: issue_tracker@your.tracker.email.domain.example
1297 Message-Id: <followup_dummy_id>
1298 Subject: Re: Testing...
1300 This is a followup
1301 '''), nodeid)
1304     def testFollowupNosyAuthor(self):
1305         self.doNewIssue()
1306         self.db.config.ADD_AUTHOR_TO_NOSY = 'yes'
1307         self._handle_mail('''Content-Type: text/plain;
1308   charset="iso-8859-1"
1309 From: john@test.test
1310 To: issue_tracker@your.tracker.email.domain.example
1311 Message-Id: <followup_dummy_id>
1312 In-Reply-To: <dummy_test_message_id>
1313 Subject: [issue1] Testing...
1315 This is a followup
1316 ''')
1318         self.compareMessages(self._get_mail(),
1319 '''FROM: roundup-admin@your.tracker.email.domain.example
1320 TO: chef@bork.bork.bork, richard@test.test
1321 Content-Type: text/plain; charset="utf-8"
1322 Subject: [issue1] Testing...
1323 To: chef@bork.bork.bork, richard@test.test
1324 From: John Doe <issue_tracker@your.tracker.email.domain.example>
1325 Reply-To: Roundup issue tracker
1326  <issue_tracker@your.tracker.email.domain.example>
1327 MIME-Version: 1.0
1328 Message-Id: <followup_dummy_id>
1329 In-Reply-To: <dummy_test_message_id>
1330 X-Roundup-Name: Roundup issue tracker
1331 X-Roundup-Loop: hello
1332 X-Roundup-Issue-Status: chatting
1333 Content-Transfer-Encoding: quoted-printable
1336 John Doe <john@test.test> added the comment:
1338 This is a followup
1340 ----------
1341 nosy: +john
1342 status: unread -> chatting
1344 _______________________________________________________________________
1345 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1346 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1347 _______________________________________________________________________
1349 ''')
1351     def testFollowupNosyRecipients(self):
1352         self.doNewIssue()
1353         self.db.config.ADD_RECIPIENTS_TO_NOSY = 'yes'
1354         self._handle_mail('''Content-Type: text/plain;
1355   charset="iso-8859-1"
1356 From: richard@test.test
1357 To: issue_tracker@your.tracker.email.domain.example
1358 Cc: john@test.test
1359 Message-Id: <followup_dummy_id>
1360 In-Reply-To: <dummy_test_message_id>
1361 Subject: [issue1] Testing...
1363 This is a followup
1364 ''')
1365         self.compareMessages(self._get_mail(),
1366 '''FROM: roundup-admin@your.tracker.email.domain.example
1367 TO: chef@bork.bork.bork
1368 Content-Type: text/plain; charset="utf-8"
1369 Subject: [issue1] Testing...
1370 To: chef@bork.bork.bork
1371 From: richard <issue_tracker@your.tracker.email.domain.example>
1372 Reply-To: Roundup issue tracker
1373  <issue_tracker@your.tracker.email.domain.example>
1374 MIME-Version: 1.0
1375 Message-Id: <followup_dummy_id>
1376 In-Reply-To: <dummy_test_message_id>
1377 X-Roundup-Name: Roundup issue tracker
1378 X-Roundup-Loop: hello
1379 X-Roundup-Issue-Status: chatting
1380 Content-Transfer-Encoding: quoted-printable
1383 richard <richard@test.test> added the comment:
1385 This is a followup
1387 ----------
1388 nosy: +john
1389 status: unread -> chatting
1391 _______________________________________________________________________
1392 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1393 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1394 _______________________________________________________________________
1396 ''')
1398     def testFollowupNosyAuthorAndCopy(self):
1399         self.doNewIssue()
1400         self.db.config.ADD_AUTHOR_TO_NOSY = 'yes'
1401         self.db.config.MESSAGES_TO_AUTHOR = 'yes'
1402         self._handle_mail('''Content-Type: text/plain;
1403   charset="iso-8859-1"
1404 From: john@test.test
1405 To: issue_tracker@your.tracker.email.domain.example
1406 Message-Id: <followup_dummy_id>
1407 In-Reply-To: <dummy_test_message_id>
1408 Subject: [issue1] Testing...
1410 This is a followup
1411 ''')
1412         self.compareMessages(self._get_mail(),
1413 '''FROM: roundup-admin@your.tracker.email.domain.example
1414 TO: chef@bork.bork.bork, john@test.test, richard@test.test
1415 Content-Type: text/plain; charset="utf-8"
1416 Subject: [issue1] Testing...
1417 To: chef@bork.bork.bork, john@test.test, richard@test.test
1418 From: John Doe <issue_tracker@your.tracker.email.domain.example>
1419 Reply-To: Roundup issue tracker
1420  <issue_tracker@your.tracker.email.domain.example>
1421 MIME-Version: 1.0
1422 Message-Id: <followup_dummy_id>
1423 In-Reply-To: <dummy_test_message_id>
1424 X-Roundup-Name: Roundup issue tracker
1425 X-Roundup-Loop: hello
1426 X-Roundup-Issue-Status: chatting
1427 Content-Transfer-Encoding: quoted-printable
1430 John Doe <john@test.test> added the comment:
1432 This is a followup
1434 ----------
1435 nosy: +john
1436 status: unread -> chatting
1438 _______________________________________________________________________
1439 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1440 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1441 _______________________________________________________________________
1443 ''')
1445     def testFollowupNoNosyAuthor(self):
1446         self.doNewIssue()
1447         self.instance.config.ADD_AUTHOR_TO_NOSY = 'no'
1448         self._handle_mail('''Content-Type: text/plain;
1449   charset="iso-8859-1"
1450 From: john@test.test
1451 To: issue_tracker@your.tracker.email.domain.example
1452 Message-Id: <followup_dummy_id>
1453 In-Reply-To: <dummy_test_message_id>
1454 Subject: [issue1] Testing...
1456 This is a followup
1457 ''')
1458         self.compareMessages(self._get_mail(),
1459 '''FROM: roundup-admin@your.tracker.email.domain.example
1460 TO: chef@bork.bork.bork, richard@test.test
1461 Content-Type: text/plain; charset="utf-8"
1462 Subject: [issue1] Testing...
1463 To: chef@bork.bork.bork, richard@test.test
1464 From: John Doe <issue_tracker@your.tracker.email.domain.example>
1465 Reply-To: Roundup issue tracker
1466  <issue_tracker@your.tracker.email.domain.example>
1467 MIME-Version: 1.0
1468 Message-Id: <followup_dummy_id>
1469 In-Reply-To: <dummy_test_message_id>
1470 X-Roundup-Name: Roundup issue tracker
1471 X-Roundup-Loop: hello
1472 X-Roundup-Issue-Status: chatting
1473 Content-Transfer-Encoding: quoted-printable
1476 John Doe <john@test.test> added the comment:
1478 This is a followup
1480 ----------
1481 status: unread -> chatting
1483 _______________________________________________________________________
1484 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1485 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1486 _______________________________________________________________________
1488 ''')
1490     def testFollowupNoNosyRecipients(self):
1491         self.doNewIssue()
1492         self.instance.config.ADD_RECIPIENTS_TO_NOSY = 'no'
1493         self._handle_mail('''Content-Type: text/plain;
1494   charset="iso-8859-1"
1495 From: richard@test.test
1496 To: issue_tracker@your.tracker.email.domain.example
1497 Cc: john@test.test
1498 Message-Id: <followup_dummy_id>
1499 In-Reply-To: <dummy_test_message_id>
1500 Subject: [issue1] Testing...
1502 This is a followup
1503 ''')
1504         self.compareMessages(self._get_mail(),
1505 '''FROM: roundup-admin@your.tracker.email.domain.example
1506 TO: chef@bork.bork.bork
1507 Content-Type: text/plain; charset="utf-8"
1508 Subject: [issue1] Testing...
1509 To: chef@bork.bork.bork
1510 From: richard <issue_tracker@your.tracker.email.domain.example>
1511 Reply-To: Roundup issue tracker
1512  <issue_tracker@your.tracker.email.domain.example>
1513 MIME-Version: 1.0
1514 Message-Id: <followup_dummy_id>
1515 In-Reply-To: <dummy_test_message_id>
1516 X-Roundup-Name: Roundup issue tracker
1517 X-Roundup-Loop: hello
1518 X-Roundup-Issue-Status: chatting
1519 Content-Transfer-Encoding: quoted-printable
1522 richard <richard@test.test> added the comment:
1524 This is a followup
1526 ----------
1527 status: unread -> chatting
1529 _______________________________________________________________________
1530 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1531 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1532 _______________________________________________________________________
1534 ''')
1536     def testFollowupEmptyMessage(self):
1537         self.doNewIssue()
1539         self._handle_mail('''Content-Type: text/plain;
1540   charset="iso-8859-1"
1541 From: richard <richard@test.test>
1542 To: issue_tracker@your.tracker.email.domain.example
1543 Message-Id: <followup_dummy_id>
1544 In-Reply-To: <dummy_test_message_id>
1545 Subject: [issue1] Testing... [assignedto=mary; nosy=+john]
1547 ''')
1548         l = self.db.issue.get('1', 'nosy')
1549         l.sort()
1550         self.assertEqual(l, [self.chef_id, self.richard_id, self.mary_id,
1551             self.john_id])
1553         # should be no file created (ie. no message)
1554         assert not os.path.exists(SENDMAILDEBUG)
1556     def testFollowupEmptyMessageNoSubject(self):
1557         self.doNewIssue()
1559         self._handle_mail('''Content-Type: text/plain;
1560   charset="iso-8859-1"
1561 From: richard <richard@test.test>
1562 To: issue_tracker@your.tracker.email.domain.example
1563 Message-Id: <followup_dummy_id>
1564 In-Reply-To: <dummy_test_message_id>
1565 Subject: [issue1] [assignedto=mary; nosy=+john]
1567 ''')
1568         l = self.db.issue.get('1', 'nosy')
1569         l.sort()
1570         self.assertEqual(l, [self.chef_id, self.richard_id, self.mary_id,
1571             self.john_id])
1573         # should be no file created (ie. no message)
1574         assert not os.path.exists(SENDMAILDEBUG)
1576     def testNosyRemove(self):
1577         self.doNewIssue()
1579         self._handle_mail('''Content-Type: text/plain;
1580   charset="iso-8859-1"
1581 From: richard <richard@test.test>
1582 To: issue_tracker@your.tracker.email.domain.example
1583 Message-Id: <followup_dummy_id>
1584 In-Reply-To: <dummy_test_message_id>
1585 Subject: [issue1] Testing... [nosy=-richard]
1587 ''')
1588         l = self.db.issue.get('1', 'nosy')
1589         l.sort()
1590         self.assertEqual(l, [self.chef_id])
1592         # NO NOSY MESSAGE SHOULD BE SENT!
1593         assert not os.path.exists(SENDMAILDEBUG)
1595     def testNewUserAuthor(self):
1596         self.db.commit()
1597         l = self.db.user.list()
1598         l.sort()
1599         message = '''Content-Type: text/plain;
1600   charset="iso-8859-1"
1601 From: fubar <fubar@bork.bork.bork>
1602 To: issue_tracker@your.tracker.email.domain.example
1603 Message-Id: <dummy_test_message_id>
1604 Subject: [issue] Testing...
1606 This is a test submission of a new issue.
1607 '''
1608         self.db.security.role['anonymous'].permissions=[]
1609         anonid = self.db.user.lookup('anonymous')
1610         self.db.user.set(anonid, roles='Anonymous')
1611         try:
1612             self._handle_mail(message)
1613         except Unauthorized, value:
1614             body_diff = self.compareMessages(str(value), """
1615 You are not a registered user.
1617 Unknown address: fubar@bork.bork.bork
1618 """)
1619             assert not body_diff, body_diff
1620         else:
1621             raise AssertionError, "Unathorized not raised when handling mail"
1623         # Add Web Access role to anonymous, and try again to make sure
1624         # we get a "please register at:" message this time.
1625         p = [
1626             self.db.security.getPermission('Register', 'user'),
1627             self.db.security.getPermission('Web Access', None),
1628         ]
1629         self.db.security.role['anonymous'].permissions=p
1630         try:
1631             self._handle_mail(message)
1632         except Unauthorized, value:
1633             body_diff = self.compareMessages(str(value), """
1634 You are not a registered user. Please register at:
1636 http://tracker.example/cgi-bin/roundup.cgi/bugs/user?template=register
1638 ...before sending mail to the tracker.
1640 Unknown address: fubar@bork.bork.bork
1641 """)
1642             assert not body_diff, body_diff
1643         else:
1644             raise AssertionError, "Unathorized not raised when handling mail"
1646         # Make sure list of users is the same as before.
1647         m = self.db.user.list()
1648         m.sort()
1649         self.assertEqual(l, m)
1651         # now with the permission
1652         p = [
1653             self.db.security.getPermission('Register', 'user'),
1654             self.db.security.getPermission('Email Access', None),
1655         ]
1656         self.db.security.role['anonymous'].permissions=p
1657         self._handle_mail(message)
1658         m = self.db.user.list()
1659         m.sort()
1660         self.assertNotEqual(l, m)
1662     def testNewUserAuthorEncodedName(self):
1663         l = set(self.db.user.list())
1664         # From: name has Euro symbol in it
1665         message = '''Content-Type: text/plain;
1666   charset="iso-8859-1"
1667 From: =?utf8?b?SOKCrGxsbw==?= <fubar@bork.bork.bork>
1668 To: issue_tracker@your.tracker.email.domain.example
1669 Message-Id: <dummy_test_message_id>
1670 Subject: [issue] Testing...
1672 This is a test submission of a new issue.
1673 '''
1674         p = [
1675             self.db.security.getPermission('Register', 'user'),
1676             self.db.security.getPermission('Email Access', None),
1677             self.db.security.getPermission('Create', 'issue'),
1678             self.db.security.getPermission('Create', 'msg'),
1679         ]
1680         self.db.security.role['anonymous'].permissions = p
1681         self._handle_mail(message)
1682         m = set(self.db.user.list())
1683         new = list(m - l)[0]
1684         name = self.db.user.get(new, 'realname')
1685         self.assertEquals(name, 'H€llo')
1687     def testUnknownUser(self):
1688         l = set(self.db.user.list())
1689         message = '''Content-Type: text/plain;
1690   charset="iso-8859-1"
1691 From: Nonexisting User <nonexisting@bork.bork.bork>
1692 To: issue_tracker@your.tracker.email.domain.example
1693 Message-Id: <dummy_test_message_id>
1694 Subject: [issue] Testing nonexisting user...
1696 This is a test submission of a new issue.
1697 '''
1698         handler = self._create_mailgw(message)
1699         # we want a bounce message:
1700         handler.trapExceptions = 1
1701         ret = handler.main(StringIO(message))
1702         self.compareMessages(self._get_mail(),
1703 '''FROM: Roundup issue tracker <roundup-admin@your.tracker.email.domain.example>
1704 TO: nonexisting@bork.bork.bork
1705 From nobody Tue Jul 14 12:04:11 2009
1706 Content-Type: multipart/mixed; boundary="===============0639262320=="
1707 MIME-Version: 1.0
1708 Subject: Failed issue tracker submission
1709 To: nonexisting@bork.bork.bork
1710 From: Roundup issue tracker <roundup-admin@your.tracker.email.domain.example>
1711 Date: Tue, 14 Jul 2009 12:04:11 +0000
1712 Precedence: bulk
1713 X-Roundup-Name: Roundup issue tracker
1714 X-Roundup-Loop: hello
1715 X-Roundup-Version: 1.4.8
1716 MIME-Version: 1.0
1718 --===============0639262320==
1719 Content-Type: text/plain; charset="us-ascii"
1720 MIME-Version: 1.0
1721 Content-Transfer-Encoding: 7bit
1725 You are not a registered user. Please register at:
1727 http://tracker.example/cgi-bin/roundup.cgi/bugs/user?template=register
1729 ...before sending mail to the tracker.
1731 Unknown address: nonexisting@bork.bork.bork
1733 --===============0639262320==
1734 Content-Type: text/plain; charset="us-ascii"
1735 MIME-Version: 1.0
1736 Content-Transfer-Encoding: 7bit
1738 Content-Type: text/plain;
1739   charset="iso-8859-1"
1740 From: Nonexisting User <nonexisting@bork.bork.bork>
1741 To: issue_tracker@your.tracker.email.domain.example
1742 Message-Id: <dummy_test_message_id>
1743 Subject: [issue] Testing nonexisting user...
1745 This is a test submission of a new issue.
1747 --===============0639262320==--
1748 ''')
1750     def testEnc01(self):
1751         self.db.user.set(self.mary_id,
1752             realname='\xe4\xf6\xfc\xc4\xd6\xdc\xdf, Mary'.decode
1753             ('latin-1').encode('utf-8'))
1754         self.doNewIssue()
1755         self._handle_mail('''Content-Type: text/plain;
1756   charset="iso-8859-1"
1757 From: mary <mary@test.test>
1758 To: issue_tracker@your.tracker.email.domain.example
1759 Message-Id: <followup_dummy_id>
1760 In-Reply-To: <dummy_test_message_id>
1761 Subject: [issue1] Testing...
1762 Content-Type: text/plain;
1763         charset="iso-8859-1"
1764 Content-Transfer-Encoding: quoted-printable
1766 A message with encoding (encoded oe =F6)
1768 ''')
1769         self.compareMessages(self._get_mail(),
1770 '''FROM: roundup-admin@your.tracker.email.domain.example
1771 TO: chef@bork.bork.bork, richard@test.test
1772 Content-Type: text/plain; charset="utf-8"
1773 Subject: [issue1] Testing...
1774 To: chef@bork.bork.bork, richard@test.test
1775 From: =?utf-8?b?w6TDtsO8w4TDlsOcw58sIE1hcnk=?=
1776  <issue_tracker@your.tracker.email.domain.example>
1777 Reply-To: Roundup issue tracker
1778  <issue_tracker@your.tracker.email.domain.example>
1779 MIME-Version: 1.0
1780 Message-Id: <followup_dummy_id>
1781 In-Reply-To: <dummy_test_message_id>
1782 X-Roundup-Name: Roundup issue tracker
1783 X-Roundup-Loop: hello
1784 X-Roundup-Issue-Status: chatting
1785 Content-Transfer-Encoding: quoted-printable
1788 =C3=A4=C3=B6=C3=BC=C3=84=C3=96=C3=9C=C3=9F, Mary <mary@test.test> added the=
1789  comment:
1791 A message with encoding (encoded oe =C3=B6)
1793 ----------
1794 status: unread -> chatting
1796 _______________________________________________________________________
1797 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1798 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1799 _______________________________________________________________________
1800 ''')
1802     def testEncNonUTF8(self):
1803         self.doNewIssue()
1804         self.instance.config.EMAIL_CHARSET = 'iso-8859-1'
1805         self._handle_mail('''Content-Type: text/plain;
1806   charset="iso-8859-1"
1807 From: mary <mary@test.test>
1808 To: issue_tracker@your.tracker.email.domain.example
1809 Message-Id: <followup_dummy_id>
1810 In-Reply-To: <dummy_test_message_id>
1811 Subject: [issue1] Testing...
1812 Content-Type: text/plain;
1813         charset="iso-8859-1"
1814 Content-Transfer-Encoding: quoted-printable
1816 A message with encoding (encoded oe =F6)
1818 ''')
1819         self.compareMessages(self._get_mail(),
1820 '''FROM: roundup-admin@your.tracker.email.domain.example
1821 TO: chef@bork.bork.bork, richard@test.test
1822 Content-Type: text/plain; charset="iso-8859-1"
1823 Subject: [issue1] Testing...
1824 To: chef@bork.bork.bork, richard@test.test
1825 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
1826 Reply-To: Roundup issue tracker
1827  <issue_tracker@your.tracker.email.domain.example>
1828 MIME-Version: 1.0
1829 Message-Id: <followup_dummy_id>
1830 In-Reply-To: <dummy_test_message_id>
1831 X-Roundup-Name: Roundup issue tracker
1832 X-Roundup-Loop: hello
1833 X-Roundup-Issue-Status: chatting
1834 Content-Transfer-Encoding: quoted-printable
1837 Contrary, Mary <mary@test.test> added the comment:
1839 A message with encoding (encoded oe =F6)
1841 ----------
1842 status: unread -> chatting
1844 _______________________________________________________________________
1845 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1846 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1847 _______________________________________________________________________
1848 ''')
1851     def testMultipartEnc01(self):
1852         self.doNewIssue()
1853         self._handle_mail('''Content-Type: text/plain;
1854   charset="iso-8859-1"
1855 From: mary <mary@test.test>
1856 To: issue_tracker@your.tracker.email.domain.example
1857 Message-Id: <followup_dummy_id>
1858 In-Reply-To: <dummy_test_message_id>
1859 Subject: [issue1] Testing...
1860 Content-Type: multipart/mixed;
1861         boundary="----_=_NextPart_000_01"
1863 This message is in MIME format. Since your mail reader does not understand
1864 this format, some or all of this message may not be legible.
1866 ------_=_NextPart_000_01
1867 Content-Type: text/plain;
1868         charset="iso-8859-1"
1869 Content-Transfer-Encoding: quoted-printable
1871 A message with first part encoded (encoded oe =F6)
1873 ''')
1874         self.compareMessages(self._get_mail(),
1875 '''FROM: roundup-admin@your.tracker.email.domain.example
1876 TO: chef@bork.bork.bork, richard@test.test
1877 Content-Type: text/plain; charset="utf-8"
1878 Subject: [issue1] Testing...
1879 To: chef@bork.bork.bork, richard@test.test
1880 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
1881 Reply-To: Roundup issue tracker
1882  <issue_tracker@your.tracker.email.domain.example>
1883 MIME-Version: 1.0
1884 Message-Id: <followup_dummy_id>
1885 In-Reply-To: <dummy_test_message_id>
1886 X-Roundup-Name: Roundup issue tracker
1887 X-Roundup-Loop: hello
1888 X-Roundup-Issue-Status: chatting
1889 Content-Transfer-Encoding: quoted-printable
1892 Contrary, Mary <mary@test.test> added the comment:
1894 A message with first part encoded (encoded oe =C3=B6)
1896 ----------
1897 status: unread -> chatting
1899 _______________________________________________________________________
1900 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1901 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1902 _______________________________________________________________________
1903 ''')
1905     def testContentDisposition(self):
1906         self.doNewIssue()
1907         self._handle_mail('''Content-Type: text/plain;
1908   charset="iso-8859-1"
1909 From: mary <mary@test.test>
1910 To: issue_tracker@your.tracker.email.domain.example
1911 Message-Id: <followup_dummy_id>
1912 In-Reply-To: <dummy_test_message_id>
1913 Subject: [issue1] Testing...
1914 Content-Type: multipart/mixed; boundary="bCsyhTFzCvuiizWE"
1915 Content-Disposition: inline
1918 --bCsyhTFzCvuiizWE
1919 Content-Type: text/plain; charset=us-ascii
1920 Content-Disposition: inline
1922 test attachment binary
1924 --bCsyhTFzCvuiizWE
1925 Content-Type: application/octet-stream
1926 Content-Disposition: attachment; filename="main.dvi"
1927 Content-Transfer-Encoding: base64
1929 SnVzdCBhIHRlc3QgAQo=
1931 --bCsyhTFzCvuiizWE--
1932 ''')
1933         messages = self.db.issue.get('1', 'messages')
1934         messages.sort()
1935         file = self.db.file.getnode (self.db.msg.get(messages[-1], 'files')[0])
1936         self.assertEqual(file.name, 'main.dvi')
1937         self.assertEqual(file.content, 'Just a test \001\n')
1939     def testFollowupStupidQuoting(self):
1940         self.doNewIssue()
1942         self._handle_mail('''Content-Type: text/plain;
1943   charset="iso-8859-1"
1944 From: richard <richard@test.test>
1945 To: issue_tracker@your.tracker.email.domain.example
1946 Message-Id: <followup_dummy_id>
1947 In-Reply-To: <dummy_test_message_id>
1948 Subject: Re: "[issue1] Testing... "
1950 This is a followup
1951 ''')
1952         self.compareMessages(self._get_mail(),
1953 '''FROM: roundup-admin@your.tracker.email.domain.example
1954 TO: chef@bork.bork.bork
1955 Content-Type: text/plain; charset="utf-8"
1956 Subject: [issue1] Testing...
1957 To: chef@bork.bork.bork
1958 From: richard <issue_tracker@your.tracker.email.domain.example>
1959 Reply-To: Roundup issue tracker
1960  <issue_tracker@your.tracker.email.domain.example>
1961 MIME-Version: 1.0
1962 Message-Id: <followup_dummy_id>
1963 In-Reply-To: <dummy_test_message_id>
1964 X-Roundup-Name: Roundup issue tracker
1965 X-Roundup-Loop: hello
1966 X-Roundup-Issue-Status: chatting
1967 Content-Transfer-Encoding: quoted-printable
1970 richard <richard@test.test> added the comment:
1972 This is a followup
1974 ----------
1975 status: unread -> chatting
1977 _______________________________________________________________________
1978 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1979 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1980 _______________________________________________________________________
1981 ''')
1983     def testEmailQuoting(self):
1984         self.instance.config.EMAIL_KEEP_QUOTED_TEXT = 'no'
1985         self.innerTestQuoting('''This is a followup
1986 ''')
1988     def testEmailQuotingRemove(self):
1989         self.instance.config.EMAIL_KEEP_QUOTED_TEXT = 'yes'
1990         self.innerTestQuoting('''Blah blah wrote:
1991 > Blah bklaskdfj sdf asdf jlaskdf skj sdkfjl asdf
1992 >  skdjlkjsdfalsdkfjasdlfkj dlfksdfalksd fj
1995 This is a followup
1996 ''')
1998     def innerTestQuoting(self, expect):
1999         nodeid = self.doNewIssue()
2001         messages = self.db.issue.get(nodeid, 'messages')
2003         self._handle_mail('''Content-Type: text/plain;
2004   charset="iso-8859-1"
2005 From: richard <richard@test.test>
2006 To: issue_tracker@your.tracker.email.domain.example
2007 Message-Id: <followup_dummy_id>
2008 In-Reply-To: <dummy_test_message_id>
2009 Subject: Re: [issue1] Testing...
2011 Blah blah wrote:
2012 > Blah bklaskdfj sdf asdf jlaskdf skj sdkfjl asdf
2013 >  skdjlkjsdfalsdkfjasdlfkj dlfksdfalksd fj
2016 This is a followup
2017 ''')
2018         # figure the new message id
2019         newmessages = self.db.issue.get(nodeid, 'messages')
2020         for msg in messages:
2021             newmessages.remove(msg)
2022         messageid = newmessages[0]
2024         self.compareMessages(self.db.msg.get(messageid, 'content'), expect)
2026     def testUserLookup(self):
2027         i = self.db.user.create(username='user1', address='user1@foo.com')
2028         self.assertEqual(uidFromAddress(self.db, ('', 'user1@foo.com'), 0), i)
2029         self.assertEqual(uidFromAddress(self.db, ('', 'USER1@foo.com'), 0), i)
2030         i = self.db.user.create(username='user2', address='USER2@foo.com')
2031         self.assertEqual(uidFromAddress(self.db, ('', 'USER2@foo.com'), 0), i)
2032         self.assertEqual(uidFromAddress(self.db, ('', 'user2@foo.com'), 0), i)
2034     def testUserAlternateLookup(self):
2035         i = self.db.user.create(username='user1', address='user1@foo.com',
2036                                 alternate_addresses='user1@bar.com')
2037         self.assertEqual(uidFromAddress(self.db, ('', 'user1@bar.com'), 0), i)
2038         self.assertEqual(uidFromAddress(self.db, ('', 'USER1@bar.com'), 0), i)
2040     def testUserCreate(self):
2041         i = uidFromAddress(self.db, ('', 'user@foo.com'), 1)
2042         self.assertNotEqual(uidFromAddress(self.db, ('', 'user@bar.com'), 1), i)
2044     def testRFC2822(self):
2045         ascii_header = "[issue243] This is a \"test\" - with 'quotation' marks"
2046         unicode_header = '[issue244] \xd0\xb0\xd0\xbd\xd0\xb4\xd1\x80\xd0\xb5\xd0\xb9'
2047         unicode_encoded = '=?utf-8?q?[issue244]_=D0=B0=D0=BD=D0=B4=D1=80=D0=B5=D0=B9?='
2048         self.assertEqual(rfc2822.encode_header(ascii_header), ascii_header)
2049         self.assertEqual(rfc2822.encode_header(unicode_header), unicode_encoded)
2051     def testRegistrationConfirmation(self):
2052         otk = "Aj4euk4LZSAdwePohj90SME5SpopLETL"
2053         self.db.getOTKManager().set(otk, username='johannes')
2054         self._handle_mail('''Content-Type: text/plain;
2055   charset="iso-8859-1"
2056 From: Chef <chef@bork.bork.bork>
2057 To: issue_tracker@your.tracker.email.domain.example
2058 Cc: richard@test.test
2059 Message-Id: <dummy_test_message_id>
2060 Subject: Re: Complete your registration to Roundup issue tracker
2061  -- key %s
2063 This is a test confirmation of registration.
2064 ''' % otk)
2065         self.db.user.lookup('johannes')
2067     def testFollowupOnNonIssue(self):
2068         self.db.keyword.create(name='Foo')
2069         self._handle_mail('''Content-Type: text/plain;
2070   charset="iso-8859-1"
2071 From: richard <richard@test.test>
2072 To: issue_tracker@your.tracker.email.domain.example
2073 Message-Id: <followup_dummy_id>
2074 In-Reply-To: <dummy_test_message_id>
2075 Subject: [keyword1] Testing... [name=Bar]
2077 ''')
2078         self.assertEqual(self.db.keyword.get('1', 'name'), 'Bar')
2080     def testResentFrom(self):
2081         nodeid = self._handle_mail('''Content-Type: text/plain;
2082   charset="iso-8859-1"
2083 From: Chef <chef@bork.bork.bork>
2084 Resent-From: mary <mary@test.test>
2085 To: issue_tracker@your.tracker.email.domain.example
2086 Cc: richard@test.test
2087 Message-Id: <dummy_test_message_id>
2088 Subject: [issue] Testing...
2090 This is a test submission of a new issue.
2091 ''')
2092         assert not os.path.exists(SENDMAILDEBUG)
2093         l = self.db.issue.get(nodeid, 'nosy')
2094         l.sort()
2095         self.assertEqual(l, [self.richard_id, self.mary_id])
2096         return nodeid
2098     def testDejaVu(self):
2099         self.assertRaises(IgnoreLoop, self._handle_mail,
2100             '''Content-Type: text/plain;
2101   charset="iso-8859-1"
2102 From: Chef <chef@bork.bork.bork>
2103 X-Roundup-Loop: hello
2104 To: issue_tracker@your.tracker.email.domain.example
2105 Cc: richard@test.test
2106 Message-Id: <dummy_test_message_id>
2107 Subject: Re: [issue] Testing...
2109 Hi, I've been mis-configured to loop messages back to myself.
2110 ''')
2112     def testItsBulkStupid(self):
2113         self.assertRaises(IgnoreBulk, self._handle_mail,
2114             '''Content-Type: text/plain;
2115   charset="iso-8859-1"
2116 From: Chef <chef@bork.bork.bork>
2117 Precedence: bulk
2118 To: issue_tracker@your.tracker.email.domain.example
2119 Cc: richard@test.test
2120 Message-Id: <dummy_test_message_id>
2121 Subject: Re: [issue] Testing...
2123 Hi, I'm on holidays, and this is a dumb auto-responder.
2124 ''')
2126     def testAutoReplyEmailsAreIgnored(self):
2127         self.assertRaises(IgnoreBulk, self._handle_mail,
2128             '''Content-Type: text/plain;
2129   charset="iso-8859-1"
2130 From: Chef <chef@bork.bork.bork>
2131 To: issue_tracker@your.tracker.email.domain.example
2132 Cc: richard@test.test
2133 Message-Id: <dummy_test_message_id>
2134 Subject: Re: [issue] Out of office AutoReply: Back next week
2136 Hi, I am back in the office next week
2137 ''')
2139     def testNoSubject(self):
2140         self.assertRaises(MailUsageError, self._handle_mail,
2141             '''Content-Type: text/plain;
2142   charset="iso-8859-1"
2143 From: Chef <chef@bork.bork.bork>
2144 To: issue_tracker@your.tracker.email.domain.example
2145 Cc: richard@test.test
2146 Reply-To: chef@bork.bork.bork
2147 Message-Id: <dummy_test_message_id>
2149 ''')
2151     #
2152     # TEST FOR INVALID DESIGNATOR HANDLING
2153     #
2154     def testInvalidDesignator(self):
2155         self.assertRaises(MailUsageError, self._handle_mail,
2156             '''Content-Type: text/plain;
2157   charset="iso-8859-1"
2158 From: Chef <chef@bork.bork.bork>
2159 To: issue_tracker@your.tracker.email.domain.example
2160 Subject: [frobulated] testing
2161 Cc: richard@test.test
2162 Reply-To: chef@bork.bork.bork
2163 Message-Id: <dummy_test_message_id>
2165 ''')
2166         self.assertRaises(MailUsageError, self._handle_mail,
2167             '''Content-Type: text/plain;
2168   charset="iso-8859-1"
2169 From: Chef <chef@bork.bork.bork>
2170 To: issue_tracker@your.tracker.email.domain.example
2171 Subject: [issue12345] testing
2172 Cc: richard@test.test
2173 Reply-To: chef@bork.bork.bork
2174 Message-Id: <dummy_test_message_id>
2176 ''')
2178     def testInvalidClassLoose(self):
2179         self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'loose'
2180         nodeid = self._handle_mail('''Content-Type: text/plain;
2181   charset="iso-8859-1"
2182 From: Chef <chef@bork.bork.bork>
2183 To: issue_tracker@your.tracker.email.domain.example
2184 Subject: [frobulated] testing
2185 Cc: richard@test.test
2186 Reply-To: chef@bork.bork.bork
2187 Message-Id: <dummy_test_message_id>
2189 ''')
2190         assert not os.path.exists(SENDMAILDEBUG)
2191         self.assertEqual(self.db.issue.get(nodeid, 'title'),
2192             '[frobulated] testing')
2194     def testInvalidClassLooseReply(self):
2195         self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'loose'
2196         nodeid = self._handle_mail('''Content-Type: text/plain;
2197   charset="iso-8859-1"
2198 From: Chef <chef@bork.bork.bork>
2199 To: issue_tracker@your.tracker.email.domain.example
2200 Subject: Re: [frobulated] testing
2201 Cc: richard@test.test
2202 Reply-To: chef@bork.bork.bork
2203 Message-Id: <dummy_test_message_id>
2205 ''')
2206         assert not os.path.exists(SENDMAILDEBUG)
2207         self.assertEqual(self.db.issue.get(nodeid, 'title'),
2208             '[frobulated] testing')
2210     def testInvalidClassLoose(self):
2211         self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'loose'
2212         nodeid = self._handle_mail('''Content-Type: text/plain;
2213   charset="iso-8859-1"
2214 From: Chef <chef@bork.bork.bork>
2215 To: issue_tracker@your.tracker.email.domain.example
2216 Subject: [issue1234] testing
2217 Cc: richard@test.test
2218 Reply-To: chef@bork.bork.bork
2219 Message-Id: <dummy_test_message_id>
2221 ''')
2222         assert not os.path.exists(SENDMAILDEBUG)
2223         self.assertEqual(self.db.issue.get(nodeid, 'title'),
2224             '[issue1234] testing')
2226     def testClassLooseOK(self):
2227         self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'loose'
2228         self.db.keyword.create(name='Foo')
2229         nodeid = self._handle_mail('''Content-Type: text/plain;
2230   charset="iso-8859-1"
2231 From: Chef <chef@bork.bork.bork>
2232 To: issue_tracker@your.tracker.email.domain.example
2233 Subject: [keyword1] Testing... [name=Bar]
2234 Cc: richard@test.test
2235 Reply-To: chef@bork.bork.bork
2236 Message-Id: <dummy_test_message_id>
2238 ''')
2239         assert not os.path.exists(SENDMAILDEBUG)
2240         self.assertEqual(self.db.keyword.get('1', 'name'), 'Bar')
2242     def testClassStrictInvalid(self):
2243         self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'strict'
2244         self.instance.config.MAILGW_DEFAULT_CLASS = ''
2246         message = '''Content-Type: text/plain;
2247   charset="iso-8859-1"
2248 From: Chef <chef@bork.bork.bork>
2249 To: issue_tracker@your.tracker.email.domain.example
2250 Subject: Testing...
2251 Cc: richard@test.test
2252 Reply-To: chef@bork.bork.bork
2253 Message-Id: <dummy_test_message_id>
2255 '''
2256         self.assertRaises(MailUsageError, self._handle_mail, message)
2258     def testClassStrictValid(self):
2259         self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'strict'
2260         self.instance.config.MAILGW_DEFAULT_CLASS = ''
2262         nodeid = self._handle_mail('''Content-Type: text/plain;
2263   charset="iso-8859-1"
2264 From: Chef <chef@bork.bork.bork>
2265 To: issue_tracker@your.tracker.email.domain.example
2266 Subject: [issue] Testing...
2267 Cc: richard@test.test
2268 Reply-To: chef@bork.bork.bork
2269 Message-Id: <dummy_test_message_id>
2271 ''')
2273         assert not os.path.exists(SENDMAILDEBUG)
2274         self.assertEqual(self.db.issue.get(nodeid, 'title'), 'Testing...')
2276     #
2277     # TEST FOR INVALID COMMANDS HANDLING
2278     #
2279     def testInvalidCommands(self):
2280         self.assertRaises(MailUsageError, self._handle_mail,
2281             '''Content-Type: text/plain;
2282   charset="iso-8859-1"
2283 From: Chef <chef@bork.bork.bork>
2284 To: issue_tracker@your.tracker.email.domain.example
2285 Subject: testing [frobulated]
2286 Cc: richard@test.test
2287 Reply-To: chef@bork.bork.bork
2288 Message-Id: <dummy_test_message_id>
2290 ''')
2292     def testInvalidCommandPassthrough(self):
2293         self.instance.config.MAILGW_SUBJECT_SUFFIX_PARSING = 'none'
2294         nodeid = self._handle_mail('''Content-Type: text/plain;
2295   charset="iso-8859-1"
2296 From: Chef <chef@bork.bork.bork>
2297 To: issue_tracker@your.tracker.email.domain.example
2298 Subject: testing [frobulated]
2299 Cc: richard@test.test
2300 Reply-To: chef@bork.bork.bork
2301 Message-Id: <dummy_test_message_id>
2303 ''')
2304         assert not os.path.exists(SENDMAILDEBUG)
2305         self.assertEqual(self.db.issue.get(nodeid, 'title'),
2306             'testing [frobulated]')
2308     def testInvalidCommandPassthroughLoose(self):
2309         self.instance.config.MAILGW_SUBJECT_SUFFIX_PARSING = 'loose'
2310         nodeid = self._handle_mail('''Content-Type: text/plain;
2311   charset="iso-8859-1"
2312 From: Chef <chef@bork.bork.bork>
2313 To: issue_tracker@your.tracker.email.domain.example
2314 Subject: testing [frobulated]
2315 Cc: richard@test.test
2316 Reply-To: chef@bork.bork.bork
2317 Message-Id: <dummy_test_message_id>
2319 ''')
2320         assert not os.path.exists(SENDMAILDEBUG)
2321         self.assertEqual(self.db.issue.get(nodeid, 'title'),
2322             'testing [frobulated]')
2324     def testInvalidCommandPassthroughLooseOK(self):
2325         self.instance.config.MAILGW_SUBJECT_SUFFIX_PARSING = 'loose'
2326         nodeid = self._handle_mail('''Content-Type: text/plain;
2327   charset="iso-8859-1"
2328 From: Chef <chef@bork.bork.bork>
2329 To: issue_tracker@your.tracker.email.domain.example
2330 Subject: testing [assignedto=mary]
2331 Cc: richard@test.test
2332 Reply-To: chef@bork.bork.bork
2333 Message-Id: <dummy_test_message_id>
2335 ''')
2336         assert not os.path.exists(SENDMAILDEBUG)
2337         self.assertEqual(self.db.issue.get(nodeid, 'title'), 'testing')
2338         self.assertEqual(self.db.issue.get(nodeid, 'assignedto'), self.mary_id)
2340     def testCommandDelimiters(self):
2341         self.instance.config.MAILGW_SUBJECT_SUFFIX_DELIMITERS = '{}'
2342         nodeid = self._handle_mail('''Content-Type: text/plain;
2343   charset="iso-8859-1"
2344 From: Chef <chef@bork.bork.bork>
2345 To: issue_tracker@your.tracker.email.domain.example
2346 Subject: testing {assignedto=mary}
2347 Cc: richard@test.test
2348 Reply-To: chef@bork.bork.bork
2349 Message-Id: <dummy_test_message_id>
2351 ''')
2352         assert not os.path.exists(SENDMAILDEBUG)
2353         self.assertEqual(self.db.issue.get(nodeid, 'title'), 'testing')
2354         self.assertEqual(self.db.issue.get(nodeid, 'assignedto'), self.mary_id)
2356     def testPrefixDelimiters(self):
2357         self.instance.config.MAILGW_SUBJECT_SUFFIX_DELIMITERS = '{}'
2358         self.db.keyword.create(name='Foo')
2359         self._handle_mail('''Content-Type: text/plain;
2360   charset="iso-8859-1"
2361 From: richard <richard@test.test>
2362 To: issue_tracker@your.tracker.email.domain.example
2363 Message-Id: <followup_dummy_id>
2364 In-Reply-To: <dummy_test_message_id>
2365 Subject: {keyword1} Testing... {name=Bar}
2367 ''')
2368         assert not os.path.exists(SENDMAILDEBUG)
2369         self.assertEqual(self.db.keyword.get('1', 'name'), 'Bar')
2371     def testCommandDelimitersIgnore(self):
2372         self.instance.config.MAILGW_SUBJECT_SUFFIX_DELIMITERS = '{}'
2373         nodeid = self._handle_mail('''Content-Type: text/plain;
2374   charset="iso-8859-1"
2375 From: Chef <chef@bork.bork.bork>
2376 To: issue_tracker@your.tracker.email.domain.example
2377 Subject: testing [assignedto=mary]
2378 Cc: richard@test.test
2379 Reply-To: chef@bork.bork.bork
2380 Message-Id: <dummy_test_message_id>
2382 ''')
2383         assert not os.path.exists(SENDMAILDEBUG)
2384         self.assertEqual(self.db.issue.get(nodeid, 'title'),
2385             'testing [assignedto=mary]')
2386         self.assertEqual(self.db.issue.get(nodeid, 'assignedto'), None)
2388     def testReplytoMatch(self):
2389         self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'loose'
2390         nodeid = self.doNewIssue()
2391         nodeid2 = self._handle_mail('''Content-Type: text/plain;
2392   charset="iso-8859-1"
2393 From: Chef <chef@bork.bork.bork>
2394 To: issue_tracker@your.tracker.email.domain.example
2395 Message-Id: <dummy_test_message_id2>
2396 In-Reply-To: <dummy_test_message_id>
2397 Subject: Testing...
2399 Followup message.
2400 ''')
2402         nodeid3 = self._handle_mail('''Content-Type: text/plain;
2403   charset="iso-8859-1"
2404 From: Chef <chef@bork.bork.bork>
2405 To: issue_tracker@your.tracker.email.domain.example
2406 Message-Id: <dummy_test_message_id3>
2407 In-Reply-To: <dummy_test_message_id2>
2408 Subject: Testing...
2410 Yet another message in the same thread/issue.
2411 ''')
2413         self.assertEqual(nodeid, nodeid2)
2414         self.assertEqual(nodeid, nodeid3)
2416     def testHelpSubject(self):
2417         message = '''Content-Type: text/plain;
2418   charset="iso-8859-1"
2419 From: Chef <chef@bork.bork.bork>
2420 To: issue_tracker@your.tracker.email.domain.example
2421 Message-Id: <dummy_test_message_id2>
2422 In-Reply-To: <dummy_test_message_id>
2423 Subject: hElp
2426 '''
2427         self.assertRaises(MailUsageHelp, self._handle_mail, message)
2429     def testMaillistSubject(self):
2430         self.instance.config.MAILGW_SUBJECT_SUFFIX_DELIMITERS = '[]'
2431         self.db.keyword.create(name='Foo')
2432         self._handle_mail('''Content-Type: text/plain;
2433   charset="iso-8859-1"
2434 From: Chef <chef@bork.bork.bork>
2435 To: issue_tracker@your.tracker.email.domain.example
2436 Subject: [mailinglist-name] [keyword1] Testing.. [name=Bar]
2437 Cc: richard@test.test
2438 Reply-To: chef@bork.bork.bork
2439 Message-Id: <dummy_test_message_id>
2441 ''')
2443         assert not os.path.exists(SENDMAILDEBUG)
2444         self.assertEqual(self.db.keyword.get('1', 'name'), 'Bar')
2446     def testUnknownPrefixSubject(self):
2447         self.db.keyword.create(name='Foo')
2448         self._handle_mail('''Content-Type: text/plain;
2449   charset="iso-8859-1"
2450 From: Chef <chef@bork.bork.bork>
2451 To: issue_tracker@your.tracker.email.domain.example
2452 Subject: VeryStrangeRe: [keyword1] Testing.. [name=Bar]
2453 Cc: richard@test.test
2454 Reply-To: chef@bork.bork.bork
2455 Message-Id: <dummy_test_message_id>
2457 ''')
2459         assert not os.path.exists(SENDMAILDEBUG)
2460         self.assertEqual(self.db.keyword.get('1', 'name'), 'Bar')
2462     def testOneCharSubject(self):
2463         message = '''Content-Type: text/plain;
2464   charset="iso-8859-1"
2465 From: Chef <chef@bork.bork.bork>
2466 To: issue_tracker@your.tracker.email.domain.example
2467 Subject: b
2468 Cc: richard@test.test
2469 Reply-To: chef@bork.bork.bork
2470 Message-Id: <dummy_test_message_id>
2472 '''
2473         try:
2474             self._handle_mail(message)
2475         except MailUsageError:
2476             self.fail('MailUsageError raised')
2478     def testIssueidLast(self):
2479         nodeid1 = self.doNewIssue()
2480         nodeid2 = self._handle_mail('''Content-Type: text/plain;
2481   charset="iso-8859-1"
2482 From: mary <mary@test.test>
2483 To: issue_tracker@your.tracker.email.domain.example
2484 Message-Id: <followup_dummy_id>
2485 In-Reply-To: <dummy_test_message_id>
2486 Subject: New title [issue1]
2488 This is a second followup
2489 ''')
2491         assert nodeid1 == nodeid2
2492         self.assertEqual(self.db.issue.get(nodeid2, 'title'), "Testing...")
2494     def testSecurityMessagePermissionContent(self):
2495         id = self.doNewIssue()
2496         issue = self.db.issue.getnode (id)
2497         self.db.security.addRole(name='Nomsg')
2498         self.db.security.addPermissionToRole('Nomsg', 'Email Access')
2499         for cl in 'issue', 'file', 'keyword':
2500             for p in 'View', 'Edit', 'Create':
2501                 self.db.security.addPermissionToRole('Nomsg', p, cl)
2502         self.db.user.set(self.mary_id, roles='Nomsg')
2503         nodeid = self._handle_mail('''Content-Type: text/plain;
2504   charset="iso-8859-1"
2505 From: Chef <chef@bork.bork.bork>
2506 To: issue_tracker@your.tracker.email.domain.example
2507 Message-Id: <dummy_test_message_id_2>
2508 Subject: [issue%(id)s] Testing... [nosy=+mary]
2510 Just a test reply
2511 '''%locals())
2512         assert os.path.exists(SENDMAILDEBUG)
2513         self.compareMessages(self._get_mail(),
2514 '''FROM: roundup-admin@your.tracker.email.domain.example
2515 TO: chef@bork.bork.bork, richard@test.test
2516 Content-Type: text/plain; charset="utf-8"
2517 Subject: [issue1] Testing...
2518 To: richard@test.test
2519 From: "Bork, Chef" <issue_tracker@your.tracker.email.domain.example>
2520 Reply-To: Roundup issue tracker
2521  <issue_tracker@your.tracker.email.domain.example>
2522 MIME-Version: 1.0
2523 Message-Id: <dummy_test_message_id_2>
2524 In-Reply-To: <dummy_test_message_id>
2525 X-Roundup-Name: Roundup issue tracker
2526 X-Roundup-Loop: hello
2527 X-Roundup-Issue-Status: chatting
2528 Content-Transfer-Encoding: quoted-printable
2531 Bork, Chef <chef@bork.bork.bork> added the comment:
2533 Just a test reply
2535 ----------
2536 nosy: +mary
2537 status: unread -> chatting
2539 _______________________________________________________________________
2540 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
2541 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
2542 _______________________________________________________________________
2543 ''')
2545     def testOutlookAttachment(self):
2546         message = '''X-MimeOLE: Produced By Microsoft Exchange V6.5
2547 Content-class: urn:content-classes:message
2548 MIME-Version: 1.0
2549 Content-Type: multipart/mixed;
2550         boundary="----_=_NextPart_001_01CACA65.40A51CBC"
2551 Subject: Example of a failed outlook attachment e-mail
2552 Date: Tue, 23 Mar 2010 01:43:44 -0700
2553 Message-ID: <CA37F17219784343816CA6613D2E339205E7D0F9@nrcwstexb1.nrc.ca>
2554 X-MS-Has-Attach: yes
2555 X-MS-TNEF-Correlator: 
2556 Thread-Topic: Example of a failed outlook attachment e-mail
2557 Thread-Index: AcrKJo/t3pUBBwTpSwWNE3LE67UBDQ==
2558 From: "Hugh" <richard@test.test>
2559 To: <richard@test.test>
2560 X-OriginalArrivalTime: 23 Mar 2010 08:45:57.0350 (UTC) FILETIME=[41893860:01CACA65]
2562 This is a multi-part message in MIME format.
2564 ------_=_NextPart_001_01CACA65.40A51CBC
2565 Content-Type: multipart/alternative;
2566         boundary="----_=_NextPart_002_01CACA65.40A51CBC"
2569 ------_=_NextPart_002_01CACA65.40A51CBC
2570 Content-Type: text/plain;
2571         charset="us-ascii"
2572 Content-Transfer-Encoding: quoted-printable
2575 Hi Richard,
2577 I suppose this isn't the exact message that was sent but is a resend of
2578 one of my trial messages that failed.  For your benefit I changed the
2579 subject line and am adding these words to the message body.  Should
2580 still be as problematic, but if you like I can resend an exact copy of a
2581 failed message changing nothing except putting your address instead of
2582 our tracker.
2584 Thanks very much for taking time to look into this.  Much appreciated.
2586  <<battery backup>>=20
2588 ------_=_NextPart_002_01CACA65.40A51CBC
2589 Content-Type: text/html;
2590         charset="us-ascii"
2591 Content-Transfer-Encoding: quoted-printable
2593 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
2594 <HTML>
2595 <HEAD>
2596 <META HTTP-EQUIV=3D"Content-Type" CONTENT=3D"text/html; =
2597 charset=3Dus-ascii">
2598 <META NAME=3D"Generator" CONTENT=3D"MS Exchange Server version =
2599 6.5.7654.12">
2600 <TITLE>Example of a failed outlook attachment e-mail</TITLE>
2601 </HEAD>
2602 <BODY>
2603 <!-- Converted from text/rtf format -->
2604 <BR>
2606 <P><FONT SIZE=3D2 FACE=3D"Arial">Hi Richard,</FONT>
2607 </P>
2609 <P><FONT SIZE=3D2 FACE=3D"Arial">I suppose this isn't the exact message =
2610 that was sent but is a resend of one of my trial messages that =
2611 failed.&nbsp; For your benefit I changed the subject line and am adding =
2612 these words to the message body.&nbsp; Should still be as problematic, =
2613 but if you like I can resend an exact copy of a failed message changing =
2614 nothing except putting your address instead of our tracker.</FONT></P>
2616 <P><FONT SIZE=3D2 FACE=3D"Arial">Thanks very much for taking time to =
2617 look into this.&nbsp; Much appreciated.</FONT>
2618 </P>
2619 <BR>
2621 <P><FONT FACE=3D"Arial" SIZE=3D2 COLOR=3D"#000000"> &lt;&lt;battery =
2622 backup&gt;&gt; </FONT>
2623 </P>
2625 </BODY>
2626 </HTML>
2627 ------_=_NextPart_002_01CACA65.40A51CBC--
2629 ------_=_NextPart_001_01CACA65.40A51CBC
2630 Content-Type: message/rfc822
2631 Content-Transfer-Encoding: 7bit
2633 X-MimeOLE: Produced By Microsoft Exchange V6.5
2634 MIME-Version: 1.0
2635 Content-Type: multipart/alternative;
2636         boundary="----_=_NextPart_003_01CAC15A.29717800"
2637 X-OriginalArrivalTime: 11 Mar 2010 20:33:51.0249 (UTC) FILETIME=[28FEE010:01CAC15A]
2638 Content-class: urn:content-classes:message
2639 Subject: battery backup
2640 Date: Thu, 11 Mar 2010 13:33:43 -0700
2641 Message-ID: <p06240809c7bf02f9624c@[128.114.22.203]>
2642 X-MS-Has-Attach: 
2643 X-MS-TNEF-Correlator: 
2644 Thread-Topic: battery backup
2645 Thread-Index: AcrBWimtulTrSvBdQ2CcfZ8lyQdxmQ==
2646 From: "Jerry" <jerry@test.test>
2647 To: "Hugh" <hugh@test.test>
2649 This is a multi-part message in MIME format.
2651 ------_=_NextPart_003_01CAC15A.29717800
2652 Content-Type: text/plain;
2653         charset="iso-8859-1"
2654 Content-Transfer-Encoding: quoted-printable
2656 Dear Hugh,
2657         A car batter has an energy capacity of ~ 500Wh.  A UPS=20
2658 battery is worse than this.
2660 if we need to provied 100kW for 30 minutes that will take 100 car=20
2661 batteries.  This seems like an awful lot of batteries.
2663 Of course I like your idea of making the time 1 minute, so we get to=20
2664 a more modest number of batteries
2666 Jerry
2669 ------_=_NextPart_003_01CAC15A.29717800
2670 Content-Type: text/html;
2671         charset="iso-8859-1"
2672 Content-Transfer-Encoding: quoted-printable
2674 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
2675 <HTML>
2676 <HEAD>
2677 <META HTTP-EQUIV=3D"Content-Type" CONTENT=3D"text/html; =
2678 charset=3Diso-8859-1">
2679 <META NAME=3D"Generator" CONTENT=3D"MS Exchange Server version =
2680 6.5.7654.12">
2681 <TITLE>battery backup</TITLE>
2682 </HEAD>
2683 <BODY>
2684 <!-- Converted from text/plain format -->
2686 <P><FONT SIZE=3D2>Dear Hugh,</FONT>
2688 <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <FONT SIZE=3D2>A car =
2689 batter has an energy capacity of ~ 500Wh.&nbsp; A UPS </FONT>
2691 <BR><FONT SIZE=3D2>battery is worse than this.</FONT>
2692 </P>
2694 <P><FONT SIZE=3D2>if we need to provied 100kW for 30 minutes that will =
2695 take 100 car </FONT>
2697 <BR><FONT SIZE=3D2>batteries.&nbsp; This seems like an awful lot of =
2698 batteries.</FONT>
2699 </P>
2701 <P><FONT SIZE=3D2>Of course I like your idea of making the time 1 =
2702 minute, so we get to </FONT>
2704 <BR><FONT SIZE=3D2>a more modest number of batteries</FONT>
2705 </P>
2707 <P><FONT SIZE=3D2>Jerry</FONT>
2708 </P>
2710 </BODY>
2711 </HTML>
2712 ------_=_NextPart_003_01CAC15A.29717800--
2714 ------_=_NextPart_001_01CACA65.40A51CBC--
2715 '''
2716         nodeid = self._handle_mail(message)
2717         assert not os.path.exists(SENDMAILDEBUG)
2718         msgid = self.db.issue.get(nodeid, 'messages')[0]
2719         self.assert_(self.db.msg.get(msgid, 'content').startswith('Hi Richard'))
2720         self.assertEqual(self.db.msg.get(msgid, 'files'), ['1', '2'])
2721         fileid = self.db.msg.get(msgid, 'files')[0]
2722         self.assertEqual(self.db.file.get(fileid, 'type'), 'text/html')
2723         fileid = self.db.msg.get(msgid, 'files')[1]
2724         self.assertEqual(self.db.file.get(fileid, 'type'), 'message/rfc822')
2726     def testForwardedMessageAttachment(self):
2727         message = '''Return-Path: <rgg@test.test>
2728 Received: from localhost(127.0.0.1), claiming to be "[115.130.26.69]"
2729 via SMTP by localhost, id smtpdAAApLaWrq; Tue Apr 13 23:10:05 2010
2730 Message-ID: <4BC4F9C7.50409@test.test>
2731 Date: Wed, 14 Apr 2010 09:09:59 +1000
2732 From: Rupert Goldie <rgg@test.test>
2733 User-Agent: Thunderbird 2.0.0.24 (Windows/20100228)
2734 MIME-Version: 1.0
2735 To: ekit issues <issues@test.test>
2736 Subject: [Fwd: PHP ERROR (fb)] post limit reached
2737 Content-Type: multipart/mixed; boundary="------------000807090608060304010403"
2739 This is a multi-part message in MIME format.
2740 --------------000807090608060304010403
2741 Content-Type: text/plain; charset=ISO-8859-1; format=flowed
2742 Content-Transfer-Encoding: 7bit
2744 Catch this exception and log it without emailing.
2746 --------------000807090608060304010403
2747 Content-Type: message/rfc822; name="PHP ERROR (fb).eml"
2748 Content-Transfer-Encoding: 7bit
2749 Content-Disposition: inline; filename="PHP ERROR (fb).eml"
2751 Return-Path: <ektravj@test.test>
2752 X-Sieve: CMU Sieve 2.2
2753 via SMTP by crown.off.ekorp.com, id smtpdAAA1JaW1o; Tue Apr 13 23:01:04 2010
2754 X-Virus-Scanned: by amavisd-new at ekit.com
2755 To: facebook-errors@test.test
2756 From: ektravj@test.test
2757 Subject: PHP ERROR (fb)
2758 Message-Id: <20100413230100.D601D27E84@mail2.elax3.ekorp.com>
2759 Date: Tue, 13 Apr 2010 23:01:00 +0000 (UTC)
2761 [13-Apr-2010 22:49:02] PHP Fatal error:  Uncaught exception 'Exception' with message 'Facebook Error Message: Feed action request limit reached' in /app/01/www/virtual/fb.ekit.com/htdocs/includes/functions.php:280
2762 Stack trace:
2763 #0 /app/01/www/virtual/fb.ekit.com/htdocs/gateway/ekit/feed/index.php(178): fb_exceptions(Object(FacebookRestClientException))
2764 #1 {main}
2765  thrown in /app/01/www/virtual/fb.ekit.com/htdocs/includes/functions.php on line 280
2768 --------------000807090608060304010403--
2769 '''
2770         nodeid = self._handle_mail(message)
2771         assert not os.path.exists(SENDMAILDEBUG)
2772         msgid = self.db.issue.get(nodeid, 'messages')[0]
2773         self.assertEqual(self.db.msg.get(msgid, 'content'),
2774             'Catch this exception and log it without emailing.')
2775         self.assertEqual(self.db.msg.get(msgid, 'files'), ['1'])
2776         fileid = self.db.msg.get(msgid, 'files')[0]
2777         self.assertEqual(self.db.file.get(fileid, 'type'), 'message/rfc822')
2779 def test_suite():
2780     suite = unittest.TestSuite()
2781     suite.addTest(unittest.makeSuite(MailgwTestCase))
2782     return suite
2784 if __name__ == '__main__':
2785     runner = unittest.TextTestRunner()
2786     unittest.main(testRunner=runner)
2788 # vim: set filetype=python sts=4 sw=4 et si :