Code

The mail-gateway used to process messages fetched, e.g., via imap in a
[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.mailgw import MailGW, Unauthorized, uidFromAddress, \
25     parseContent, IgnoreLoop, IgnoreBulk, MailUsageError, MailUsageHelp
26 from roundup import init, instance, password, rfc2822, __version__
27 from roundup.anypy.sets_ import set
29 import db_test_base
31 class Message(rfc822.Message):
32     """String-based Message class with equivalence test."""
33     def __init__(self, s):
34         rfc822.Message.__init__(self, StringIO(s.strip()))
36     def __eq__(self, other):
37         return (self.dict == other.dict and
38                 self.fp.read() == other.fp.read())
40 class DiffHelper:
41     def compareMessages(self, new, old):
42         """Compare messages for semantic equivalence."""
43         new, old = Message(new), Message(old)
45         # all Roundup-generated messages have "Precedence: bulk"
46         old['Precedence'] = 'bulk'
48         # don't try to compare the date
49         del new['date'], old['date']
51         if not new == old:
52             res = []
54             for key in new.keys():
55                 if key.startswith('from '):
56                     # skip the unix from line
57                     continue
58                 if key.lower() == 'x-roundup-version':
59                     # version changes constantly, so handle it specially
60                     if new[key] != __version__:
61                         res.append('  %s: %r != %r' % (key, __version__,
62                             new[key]))
63                 elif new.get(key, '') != old.get(key, ''):
64                     res.append('  %s: %r != %r' % (key, old.get(key, ''),
65                         new.get(key, '')))
67             body_diff = self.compareStrings(new.fp.read(), old.fp.read())
68             if body_diff:
69                 res.append('')
70                 res.extend(body_diff)
72             if res:
73                 res.insert(0, 'Generated message not correct (diff follows):')
74                 raise AssertionError, '\n'.join(res)
76     def compareStrings(self, s2, s1):
77         '''Note the reversal of s2 and s1 - difflib.SequenceMatcher wants
78            the first to be the "original" but in the calls in this file,
79            the second arg is the original. Ho hum.
80         '''
81         l1 = s1.strip().split('\n')
82         l2 = s2.strip().split('\n')
83         if l1 == l2:
84             return
85         s = difflib.SequenceMatcher(None, l1, l2)
86         res = []
87         for value, s1s, s1e, s2s, s2e in s.get_opcodes():
88             if value == 'equal':
89                 for i in range(s1s, s1e):
90                     res.append('  %s'%l1[i])
91             elif value == 'delete':
92                 for i in range(s1s, s1e):
93                     res.append('- %s'%l1[i])
94             elif value == 'insert':
95                 for i in range(s2s, s2e):
96                     res.append('+ %s'%l2[i])
97             elif value == 'replace':
98                 for i, j in zip(range(s1s, s1e), range(s2s, s2e)):
99                     res.append('- %s'%l1[i])
100                     res.append('+ %s'%l2[j])
102         return res
104 class MailgwTestCase(unittest.TestCase, DiffHelper):
105     count = 0
106     schema = 'classic'
107     def setUp(self):
108         MailgwTestCase.count = MailgwTestCase.count + 1
109         self.dirname = '_test_mailgw_%s'%self.count
110         # set up and open a tracker
111         self.instance = db_test_base.setupTracker(self.dirname)
113         # and open the database
114         self.db = self.instance.open('admin')
115         self.chef_id = self.db.user.create(username='Chef',
116             address='chef@bork.bork.bork', realname='Bork, Chef', roles='User')
117         self.richard_id = self.db.user.create(username='richard',
118             address='richard@test.test', roles='User')
119         self.mary_id = self.db.user.create(username='mary',
120             address='mary@test.test', roles='User', realname='Contrary, Mary')
121         self.john_id = self.db.user.create(username='john',
122             address='john@test.test', roles='User', realname='John Doe',
123             alternate_addresses='jondoe@test.test\njohn.doe@test.test')
125     def tearDown(self):
126         if os.path.exists(SENDMAILDEBUG):
127             os.remove(SENDMAILDEBUG)
128         self.db.close()
129         try:
130             shutil.rmtree(self.dirname)
131         except OSError, error:
132             if error.errno not in (errno.ENOENT, errno.ESRCH): raise
134     def _handle_mail(self, message):
135         # handler will open a new db handle. On single-threaded
136         # databases we'll have to close our current connection
137         self.db.commit()
138         self.db.close()
139         handler = self.instance.MailGW(self.instance)
140         handler.trapExceptions = 0
141         ret = handler.main(StringIO(message))
142         # handler had its own database, open new connection
143         self.db = self.instance.open('admin')
144         return ret
146     def _get_mail(self):
147         f = open(SENDMAILDEBUG)
148         try:
149             return f.read()
150         finally:
151             f.close()
153     def testEmptyMessage(self):
154         nodeid = self._handle_mail('''Content-Type: text/plain;
155   charset="iso-8859-1"
156 From: Chef <chef@bork.bork.bork>
157 To: issue_tracker@your.tracker.email.domain.example
158 Cc: richard@test.test
159 Reply-To: chef@bork.bork.bork
160 Message-Id: <dummy_test_message_id>
161 Subject: [issue] Testing...
163 ''')
164         assert not os.path.exists(SENDMAILDEBUG)
165         self.assertEqual(self.db.issue.get(nodeid, 'title'), 'Testing...')
167     def doNewIssue(self):
168         nodeid = self._handle_mail('''Content-Type: text/plain;
169   charset="iso-8859-1"
170 From: Chef <chef@bork.bork.bork>
171 To: issue_tracker@your.tracker.email.domain.example
172 Cc: richard@test.test
173 Message-Id: <dummy_test_message_id>
174 Subject: [issue] Testing...
176 This is a test submission of a new issue.
177 ''')
178         assert not os.path.exists(SENDMAILDEBUG)
179         l = self.db.issue.get(nodeid, 'nosy')
180         l.sort()
181         self.assertEqual(l, [self.chef_id, self.richard_id])
182         return nodeid
184     def testNewIssue(self):
185         self.doNewIssue()
187     def testNewIssueNosy(self):
188         self.instance.config.ADD_AUTHOR_TO_NOSY = 'yes'
189         nodeid = self._handle_mail('''Content-Type: text/plain;
190   charset="iso-8859-1"
191 From: Chef <chef@bork.bork.bork>
192 To: issue_tracker@your.tracker.email.domain.example
193 Cc: richard@test.test
194 Message-Id: <dummy_test_message_id>
195 Subject: [issue] Testing...
197 This is a test submission of a new issue.
198 ''')
199         assert not os.path.exists(SENDMAILDEBUG)
200         l = self.db.issue.get(nodeid, 'nosy')
201         l.sort()
202         self.assertEqual(l, [self.chef_id, self.richard_id])
204     def testAlternateAddress(self):
205         self._handle_mail('''Content-Type: text/plain;
206   charset="iso-8859-1"
207 From: John Doe <john.doe@test.test>
208 To: issue_tracker@your.tracker.email.domain.example
209 Message-Id: <dummy_test_message_id>
210 Subject: [issue] Testing...
212 This is a test submission of a new issue.
213 ''')
214         userlist = self.db.user.list()
215         assert not os.path.exists(SENDMAILDEBUG)
216         self.assertEqual(userlist, self.db.user.list(),
217             "user created when it shouldn't have been")
219     def testNewIssueNoClass(self):
220         self._handle_mail('''Content-Type: text/plain;
221   charset="iso-8859-1"
222 From: Chef <chef@bork.bork.bork>
223 To: issue_tracker@your.tracker.email.domain.example
224 Cc: richard@test.test
225 Message-Id: <dummy_test_message_id>
226 Subject: Testing...
228 This is a test submission of a new issue.
229 ''')
230         assert not os.path.exists(SENDMAILDEBUG)
232     def testNewIssueAuthMsg(self):
233         # TODO: fix the damn config - this is apalling
234         self.db.config.MESSAGES_TO_AUTHOR = 'yes'
235         self._handle_mail('''Content-Type: text/plain;
236   charset="iso-8859-1"
237 From: Chef <chef@bork.bork.bork>
238 To: issue_tracker@your.tracker.email.domain.example
239 Message-Id: <dummy_test_message_id>
240 Subject: [issue] Testing... [nosy=mary; assignedto=richard]
242 This is a test submission of a new issue.
243 ''')
244         self.compareMessages(self._get_mail(),
245 '''FROM: roundup-admin@your.tracker.email.domain.example
246 TO: chef@bork.bork.bork, mary@test.test, richard@test.test
247 Content-Type: text/plain; charset="utf-8"
248 Subject: [issue1] Testing...
249 To: chef@bork.bork.bork, mary@test.test, richard@test.test
250 From: "Bork, Chef" <issue_tracker@your.tracker.email.domain.example>
251 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
252 MIME-Version: 1.0
253 Message-Id: <dummy_test_message_id>
254 X-Roundup-Name: Roundup issue tracker
255 X-Roundup-Loop: hello
256 X-Roundup-Issue-Status: unread
257 Content-Transfer-Encoding: quoted-printable
260 New submission from Bork, Chef <chef@bork.bork.bork>:
262 This is a test submission of a new issue.
264 ----------
265 assignedto: richard
266 messages: 1
267 nosy: Chef, mary, richard
268 status: unread
269 title: Testing...
271 _______________________________________________________________________
272 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
273 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
274 _______________________________________________________________________
275 ''')
277     def testNewIssueNoAuthorInfo(self):
278         self.db.config.MAIL_ADD_AUTHORINFO = 'no'
279         self._handle_mail('''Content-Type: text/plain;
280   charset="iso-8859-1"
281 From: Chef <chef@bork.bork.bork>
282 To: issue_tracker@your.tracker.email.domain.example
283 Message-Id: <dummy_test_message_id>
284 Subject: [issue] Testing... [nosy=mary; assignedto=richard]
286 This is a test submission of a new issue.
287 ''')
288         self.compareMessages(self._get_mail(),
289 '''FROM: roundup-admin@your.tracker.email.domain.example
290 TO: chef@bork.bork.bork, mary@test.test, richard@test.test
291 Content-Type: text/plain; charset="utf-8"
292 Subject: [issue1] Testing...
293 To: mary@test.test, richard@test.test
294 From: "Bork, Chef" <issue_tracker@your.tracker.email.domain.example>
295 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
296 MIME-Version: 1.0
297 Message-Id: <dummy_test_message_id>
298 X-Roundup-Name: Roundup issue tracker
299 X-Roundup-Loop: hello
300 X-Roundup-Issue-Status: unread
301 Content-Transfer-Encoding: quoted-printable
303 This is a test submission of a new issue.
305 ----------
306 assignedto: richard
307 messages: 1
308 nosy: Chef, mary, richard
309 status: unread
310 title: Testing...
312 _______________________________________________________________________
313 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
314 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
315 _______________________________________________________________________
316 ''')
318     def testNewIssueNoAuthorEmail(self):
319         self.db.config.MAIL_ADD_AUTHOREMAIL = 'no'
320         self._handle_mail('''Content-Type: text/plain;
321   charset="iso-8859-1"
322 From: Chef <chef@bork.bork.bork>
323 To: issue_tracker@your.tracker.email.domain.example
324 Message-Id: <dummy_test_message_id>
325 Subject: [issue] Testing... [nosy=mary; assignedto=richard]
327 This is a test submission of a new issue.
328 ''')
329         self.compareMessages(self._get_mail(),
330 '''FROM: roundup-admin@your.tracker.email.domain.example
331 TO: chef@bork.bork.bork, mary@test.test, richard@test.test
332 Content-Type: text/plain; charset="utf-8"
333 Subject: [issue1] Testing...
334 To: mary@test.test, richard@test.test
335 From: "Bork, Chef" <issue_tracker@your.tracker.email.domain.example>
336 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
337 MIME-Version: 1.0
338 Message-Id: <dummy_test_message_id>
339 X-Roundup-Name: Roundup issue tracker
340 X-Roundup-Loop: hello
341 X-Roundup-Issue-Status: unread
342 Content-Transfer-Encoding: quoted-printable
344 New submission from Bork, Chef:
346 This is a test submission of a new issue.
348 ----------
349 assignedto: richard
350 messages: 1
351 nosy: Chef, mary, richard
352 status: unread
353 title: Testing...
355 _______________________________________________________________________
356 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
357 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
358 _______________________________________________________________________
359 ''')
361     multipart_msg = '''From: mary <mary@test.test>
362 To: issue_tracker@your.tracker.email.domain.example
363 Message-Id: <followup_dummy_id>
364 In-Reply-To: <dummy_test_message_id>
365 Subject: [issue1] Testing...
366 Content-Type: multipart/mixed; boundary="bxyzzy"
367 Content-Disposition: inline
370 --bxyzzy
371 Content-Type: multipart/alternative; boundary="bCsyhTFzCvuiizWE"
372 Content-Disposition: inline
374 --bCsyhTFzCvuiizWE
375 Content-Type: text/plain; charset=us-ascii
376 Content-Disposition: inline
378 test attachment first text/plain
380 --bCsyhTFzCvuiizWE
381 Content-Type: application/octet-stream
382 Content-Disposition: attachment; filename="first.dvi"
383 Content-Transfer-Encoding: base64
385 SnVzdCBhIHRlc3QgAQo=
387 --bCsyhTFzCvuiizWE
388 Content-Type: text/plain; charset=us-ascii
389 Content-Disposition: inline
391 test attachment second text/plain
393 --bCsyhTFzCvuiizWE
394 Content-Type: text/html
395 Content-Disposition: inline
397 <html>
398 to be ignored.
399 </html>
401 --bCsyhTFzCvuiizWE--
403 --bxyzzy
404 Content-Type: multipart/alternative; boundary="bCsyhTFzCvuiizWF"
405 Content-Disposition: inline
407 --bCsyhTFzCvuiizWF
408 Content-Type: text/plain; charset=us-ascii
409 Content-Disposition: inline
411 test attachment third text/plain
413 --bCsyhTFzCvuiizWF
414 Content-Type: application/octet-stream
415 Content-Disposition: attachment; filename="second.dvi"
416 Content-Transfer-Encoding: base64
418 SnVzdCBhIHRlc3QK
420 --bCsyhTFzCvuiizWF--
422 --bxyzzy--
423 '''
425     def testMultipartKeepAlternatives(self):
426         self.doNewIssue()
427         self._handle_mail(self.multipart_msg)
428         messages = self.db.issue.get('1', 'messages')
429         messages.sort()
430         msg = self.db.msg.getnode (messages[-1])
431         assert(len(msg.files) == 5)
432         names = {0 : 'first.dvi', 4 : 'second.dvi'}
433         content = {3 : 'test attachment third text/plain\n',
434                    4 : 'Just a test\n'}
435         for n, id in enumerate (msg.files):
436             f = self.db.file.getnode (id)
437             self.assertEqual(f.name, names.get (n, 'unnamed'))
438             if n in content :
439                 self.assertEqual(f.content, content [n])
440         self.assertEqual(msg.content, 'test attachment second text/plain')
442     def testMultipartDropAlternatives(self):
443         self.doNewIssue()
444         self.db.config.MAILGW_IGNORE_ALTERNATIVES = True
445         self._handle_mail(self.multipart_msg)
446         messages = self.db.issue.get('1', 'messages')
447         messages.sort()
448         msg = self.db.msg.getnode (messages[-1])
449         assert(len(msg.files) == 2)
450         names = {1 : 'second.dvi'}
451         content = {0 : 'test attachment third text/plain\n',
452                    1 : 'Just a test\n'}
453         for n, id in enumerate (msg.files):
454             f = self.db.file.getnode (id)
455             self.assertEqual(f.name, names.get (n, 'unnamed'))
456             if n in content :
457                 self.assertEqual(f.content, content [n])
458         self.assertEqual(msg.content, 'test attachment second text/plain')
460     def testSimpleFollowup(self):
461         self.doNewIssue()
462         self._handle_mail('''Content-Type: text/plain;
463   charset="iso-8859-1"
464 From: mary <mary@test.test>
465 To: issue_tracker@your.tracker.email.domain.example
466 Message-Id: <followup_dummy_id>
467 In-Reply-To: <dummy_test_message_id>
468 Subject: [issue1] Testing...
470 This is a second followup
471 ''')
472         self.compareMessages(self._get_mail(),
473 '''FROM: roundup-admin@your.tracker.email.domain.example
474 TO: chef@bork.bork.bork, richard@test.test
475 Content-Type: text/plain; charset="utf-8"
476 Subject: [issue1] Testing...
477 To: chef@bork.bork.bork, richard@test.test
478 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
479 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
480 MIME-Version: 1.0
481 Message-Id: <followup_dummy_id>
482 In-Reply-To: <dummy_test_message_id>
483 X-Roundup-Name: Roundup issue tracker
484 X-Roundup-Loop: hello
485 X-Roundup-Issue-Status: chatting
486 Content-Transfer-Encoding: quoted-printable
489 Contrary, Mary <mary@test.test> added the comment:
491 This is a second followup
493 ----------
494 status: unread -> chatting
496 _______________________________________________________________________
497 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
498 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
499 _______________________________________________________________________
500 ''')
502     def testFollowup(self):
503         self.doNewIssue()
505         self._handle_mail('''Content-Type: text/plain;
506   charset="iso-8859-1"
507 From: richard <richard@test.test>
508 To: issue_tracker@your.tracker.email.domain.example
509 Message-Id: <followup_dummy_id>
510 In-Reply-To: <dummy_test_message_id>
511 Subject: [issue1] Testing... [assignedto=mary; nosy=+john]
513 This is a followup
514 ''')
515         l = self.db.issue.get('1', 'nosy')
516         l.sort()
517         self.assertEqual(l, [self.chef_id, self.richard_id, self.mary_id,
518             self.john_id])
520         self.compareMessages(self._get_mail(),
521 '''FROM: roundup-admin@your.tracker.email.domain.example
522 TO: chef@bork.bork.bork, john@test.test, mary@test.test
523 Content-Type: text/plain; charset="utf-8"
524 Subject: [issue1] Testing...
525 To: chef@bork.bork.bork, john@test.test, mary@test.test
526 From: richard <issue_tracker@your.tracker.email.domain.example>
527 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
528 MIME-Version: 1.0
529 Message-Id: <followup_dummy_id>
530 In-Reply-To: <dummy_test_message_id>
531 X-Roundup-Name: Roundup issue tracker
532 X-Roundup-Loop: hello
533 X-Roundup-Issue-Status: chatting
534 Content-Transfer-Encoding: quoted-printable
537 richard <richard@test.test> added the comment:
539 This is a followup
541 ----------
542 assignedto:  -> mary
543 nosy: +john, mary
544 status: unread -> chatting
546 _______________________________________________________________________
547 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
548 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
549 _______________________________________________________________________
550 ''')
552     def testPropertyChangeOnly(self):
553         self.doNewIssue()
554         oldvalues = self.db.getnode('issue', '1').copy()
555         oldvalues['assignedto'] = None
556         # reconstruct old behaviour: This would reuse the
557         # database-handle from the doNewIssue above which has committed
558         # as user "Chef". So we close and reopen the db as that user.
559         self.db.close()
560         self.db = self.instance.open('Chef')
561         self.db.issue.set('1', assignedto=self.chef_id)
562         self.db.commit()
563         self.db.issue.nosymessage('1', None, oldvalues)
565         new_mail = ""
566         for line in self._get_mail().split("\n"):
567             if "Message-Id: " in line:
568                 continue
569             if "Date: " in line:
570                 continue
571             new_mail += line+"\n"
573         self.compareMessages(new_mail, """
574 FROM: roundup-admin@your.tracker.email.domain.example
575 TO: chef@bork.bork.bork, richard@test.test
576 Content-Type: text/plain; charset="utf-8"
577 Subject: [issue1] Testing...
578 To: chef@bork.bork.bork, richard@test.test
579 From: "Bork, Chef" <issue_tracker@your.tracker.email.domain.example>
580 X-Roundup-Name: Roundup issue tracker
581 X-Roundup-Loop: hello
582 X-Roundup-Issue-Status: unread
583 X-Roundup-Version: 1.3.3
584 MIME-Version: 1.0
585 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
586 Content-Transfer-Encoding: quoted-printable
589 Change by Bork, Chef <chef@bork.bork.bork>:
592 ----------
593 assignedto:  -> Chef
595 _______________________________________________________________________
596 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
597 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
598 _______________________________________________________________________
599 """)
602     #
603     # FOLLOWUP TITLE MATCH
604     #
605     def testFollowupTitleMatch(self):
606         self.doNewIssue()
607         self._handle_mail('''Content-Type: text/plain;
608   charset="iso-8859-1"
609 From: richard <richard@test.test>
610 To: issue_tracker@your.tracker.email.domain.example
611 Message-Id: <followup_dummy_id>
612 Subject: Re: Testing... [assignedto=mary; nosy=+john]
614 This is a followup
615 ''')
616         self.compareMessages(self._get_mail(),
617 '''FROM: roundup-admin@your.tracker.email.domain.example
618 TO: chef@bork.bork.bork, john@test.test, mary@test.test
619 Content-Type: text/plain; charset="utf-8"
620 Subject: [issue1] Testing...
621 To: chef@bork.bork.bork, john@test.test, mary@test.test
622 From: richard <issue_tracker@your.tracker.email.domain.example>
623 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
624 MIME-Version: 1.0
625 Message-Id: <followup_dummy_id>
626 In-Reply-To: <dummy_test_message_id>
627 X-Roundup-Name: Roundup issue tracker
628 X-Roundup-Loop: hello
629 X-Roundup-Issue-Status: chatting
630 Content-Transfer-Encoding: quoted-printable
633 richard <richard@test.test> added the comment:
635 This is a followup
637 ----------
638 assignedto:  -> mary
639 nosy: +john, mary
640 status: unread -> chatting
642 _______________________________________________________________________
643 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
644 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
645 _______________________________________________________________________
646 ''')
648     def testFollowupTitleMatchMultiRe(self):
649         nodeid1 = self.doNewIssue()
650         nodeid2 = self._handle_mail('''Content-Type: text/plain;
651   charset="iso-8859-1"
652 From: richard <richard@test.test>
653 To: issue_tracker@your.tracker.email.domain.example
654 Message-Id: <followup_dummy_id>
655 Subject: Re: Testing... [assignedto=mary; nosy=+john]
657 This is a followup
658 ''')
660         nodeid3 = self._handle_mail('''Content-Type: text/plain;
661   charset="iso-8859-1"
662 From: richard <richard@test.test>
663 To: issue_tracker@your.tracker.email.domain.example
664 Message-Id: <followup2_dummy_id>
665 Subject: Ang: Re: Testing...
667 This is a followup
668 ''')
669         self.assertEqual(nodeid1, nodeid2)
670         self.assertEqual(nodeid1, nodeid3)
672     def testFollowupTitleMatchNever(self):
673         nodeid = self.doNewIssue()
674         self.db.config.MAILGW_SUBJECT_CONTENT_MATCH = 'never'
675         self.assertNotEqual(self._handle_mail('''Content-Type: text/plain;
676   charset="iso-8859-1"
677 From: richard <richard@test.test>
678 To: issue_tracker@your.tracker.email.domain.example
679 Message-Id: <followup_dummy_id>
680 Subject: Re: Testing...
682 This is a followup
683 '''), nodeid)
685     def testFollowupTitleMatchNeverInterval(self):
686         nodeid = self.doNewIssue()
687         # force failure of the interval
688         time.sleep(2)
689         self.db.config.MAILGW_SUBJECT_CONTENT_MATCH = 'creation 00:00:01'
690         self.assertNotEqual(self._handle_mail('''Content-Type: text/plain;
691   charset="iso-8859-1"
692 From: richard <richard@test.test>
693 To: issue_tracker@your.tracker.email.domain.example
694 Message-Id: <followup_dummy_id>
695 Subject: Re: Testing...
697 This is a followup
698 '''), nodeid)
701     def testFollowupTitleMatchInterval(self):
702         nodeid = self.doNewIssue()
703         self.db.config.MAILGW_SUBJECT_CONTENT_MATCH = 'creation +1d'
704         self.assertEqual(self._handle_mail('''Content-Type: text/plain;
705   charset="iso-8859-1"
706 From: richard <richard@test.test>
707 To: issue_tracker@your.tracker.email.domain.example
708 Message-Id: <followup_dummy_id>
709 Subject: Re: Testing...
711 This is a followup
712 '''), nodeid)
715     def testFollowupNosyAuthor(self):
716         self.doNewIssue()
717         self.db.config.ADD_AUTHOR_TO_NOSY = 'yes'
718         self._handle_mail('''Content-Type: text/plain;
719   charset="iso-8859-1"
720 From: john@test.test
721 To: issue_tracker@your.tracker.email.domain.example
722 Message-Id: <followup_dummy_id>
723 In-Reply-To: <dummy_test_message_id>
724 Subject: [issue1] Testing...
726 This is a followup
727 ''')
729         self.compareMessages(self._get_mail(),
730 '''FROM: roundup-admin@your.tracker.email.domain.example
731 TO: chef@bork.bork.bork, richard@test.test
732 Content-Type: text/plain; charset="utf-8"
733 Subject: [issue1] Testing...
734 To: chef@bork.bork.bork, richard@test.test
735 From: John Doe <issue_tracker@your.tracker.email.domain.example>
736 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
737 MIME-Version: 1.0
738 Message-Id: <followup_dummy_id>
739 In-Reply-To: <dummy_test_message_id>
740 X-Roundup-Name: Roundup issue tracker
741 X-Roundup-Loop: hello
742 X-Roundup-Issue-Status: chatting
743 Content-Transfer-Encoding: quoted-printable
746 John Doe <john@test.test> added the comment:
748 This is a followup
750 ----------
751 nosy: +john
752 status: unread -> chatting
754 _______________________________________________________________________
755 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
756 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
757 _______________________________________________________________________
759 ''')
761     def testFollowupNosyRecipients(self):
762         self.doNewIssue()
763         self.db.config.ADD_RECIPIENTS_TO_NOSY = 'yes'
764         self._handle_mail('''Content-Type: text/plain;
765   charset="iso-8859-1"
766 From: richard@test.test
767 To: issue_tracker@your.tracker.email.domain.example
768 Cc: john@test.test
769 Message-Id: <followup_dummy_id>
770 In-Reply-To: <dummy_test_message_id>
771 Subject: [issue1] Testing...
773 This is a followup
774 ''')
775         self.compareMessages(self._get_mail(),
776 '''FROM: roundup-admin@your.tracker.email.domain.example
777 TO: chef@bork.bork.bork
778 Content-Type: text/plain; charset="utf-8"
779 Subject: [issue1] Testing...
780 To: chef@bork.bork.bork
781 From: richard <issue_tracker@your.tracker.email.domain.example>
782 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
783 MIME-Version: 1.0
784 Message-Id: <followup_dummy_id>
785 In-Reply-To: <dummy_test_message_id>
786 X-Roundup-Name: Roundup issue tracker
787 X-Roundup-Loop: hello
788 X-Roundup-Issue-Status: chatting
789 Content-Transfer-Encoding: quoted-printable
792 richard <richard@test.test> added the comment:
794 This is a followup
796 ----------
797 nosy: +john
798 status: unread -> chatting
800 _______________________________________________________________________
801 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
802 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
803 _______________________________________________________________________
805 ''')
807     def testFollowupNosyAuthorAndCopy(self):
808         self.doNewIssue()
809         self.db.config.ADD_AUTHOR_TO_NOSY = 'yes'
810         self.db.config.MESSAGES_TO_AUTHOR = 'yes'
811         self._handle_mail('''Content-Type: text/plain;
812   charset="iso-8859-1"
813 From: john@test.test
814 To: issue_tracker@your.tracker.email.domain.example
815 Message-Id: <followup_dummy_id>
816 In-Reply-To: <dummy_test_message_id>
817 Subject: [issue1] Testing...
819 This is a followup
820 ''')
821         self.compareMessages(self._get_mail(),
822 '''FROM: roundup-admin@your.tracker.email.domain.example
823 TO: chef@bork.bork.bork, john@test.test, richard@test.test
824 Content-Type: text/plain; charset="utf-8"
825 Subject: [issue1] Testing...
826 To: chef@bork.bork.bork, john@test.test, richard@test.test
827 From: John Doe <issue_tracker@your.tracker.email.domain.example>
828 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
829 MIME-Version: 1.0
830 Message-Id: <followup_dummy_id>
831 In-Reply-To: <dummy_test_message_id>
832 X-Roundup-Name: Roundup issue tracker
833 X-Roundup-Loop: hello
834 X-Roundup-Issue-Status: chatting
835 Content-Transfer-Encoding: quoted-printable
838 John Doe <john@test.test> added the comment:
840 This is a followup
842 ----------
843 nosy: +john
844 status: unread -> chatting
846 _______________________________________________________________________
847 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
848 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
849 _______________________________________________________________________
851 ''')
853     def testFollowupNoNosyAuthor(self):
854         self.doNewIssue()
855         self.instance.config.ADD_AUTHOR_TO_NOSY = 'no'
856         self._handle_mail('''Content-Type: text/plain;
857   charset="iso-8859-1"
858 From: john@test.test
859 To: issue_tracker@your.tracker.email.domain.example
860 Message-Id: <followup_dummy_id>
861 In-Reply-To: <dummy_test_message_id>
862 Subject: [issue1] Testing...
864 This is a followup
865 ''')
866         self.compareMessages(self._get_mail(),
867 '''FROM: roundup-admin@your.tracker.email.domain.example
868 TO: chef@bork.bork.bork, richard@test.test
869 Content-Type: text/plain; charset="utf-8"
870 Subject: [issue1] Testing...
871 To: chef@bork.bork.bork, richard@test.test
872 From: John Doe <issue_tracker@your.tracker.email.domain.example>
873 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
874 MIME-Version: 1.0
875 Message-Id: <followup_dummy_id>
876 In-Reply-To: <dummy_test_message_id>
877 X-Roundup-Name: Roundup issue tracker
878 X-Roundup-Loop: hello
879 X-Roundup-Issue-Status: chatting
880 Content-Transfer-Encoding: quoted-printable
883 John Doe <john@test.test> added the comment:
885 This is a followup
887 ----------
888 status: unread -> chatting
890 _______________________________________________________________________
891 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
892 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
893 _______________________________________________________________________
895 ''')
897     def testFollowupNoNosyRecipients(self):
898         self.doNewIssue()
899         self.instance.config.ADD_RECIPIENTS_TO_NOSY = 'no'
900         self._handle_mail('''Content-Type: text/plain;
901   charset="iso-8859-1"
902 From: richard@test.test
903 To: issue_tracker@your.tracker.email.domain.example
904 Cc: john@test.test
905 Message-Id: <followup_dummy_id>
906 In-Reply-To: <dummy_test_message_id>
907 Subject: [issue1] Testing...
909 This is a followup
910 ''')
911         self.compareMessages(self._get_mail(),
912 '''FROM: roundup-admin@your.tracker.email.domain.example
913 TO: chef@bork.bork.bork
914 Content-Type: text/plain; charset="utf-8"
915 Subject: [issue1] Testing...
916 To: chef@bork.bork.bork
917 From: richard <issue_tracker@your.tracker.email.domain.example>
918 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
919 MIME-Version: 1.0
920 Message-Id: <followup_dummy_id>
921 In-Reply-To: <dummy_test_message_id>
922 X-Roundup-Name: Roundup issue tracker
923 X-Roundup-Loop: hello
924 X-Roundup-Issue-Status: chatting
925 Content-Transfer-Encoding: quoted-printable
928 richard <richard@test.test> added the comment:
930 This is a followup
932 ----------
933 status: unread -> chatting
935 _______________________________________________________________________
936 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
937 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
938 _______________________________________________________________________
940 ''')
942     def testFollowupEmptyMessage(self):
943         self.doNewIssue()
945         self._handle_mail('''Content-Type: text/plain;
946   charset="iso-8859-1"
947 From: richard <richard@test.test>
948 To: issue_tracker@your.tracker.email.domain.example
949 Message-Id: <followup_dummy_id>
950 In-Reply-To: <dummy_test_message_id>
951 Subject: [issue1] Testing... [assignedto=mary; nosy=+john]
953 ''')
954         l = self.db.issue.get('1', 'nosy')
955         l.sort()
956         self.assertEqual(l, [self.chef_id, self.richard_id, self.mary_id,
957             self.john_id])
959         # should be no file created (ie. no message)
960         assert not os.path.exists(SENDMAILDEBUG)
962     def testFollowupEmptyMessageNoSubject(self):
963         self.doNewIssue()
965         self._handle_mail('''Content-Type: text/plain;
966   charset="iso-8859-1"
967 From: richard <richard@test.test>
968 To: issue_tracker@your.tracker.email.domain.example
969 Message-Id: <followup_dummy_id>
970 In-Reply-To: <dummy_test_message_id>
971 Subject: [issue1] [assignedto=mary; nosy=+john]
973 ''')
974         l = self.db.issue.get('1', 'nosy')
975         l.sort()
976         self.assertEqual(l, [self.chef_id, self.richard_id, self.mary_id,
977             self.john_id])
979         # should be no file created (ie. no message)
980         assert not os.path.exists(SENDMAILDEBUG)
982     def testNosyRemove(self):
983         self.doNewIssue()
985         self._handle_mail('''Content-Type: text/plain;
986   charset="iso-8859-1"
987 From: richard <richard@test.test>
988 To: issue_tracker@your.tracker.email.domain.example
989 Message-Id: <followup_dummy_id>
990 In-Reply-To: <dummy_test_message_id>
991 Subject: [issue1] Testing... [nosy=-richard]
993 ''')
994         l = self.db.issue.get('1', 'nosy')
995         l.sort()
996         self.assertEqual(l, [self.chef_id])
998         # NO NOSY MESSAGE SHOULD BE SENT!
999         assert not os.path.exists(SENDMAILDEBUG)
1001     def testNewUserAuthor(self):
1003         l = self.db.user.list()
1004         l.sort()
1005         message = '''Content-Type: text/plain;
1006   charset="iso-8859-1"
1007 From: fubar <fubar@bork.bork.bork>
1008 To: issue_tracker@your.tracker.email.domain.example
1009 Message-Id: <dummy_test_message_id>
1010 Subject: [issue] Testing...
1012 This is a test submission of a new issue.
1013 '''
1014         def hook (db, **kw):
1015             ''' set up callback for db open '''
1016             db.security.role['anonymous'].permissions=[]
1017             anonid = db.user.lookup('anonymous')
1018             db.user.set(anonid, roles='Anonymous')
1019         self.instance.schema_hook = hook
1020         try:
1021             self._handle_mail(message)
1022         except Unauthorized, value:
1023             body_diff = self.compareMessages(str(value), """
1024 You are not a registered user.
1026 Unknown address: fubar@bork.bork.bork
1027 """)
1029             assert not body_diff, body_diff
1031         else:
1032             raise AssertionError, "Unathorized not raised when handling mail"
1035         def hook (db, **kw):
1036             ''' set up callback for db open '''
1037             # Add Web Access role to anonymous, and try again to make sure
1038             # we get a "please register at:" message this time.
1039             p = [
1040                 db.security.getPermission('Create', 'user'),
1041                 db.security.getPermission('Web Access', None),
1042             ]
1043             db.security.role['anonymous'].permissions=p
1044         self.instance.schema_hook = hook
1045         try:
1046             self._handle_mail(message)
1047         except Unauthorized, value:
1048             body_diff = self.compareMessages(str(value), """
1049 You are not a registered user. Please register at:
1051 http://tracker.example/cgi-bin/roundup.cgi/bugs/user?template=register
1053 ...before sending mail to the tracker.
1055 Unknown address: fubar@bork.bork.bork
1056 """)
1058             assert not body_diff, body_diff
1060         else:
1061             raise AssertionError, "Unathorized not raised when handling mail"
1063         # Make sure list of users is the same as before.
1064         m = self.db.user.list()
1065         m.sort()
1066         self.assertEqual(l, m)
1068         def hook (db, **kw):
1069             ''' set up callback for db open '''
1070             # now with the permission
1071             p = [
1072                 db.security.getPermission('Create', 'user'),
1073                 db.security.getPermission('Email Access', None),
1074             ]
1075             db.security.role['anonymous'].permissions=p
1076         self.instance.schema_hook = hook
1077         self._handle_mail(message)
1078         m = self.db.user.list()
1079         m.sort()
1080         self.assertNotEqual(l, m)
1082     def testNewUserAuthorHighBit(self):
1083         l = set(self.db.user.list())
1084         # From: name has Euro symbol in it
1085         message = '''Content-Type: text/plain;
1086   charset="iso-8859-1"
1087 From: =?utf8?b?SOKCrGxsbw==?= <fubar@bork.bork.bork>
1088 To: issue_tracker@your.tracker.email.domain.example
1089 Message-Id: <dummy_test_message_id>
1090 Subject: [issue] Testing...
1092 This is a test submission of a new issue.
1093 '''
1094         def hook (db, **kw):
1095             ''' set up callback for db open '''
1096             p = [
1097                 db.security.getPermission('Create', 'user'),
1098                 db.security.getPermission('Email Access', None),
1099             ]
1100             db.security.role['anonymous'].permissions=p
1101         self.instance.schema_hook = hook
1102         self._handle_mail(message)
1103         m = set(self.db.user.list())
1104         new = list(m - l)[0]
1105         name = self.db.user.get(new, 'realname')
1106         self.assertEquals(name, 'H€llo')
1108     def testEnc01(self):
1109         self.doNewIssue()
1110         self._handle_mail('''Content-Type: text/plain;
1111   charset="iso-8859-1"
1112 From: mary <mary@test.test>
1113 To: issue_tracker@your.tracker.email.domain.example
1114 Message-Id: <followup_dummy_id>
1115 In-Reply-To: <dummy_test_message_id>
1116 Subject: [issue1] Testing...
1117 Content-Type: text/plain;
1118         charset="iso-8859-1"
1119 Content-Transfer-Encoding: quoted-printable
1121 A message with encoding (encoded oe =F6)
1123 ''')
1124         self.compareMessages(self._get_mail(),
1125 '''FROM: roundup-admin@your.tracker.email.domain.example
1126 TO: chef@bork.bork.bork, richard@test.test
1127 Content-Type: text/plain; charset="utf-8"
1128 Subject: [issue1] Testing...
1129 To: chef@bork.bork.bork, richard@test.test
1130 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
1131 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1132 MIME-Version: 1.0
1133 Message-Id: <followup_dummy_id>
1134 In-Reply-To: <dummy_test_message_id>
1135 X-Roundup-Name: Roundup issue tracker
1136 X-Roundup-Loop: hello
1137 X-Roundup-Issue-Status: chatting
1138 Content-Transfer-Encoding: quoted-printable
1141 Contrary, Mary <mary@test.test> added the comment:
1143 A message with encoding (encoded oe =C3=B6)
1145 ----------
1146 status: unread -> chatting
1148 _______________________________________________________________________
1149 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1150 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1151 _______________________________________________________________________
1152 ''')
1154     def testEncNonUTF8(self):
1155         self.doNewIssue()
1156         self.instance.config.EMAIL_CHARSET = 'iso-8859-1'
1157         self._handle_mail('''Content-Type: text/plain;
1158   charset="iso-8859-1"
1159 From: mary <mary@test.test>
1160 To: issue_tracker@your.tracker.email.domain.example
1161 Message-Id: <followup_dummy_id>
1162 In-Reply-To: <dummy_test_message_id>
1163 Subject: [issue1] Testing...
1164 Content-Type: text/plain;
1165         charset="iso-8859-1"
1166 Content-Transfer-Encoding: quoted-printable
1168 A message with encoding (encoded oe =F6)
1170 ''')
1171         self.compareMessages(self._get_mail(),
1172 '''FROM: roundup-admin@your.tracker.email.domain.example
1173 TO: chef@bork.bork.bork, richard@test.test
1174 Content-Type: text/plain; charset="iso-8859-1"
1175 Subject: [issue1] Testing...
1176 To: chef@bork.bork.bork, richard@test.test
1177 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
1178 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1179 MIME-Version: 1.0
1180 Message-Id: <followup_dummy_id>
1181 In-Reply-To: <dummy_test_message_id>
1182 X-Roundup-Name: Roundup issue tracker
1183 X-Roundup-Loop: hello
1184 X-Roundup-Issue-Status: chatting
1185 Content-Transfer-Encoding: quoted-printable
1188 Contrary, Mary <mary@test.test> added the comment:
1190 A message with encoding (encoded oe =F6)
1192 ----------
1193 status: unread -> chatting
1195 _______________________________________________________________________
1196 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1197 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1198 _______________________________________________________________________
1199 ''')
1202     def testMultipartEnc01(self):
1203         self.doNewIssue()
1204         self._handle_mail('''Content-Type: text/plain;
1205   charset="iso-8859-1"
1206 From: mary <mary@test.test>
1207 To: issue_tracker@your.tracker.email.domain.example
1208 Message-Id: <followup_dummy_id>
1209 In-Reply-To: <dummy_test_message_id>
1210 Subject: [issue1] Testing...
1211 Content-Type: multipart/mixed;
1212         boundary="----_=_NextPart_000_01"
1214 This message is in MIME format. Since your mail reader does not understand
1215 this format, some or all of this message may not be legible.
1217 ------_=_NextPart_000_01
1218 Content-Type: text/plain;
1219         charset="iso-8859-1"
1220 Content-Transfer-Encoding: quoted-printable
1222 A message with first part encoded (encoded oe =F6)
1224 ''')
1225         self.compareMessages(self._get_mail(),
1226 '''FROM: roundup-admin@your.tracker.email.domain.example
1227 TO: chef@bork.bork.bork, richard@test.test
1228 Content-Type: text/plain; charset="utf-8"
1229 Subject: [issue1] Testing...
1230 To: chef@bork.bork.bork, richard@test.test
1231 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
1232 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1233 MIME-Version: 1.0
1234 Message-Id: <followup_dummy_id>
1235 In-Reply-To: <dummy_test_message_id>
1236 X-Roundup-Name: Roundup issue tracker
1237 X-Roundup-Loop: hello
1238 X-Roundup-Issue-Status: chatting
1239 Content-Transfer-Encoding: quoted-printable
1242 Contrary, Mary <mary@test.test> added the comment:
1244 A message with first part encoded (encoded oe =C3=B6)
1246 ----------
1247 status: unread -> chatting
1249 _______________________________________________________________________
1250 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1251 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1252 _______________________________________________________________________
1253 ''')
1255     def testContentDisposition(self):
1256         self.doNewIssue()
1257         self._handle_mail('''Content-Type: text/plain;
1258   charset="iso-8859-1"
1259 From: mary <mary@test.test>
1260 To: issue_tracker@your.tracker.email.domain.example
1261 Message-Id: <followup_dummy_id>
1262 In-Reply-To: <dummy_test_message_id>
1263 Subject: [issue1] Testing...
1264 Content-Type: multipart/mixed; boundary="bCsyhTFzCvuiizWE"
1265 Content-Disposition: inline
1268 --bCsyhTFzCvuiizWE
1269 Content-Type: text/plain; charset=us-ascii
1270 Content-Disposition: inline
1272 test attachment binary
1274 --bCsyhTFzCvuiizWE
1275 Content-Type: application/octet-stream
1276 Content-Disposition: attachment; filename="main.dvi"
1277 Content-Transfer-Encoding: base64
1279 SnVzdCBhIHRlc3QgAQo=
1281 --bCsyhTFzCvuiizWE--
1282 ''')
1283         messages = self.db.issue.get('1', 'messages')
1284         messages.sort()
1285         file = self.db.file.getnode (self.db.msg.get(messages[-1], 'files')[0])
1286         self.assertEqual(file.name, 'main.dvi')
1287         self.assertEqual(file.content, 'Just a test \001\n')
1289     def testFollowupStupidQuoting(self):
1290         self.doNewIssue()
1292         self._handle_mail('''Content-Type: text/plain;
1293   charset="iso-8859-1"
1294 From: richard <richard@test.test>
1295 To: issue_tracker@your.tracker.email.domain.example
1296 Message-Id: <followup_dummy_id>
1297 In-Reply-To: <dummy_test_message_id>
1298 Subject: Re: "[issue1] Testing... "
1300 This is a followup
1301 ''')
1302         self.compareMessages(self._get_mail(),
1303 '''FROM: roundup-admin@your.tracker.email.domain.example
1304 TO: chef@bork.bork.bork
1305 Content-Type: text/plain; charset="utf-8"
1306 Subject: [issue1] Testing...
1307 To: chef@bork.bork.bork
1308 From: richard <issue_tracker@your.tracker.email.domain.example>
1309 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1310 MIME-Version: 1.0
1311 Message-Id: <followup_dummy_id>
1312 In-Reply-To: <dummy_test_message_id>
1313 X-Roundup-Name: Roundup issue tracker
1314 X-Roundup-Loop: hello
1315 X-Roundup-Issue-Status: chatting
1316 Content-Transfer-Encoding: quoted-printable
1319 richard <richard@test.test> added the comment:
1321 This is a followup
1323 ----------
1324 status: unread -> chatting
1326 _______________________________________________________________________
1327 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1328 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1329 _______________________________________________________________________
1330 ''')
1332     def testEmailQuoting(self):
1333         self.instance.config.EMAIL_KEEP_QUOTED_TEXT = 'no'
1334         self.innerTestQuoting('''This is a followup
1335 ''')
1337     def testEmailQuotingRemove(self):
1338         self.instance.config.EMAIL_KEEP_QUOTED_TEXT = 'yes'
1339         self.innerTestQuoting('''Blah blah wrote:
1340 > Blah bklaskdfj sdf asdf jlaskdf skj sdkfjl asdf
1341 >  skdjlkjsdfalsdkfjasdlfkj dlfksdfalksd fj
1344 This is a followup
1345 ''')
1347     def innerTestQuoting(self, expect):
1348         nodeid = self.doNewIssue()
1350         messages = self.db.issue.get(nodeid, 'messages')
1352         self._handle_mail('''Content-Type: text/plain;
1353   charset="iso-8859-1"
1354 From: richard <richard@test.test>
1355 To: issue_tracker@your.tracker.email.domain.example
1356 Message-Id: <followup_dummy_id>
1357 In-Reply-To: <dummy_test_message_id>
1358 Subject: Re: [issue1] Testing...
1360 Blah blah wrote:
1361 > Blah bklaskdfj sdf asdf jlaskdf skj sdkfjl asdf
1362 >  skdjlkjsdfalsdkfjasdlfkj dlfksdfalksd fj
1365 This is a followup
1366 ''')
1367         # figure the new message id
1368         newmessages = self.db.issue.get(nodeid, 'messages')
1369         for msg in messages:
1370             newmessages.remove(msg)
1371         messageid = newmessages[0]
1373         self.compareMessages(self.db.msg.get(messageid, 'content'), expect)
1375     def testUserLookup(self):
1376         i = self.db.user.create(username='user1', address='user1@foo.com')
1377         self.assertEqual(uidFromAddress(self.db, ('', 'user1@foo.com'), 0), i)
1378         self.assertEqual(uidFromAddress(self.db, ('', 'USER1@foo.com'), 0), i)
1379         i = self.db.user.create(username='user2', address='USER2@foo.com')
1380         self.assertEqual(uidFromAddress(self.db, ('', 'USER2@foo.com'), 0), i)
1381         self.assertEqual(uidFromAddress(self.db, ('', 'user2@foo.com'), 0), i)
1383     def testUserAlternateLookup(self):
1384         i = self.db.user.create(username='user1', address='user1@foo.com',
1385                                 alternate_addresses='user1@bar.com')
1386         self.assertEqual(uidFromAddress(self.db, ('', 'user1@bar.com'), 0), i)
1387         self.assertEqual(uidFromAddress(self.db, ('', 'USER1@bar.com'), 0), i)
1389     def testUserCreate(self):
1390         i = uidFromAddress(self.db, ('', 'user@foo.com'), 1)
1391         self.assertNotEqual(uidFromAddress(self.db, ('', 'user@bar.com'), 1), i)
1393     def testRFC2822(self):
1394         ascii_header = "[issue243] This is a \"test\" - with 'quotation' marks"
1395         unicode_header = '[issue244] \xd0\xb0\xd0\xbd\xd0\xb4\xd1\x80\xd0\xb5\xd0\xb9'
1396         unicode_encoded = '=?utf-8?q?[issue244]_=D0=B0=D0=BD=D0=B4=D1=80=D0=B5=D0=B9?='
1397         self.assertEqual(rfc2822.encode_header(ascii_header), ascii_header)
1398         self.assertEqual(rfc2822.encode_header(unicode_header), unicode_encoded)
1400     def testRegistrationConfirmation(self):
1401         otk = "Aj4euk4LZSAdwePohj90SME5SpopLETL"
1402         self.db.getOTKManager().set(otk, username='johannes')
1403         self._handle_mail('''Content-Type: text/plain;
1404   charset="iso-8859-1"
1405 From: Chef <chef@bork.bork.bork>
1406 To: issue_tracker@your.tracker.email.domain.example
1407 Cc: richard@test.test
1408 Message-Id: <dummy_test_message_id>
1409 Subject: Re: Complete your registration to Roundup issue tracker
1410  -- key %s
1412 This is a test confirmation of registration.
1413 ''' % otk)
1414         self.db.user.lookup('johannes')
1416     def testFollowupOnNonIssue(self):
1417         self.db.keyword.create(name='Foo')
1418         self._handle_mail('''Content-Type: text/plain;
1419   charset="iso-8859-1"
1420 From: richard <richard@test.test>
1421 To: issue_tracker@your.tracker.email.domain.example
1422 Message-Id: <followup_dummy_id>
1423 In-Reply-To: <dummy_test_message_id>
1424 Subject: [keyword1] Testing... [name=Bar]
1426 ''')
1427         self.assertEqual(self.db.keyword.get('1', 'name'), 'Bar')
1429     def testResentFrom(self):
1430         nodeid = self._handle_mail('''Content-Type: text/plain;
1431   charset="iso-8859-1"
1432 From: Chef <chef@bork.bork.bork>
1433 Resent-From: mary <mary@test.test>
1434 To: issue_tracker@your.tracker.email.domain.example
1435 Cc: richard@test.test
1436 Message-Id: <dummy_test_message_id>
1437 Subject: [issue] Testing...
1439 This is a test submission of a new issue.
1440 ''')
1441         assert not os.path.exists(SENDMAILDEBUG)
1442         l = self.db.issue.get(nodeid, 'nosy')
1443         l.sort()
1444         self.assertEqual(l, [self.richard_id, self.mary_id])
1445         return nodeid
1447     def testDejaVu(self):
1448         self.assertRaises(IgnoreLoop, self._handle_mail,
1449             '''Content-Type: text/plain;
1450   charset="iso-8859-1"
1451 From: Chef <chef@bork.bork.bork>
1452 X-Roundup-Loop: hello
1453 To: issue_tracker@your.tracker.email.domain.example
1454 Cc: richard@test.test
1455 Message-Id: <dummy_test_message_id>
1456 Subject: Re: [issue] Testing...
1458 Hi, I've been mis-configured to loop messages back to myself.
1459 ''')
1461     def testItsBulkStupid(self):
1462         self.assertRaises(IgnoreBulk, self._handle_mail,
1463             '''Content-Type: text/plain;
1464   charset="iso-8859-1"
1465 From: Chef <chef@bork.bork.bork>
1466 Precedence: bulk
1467 To: issue_tracker@your.tracker.email.domain.example
1468 Cc: richard@test.test
1469 Message-Id: <dummy_test_message_id>
1470 Subject: Re: [issue] Testing...
1472 Hi, I'm on holidays, and this is a dumb auto-responder.
1473 ''')
1475     def testAutoReplyEmailsAreIgnored(self):
1476         self.assertRaises(IgnoreBulk, self._handle_mail,
1477             '''Content-Type: text/plain;
1478   charset="iso-8859-1"
1479 From: Chef <chef@bork.bork.bork>
1480 To: issue_tracker@your.tracker.email.domain.example
1481 Cc: richard@test.test
1482 Message-Id: <dummy_test_message_id>
1483 Subject: Re: [issue] Out of office AutoReply: Back next week
1485 Hi, I am back in the office next week
1486 ''')
1488     def testNoSubject(self):
1489         self.assertRaises(MailUsageError, self._handle_mail,
1490             '''Content-Type: text/plain;
1491   charset="iso-8859-1"
1492 From: Chef <chef@bork.bork.bork>
1493 To: issue_tracker@your.tracker.email.domain.example
1494 Cc: richard@test.test
1495 Reply-To: chef@bork.bork.bork
1496 Message-Id: <dummy_test_message_id>
1498 ''')
1500     #
1501     # TEST FOR INVALID DESIGNATOR HANDLING
1502     #
1503     def testInvalidDesignator(self):
1504         self.assertRaises(MailUsageError, self._handle_mail,
1505             '''Content-Type: text/plain;
1506   charset="iso-8859-1"
1507 From: Chef <chef@bork.bork.bork>
1508 To: issue_tracker@your.tracker.email.domain.example
1509 Subject: [frobulated] testing
1510 Cc: richard@test.test
1511 Reply-To: chef@bork.bork.bork
1512 Message-Id: <dummy_test_message_id>
1514 ''')
1515         self.assertRaises(MailUsageError, self._handle_mail,
1516             '''Content-Type: text/plain;
1517   charset="iso-8859-1"
1518 From: Chef <chef@bork.bork.bork>
1519 To: issue_tracker@your.tracker.email.domain.example
1520 Subject: [issue12345] testing
1521 Cc: richard@test.test
1522 Reply-To: chef@bork.bork.bork
1523 Message-Id: <dummy_test_message_id>
1525 ''')
1527     def testInvalidClassLoose(self):
1528         self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'loose'
1529         nodeid = self._handle_mail('''Content-Type: text/plain;
1530   charset="iso-8859-1"
1531 From: Chef <chef@bork.bork.bork>
1532 To: issue_tracker@your.tracker.email.domain.example
1533 Subject: [frobulated] testing
1534 Cc: richard@test.test
1535 Reply-To: chef@bork.bork.bork
1536 Message-Id: <dummy_test_message_id>
1538 ''')
1539         assert not os.path.exists(SENDMAILDEBUG)
1540         self.assertEqual(self.db.issue.get(nodeid, 'title'),
1541             '[frobulated] testing')
1543     def testInvalidClassLooseReply(self):
1544         self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'loose'
1545         nodeid = self._handle_mail('''Content-Type: text/plain;
1546   charset="iso-8859-1"
1547 From: Chef <chef@bork.bork.bork>
1548 To: issue_tracker@your.tracker.email.domain.example
1549 Subject: Re: [frobulated] testing
1550 Cc: richard@test.test
1551 Reply-To: chef@bork.bork.bork
1552 Message-Id: <dummy_test_message_id>
1554 ''')
1555         assert not os.path.exists(SENDMAILDEBUG)
1556         self.assertEqual(self.db.issue.get(nodeid, 'title'),
1557             '[frobulated] testing')
1559     def testInvalidClassLoose(self):
1560         self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'loose'
1561         nodeid = self._handle_mail('''Content-Type: text/plain;
1562   charset="iso-8859-1"
1563 From: Chef <chef@bork.bork.bork>
1564 To: issue_tracker@your.tracker.email.domain.example
1565 Subject: [issue1234] testing
1566 Cc: richard@test.test
1567 Reply-To: chef@bork.bork.bork
1568 Message-Id: <dummy_test_message_id>
1570 ''')
1571         assert not os.path.exists(SENDMAILDEBUG)
1572         self.assertEqual(self.db.issue.get(nodeid, 'title'),
1573             '[issue1234] testing')
1575     def testClassLooseOK(self):
1576         self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'loose'
1577         self.db.keyword.create(name='Foo')
1578         nodeid = self._handle_mail('''Content-Type: text/plain;
1579   charset="iso-8859-1"
1580 From: Chef <chef@bork.bork.bork>
1581 To: issue_tracker@your.tracker.email.domain.example
1582 Subject: [keyword1] Testing... [name=Bar]
1583 Cc: richard@test.test
1584 Reply-To: chef@bork.bork.bork
1585 Message-Id: <dummy_test_message_id>
1587 ''')
1588         assert not os.path.exists(SENDMAILDEBUG)
1589         self.assertEqual(self.db.keyword.get('1', 'name'), 'Bar')
1591     def testClassStrictInvalid(self):
1592         self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'strict'
1593         self.instance.config.MAILGW_DEFAULT_CLASS = ''
1595         message = '''Content-Type: text/plain;
1596   charset="iso-8859-1"
1597 From: Chef <chef@bork.bork.bork>
1598 To: issue_tracker@your.tracker.email.domain.example
1599 Subject: Testing...
1600 Cc: richard@test.test
1601 Reply-To: chef@bork.bork.bork
1602 Message-Id: <dummy_test_message_id>
1604 '''
1605         self.assertRaises(MailUsageError, self._handle_mail, message)
1607     def testClassStrictValid(self):
1608         self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'strict'
1609         self.instance.config.MAILGW_DEFAULT_CLASS = ''
1611         nodeid = self._handle_mail('''Content-Type: text/plain;
1612   charset="iso-8859-1"
1613 From: Chef <chef@bork.bork.bork>
1614 To: issue_tracker@your.tracker.email.domain.example
1615 Subject: [issue] Testing...
1616 Cc: richard@test.test
1617 Reply-To: chef@bork.bork.bork
1618 Message-Id: <dummy_test_message_id>
1620 ''')
1622         assert not os.path.exists(SENDMAILDEBUG)
1623         self.assertEqual(self.db.issue.get(nodeid, 'title'), 'Testing...')
1625     #
1626     # TEST FOR INVALID COMMANDS HANDLING
1627     #
1628     def testInvalidCommands(self):
1629         self.assertRaises(MailUsageError, self._handle_mail,
1630             '''Content-Type: text/plain;
1631   charset="iso-8859-1"
1632 From: Chef <chef@bork.bork.bork>
1633 To: issue_tracker@your.tracker.email.domain.example
1634 Subject: testing [frobulated]
1635 Cc: richard@test.test
1636 Reply-To: chef@bork.bork.bork
1637 Message-Id: <dummy_test_message_id>
1639 ''')
1641     def testInvalidCommandPassthrough(self):
1642         self.instance.config.MAILGW_SUBJECT_SUFFIX_PARSING = 'none'
1643         nodeid = self._handle_mail('''Content-Type: text/plain;
1644   charset="iso-8859-1"
1645 From: Chef <chef@bork.bork.bork>
1646 To: issue_tracker@your.tracker.email.domain.example
1647 Subject: testing [frobulated]
1648 Cc: richard@test.test
1649 Reply-To: chef@bork.bork.bork
1650 Message-Id: <dummy_test_message_id>
1652 ''')
1653         assert not os.path.exists(SENDMAILDEBUG)
1654         self.assertEqual(self.db.issue.get(nodeid, 'title'),
1655             'testing [frobulated]')
1657     def testInvalidCommandPassthroughLoose(self):
1658         self.instance.config.MAILGW_SUBJECT_SUFFIX_PARSING = 'loose'
1659         nodeid = self._handle_mail('''Content-Type: text/plain;
1660   charset="iso-8859-1"
1661 From: Chef <chef@bork.bork.bork>
1662 To: issue_tracker@your.tracker.email.domain.example
1663 Subject: testing [frobulated]
1664 Cc: richard@test.test
1665 Reply-To: chef@bork.bork.bork
1666 Message-Id: <dummy_test_message_id>
1668 ''')
1669         assert not os.path.exists(SENDMAILDEBUG)
1670         self.assertEqual(self.db.issue.get(nodeid, 'title'),
1671             'testing [frobulated]')
1673     def testInvalidCommandPassthroughLooseOK(self):
1674         self.instance.config.MAILGW_SUBJECT_SUFFIX_PARSING = 'loose'
1675         nodeid = self._handle_mail('''Content-Type: text/plain;
1676   charset="iso-8859-1"
1677 From: Chef <chef@bork.bork.bork>
1678 To: issue_tracker@your.tracker.email.domain.example
1679 Subject: testing [assignedto=mary]
1680 Cc: richard@test.test
1681 Reply-To: chef@bork.bork.bork
1682 Message-Id: <dummy_test_message_id>
1684 ''')
1685         assert not os.path.exists(SENDMAILDEBUG)
1686         self.assertEqual(self.db.issue.get(nodeid, 'title'), 'testing')
1687         self.assertEqual(self.db.issue.get(nodeid, 'assignedto'), self.mary_id)
1689     def testCommandDelimiters(self):
1690         self.instance.config.MAILGW_SUBJECT_SUFFIX_DELIMITERS = '{}'
1691         nodeid = self._handle_mail('''Content-Type: text/plain;
1692   charset="iso-8859-1"
1693 From: Chef <chef@bork.bork.bork>
1694 To: issue_tracker@your.tracker.email.domain.example
1695 Subject: testing {assignedto=mary}
1696 Cc: richard@test.test
1697 Reply-To: chef@bork.bork.bork
1698 Message-Id: <dummy_test_message_id>
1700 ''')
1701         assert not os.path.exists(SENDMAILDEBUG)
1702         self.assertEqual(self.db.issue.get(nodeid, 'title'), 'testing')
1703         self.assertEqual(self.db.issue.get(nodeid, 'assignedto'), self.mary_id)
1705     def testPrefixDelimiters(self):
1706         self.instance.config.MAILGW_SUBJECT_SUFFIX_DELIMITERS = '{}'
1707         self.db.keyword.create(name='Foo')
1708         self._handle_mail('''Content-Type: text/plain;
1709   charset="iso-8859-1"
1710 From: richard <richard@test.test>
1711 To: issue_tracker@your.tracker.email.domain.example
1712 Message-Id: <followup_dummy_id>
1713 In-Reply-To: <dummy_test_message_id>
1714 Subject: {keyword1} Testing... {name=Bar}
1716 ''')
1717         assert not os.path.exists(SENDMAILDEBUG)
1718         self.assertEqual(self.db.keyword.get('1', 'name'), 'Bar')
1720     def testCommandDelimitersIgnore(self):
1721         self.instance.config.MAILGW_SUBJECT_SUFFIX_DELIMITERS = '{}'
1722         nodeid = self._handle_mail('''Content-Type: text/plain;
1723   charset="iso-8859-1"
1724 From: Chef <chef@bork.bork.bork>
1725 To: issue_tracker@your.tracker.email.domain.example
1726 Subject: testing [assignedto=mary]
1727 Cc: richard@test.test
1728 Reply-To: chef@bork.bork.bork
1729 Message-Id: <dummy_test_message_id>
1731 ''')
1732         assert not os.path.exists(SENDMAILDEBUG)
1733         self.assertEqual(self.db.issue.get(nodeid, 'title'),
1734             'testing [assignedto=mary]')
1735         self.assertEqual(self.db.issue.get(nodeid, 'assignedto'), None)
1737     def testReplytoMatch(self):
1738         self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'loose'
1739         nodeid = self.doNewIssue()
1740         nodeid2 = self._handle_mail('''Content-Type: text/plain;
1741   charset="iso-8859-1"
1742 From: Chef <chef@bork.bork.bork>
1743 To: issue_tracker@your.tracker.email.domain.example
1744 Message-Id: <dummy_test_message_id2>
1745 In-Reply-To: <dummy_test_message_id>
1746 Subject: Testing...
1748 Followup message.
1749 ''')
1751         nodeid3 = self._handle_mail('''Content-Type: text/plain;
1752   charset="iso-8859-1"
1753 From: Chef <chef@bork.bork.bork>
1754 To: issue_tracker@your.tracker.email.domain.example
1755 Message-Id: <dummy_test_message_id3>
1756 In-Reply-To: <dummy_test_message_id2>
1757 Subject: Testing...
1759 Yet another message in the same thread/issue.
1760 ''')
1762         self.assertEqual(nodeid, nodeid2)
1763         self.assertEqual(nodeid, nodeid3)
1765     def testHelpSubject(self):
1766         message = '''Content-Type: text/plain;
1767   charset="iso-8859-1"
1768 From: Chef <chef@bork.bork.bork>
1769 To: issue_tracker@your.tracker.email.domain.example
1770 Message-Id: <dummy_test_message_id2>
1771 In-Reply-To: <dummy_test_message_id>
1772 Subject: hElp
1775 '''
1776         self.assertRaises(MailUsageHelp, self._handle_mail, message)
1778     def testMaillistSubject(self):
1779         self.instance.config.MAILGW_SUBJECT_SUFFIX_DELIMITERS = '[]'
1780         self.db.keyword.create(name='Foo')
1781         self._handle_mail('''Content-Type: text/plain;
1782   charset="iso-8859-1"
1783 From: Chef <chef@bork.bork.bork>
1784 To: issue_tracker@your.tracker.email.domain.example
1785 Subject: [mailinglist-name] [keyword1] Testing.. [name=Bar]
1786 Cc: richard@test.test
1787 Reply-To: chef@bork.bork.bork
1788 Message-Id: <dummy_test_message_id>
1790 ''')
1792         assert not os.path.exists(SENDMAILDEBUG)
1793         self.assertEqual(self.db.keyword.get('1', 'name'), 'Bar')
1795     def testUnknownPrefixSubject(self):
1796         self.db.keyword.create(name='Foo')
1797         self._handle_mail('''Content-Type: text/plain;
1798   charset="iso-8859-1"
1799 From: Chef <chef@bork.bork.bork>
1800 To: issue_tracker@your.tracker.email.domain.example
1801 Subject: VeryStrangeRe: [keyword1] Testing.. [name=Bar]
1802 Cc: richard@test.test
1803 Reply-To: chef@bork.bork.bork
1804 Message-Id: <dummy_test_message_id>
1806 ''')
1808         assert not os.path.exists(SENDMAILDEBUG)
1809         self.assertEqual(self.db.keyword.get('1', 'name'), 'Bar')
1811     def testIssueidLast(self):
1812         nodeid1 = self.doNewIssue()
1813         nodeid2 = self._handle_mail('''Content-Type: text/plain;
1814   charset="iso-8859-1"
1815 From: mary <mary@test.test>
1816 To: issue_tracker@your.tracker.email.domain.example
1817 Message-Id: <followup_dummy_id>
1818 In-Reply-To: <dummy_test_message_id>
1819 Subject: New title [issue1]
1821 This is a second followup
1822 ''')
1824         assert nodeid1 == nodeid2
1825         self.assertEqual(self.db.issue.get(nodeid2, 'title'), "Testing...")
1828 def test_suite():
1829     suite = unittest.TestSuite()
1830     suite.addTest(unittest.makeSuite(MailgwTestCase))
1831     return suite
1833 if __name__ == '__main__':
1834     runner = unittest.TextTestRunner()
1835     unittest.main(testRunner=runner)
1837 # vim: set filetype=python sts=4 sw=4 et si :