Code

0a69ad6da0042affa97c204ade518e76e5a46103
[roundup.git] / test / test_mailgw.py
1 #
2 # Copyright (c) 2001 Richard Jones, richard@bofh.asn.au.
3 # This module is free software, and you may redistribute it and/or modify
4 # under the same terms as Python, so long as this copyright message and
5 # disclaimer are retained in their original form.
6 #
7 # This module is distributed in the hope that it will be useful,
8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
10 #
11 # $Id: test_mailgw.py,v 1.96 2008-08-19 01:40:59 richard Exp $
13 # TODO: test bcc
15 import unittest, tempfile, os, shutil, errno, imp, sys, difflib, rfc822, time
17 from cStringIO import StringIO
19 if not os.environ.has_key('SENDMAILDEBUG'):
20     os.environ['SENDMAILDEBUG'] = 'mail-test.log'
21 SENDMAILDEBUG = os.environ['SENDMAILDEBUG']
23 from roundup.mailgw import MailGW, Unauthorized, uidFromAddress, \
24     parseContent, IgnoreLoop, IgnoreBulk, MailUsageError, MailUsageHelp
25 from roundup import init, instance, password, rfc2822, __version__
27 import db_test_base
29 class Message(rfc822.Message):
30     """String-based Message class with equivalence test."""
31     def __init__(self, s):
32         rfc822.Message.__init__(self, StringIO(s.strip()))
34     def __eq__(self, other):
35         return (self.dict == other.dict and
36                 self.fp.read() == other.fp.read())
38 class DiffHelper:
39     def compareMessages(self, new, old):
40         """Compare messages for semantic equivalence."""
41         new, old = Message(new), Message(old)
43         # all Roundup-generated messages have "Precedence: bulk"
44         old['Precedence'] = 'bulk'
46         # don't try to compare the date
47         del new['date'], old['date']
49         if not new == old:
50             res = []
52             for key in new.keys():
53                 if key.lower() == 'x-roundup-version':
54                     # version changes constantly, so handle it specially
55                     if new[key] != __version__:
56                         res.append('  %s: %r != %r' % (key, __version__,
57                             new[key]))
58                 elif new.get(key, '') != old.get(key, ''):
59                     res.append('  %s: %r != %r' % (key, old.get(key, ''),
60                         new.get(key, '')))
62             body_diff = self.compareStrings(new.fp.read(), old.fp.read())
63             if body_diff:
64                 res.append('')
65                 res.extend(body_diff)
67             if res:
68                 res.insert(0, 'Generated message not correct (diff follows):')
69                 raise AssertionError, '\n'.join(res)
71     def compareStrings(self, s2, s1):
72         '''Note the reversal of s2 and s1 - difflib.SequenceMatcher wants
73            the first to be the "original" but in the calls in this file,
74            the second arg is the original. Ho hum.
75         '''
76         l1 = s1.strip().split('\n')
77         l2 = s2.strip().split('\n')
78         if l1 == l2:
79             return
80         s = difflib.SequenceMatcher(None, l1, l2)
81         res = []
82         for value, s1s, s1e, s2s, s2e in s.get_opcodes():
83             if value == 'equal':
84                 for i in range(s1s, s1e):
85                     res.append('  %s'%l1[i])
86             elif value == 'delete':
87                 for i in range(s1s, s1e):
88                     res.append('- %s'%l1[i])
89             elif value == 'insert':
90                 for i in range(s2s, s2e):
91                     res.append('+ %s'%l2[i])
92             elif value == 'replace':
93                 for i, j in zip(range(s1s, s1e), range(s2s, s2e)):
94                     res.append('- %s'%l1[i])
95                     res.append('+ %s'%l2[j])
97         return res
99 class MailgwTestCase(unittest.TestCase, DiffHelper):
100     count = 0
101     schema = 'classic'
102     def setUp(self):
103         MailgwTestCase.count = MailgwTestCase.count + 1
104         self.dirname = '_test_mailgw_%s'%self.count
105         # set up and open a tracker
106         self.instance = db_test_base.setupTracker(self.dirname)
108         # and open the database
109         self.db = self.instance.open('admin')
110         self.chef_id = self.db.user.create(username='Chef',
111             address='chef@bork.bork.bork', realname='Bork, Chef', roles='User')
112         self.richard_id = self.db.user.create(username='richard',
113             address='richard@test.test', roles='User')
114         self.mary_id = self.db.user.create(username='mary', address='mary@test.test',
115             roles='User', realname='Contrary, Mary')
116         self.john_id = self.db.user.create(username='john', address='john@test.test',
117             alternate_addresses='jondoe@test.test\njohn.doe@test.test', roles='User',
118             realname='John Doe')
120     def tearDown(self):
121         if os.path.exists(SENDMAILDEBUG):
122             os.remove(SENDMAILDEBUG)
123         self.db.close()
124         try:
125             shutil.rmtree(self.dirname)
126         except OSError, error:
127             if error.errno not in (errno.ENOENT, errno.ESRCH): raise
129     def _handle_mail(self, message):
130         handler = self.instance.MailGW(self.instance, self.db)
131         handler.trapExceptions = 0
132         ret = handler.main(StringIO(message))
133         # handler can close the db on us and open a new one
134         self.db = handler.db
135         return ret
137     def _get_mail(self):
138         f = open(SENDMAILDEBUG)
139         try:
140             return f.read()
141         finally:
142             f.close()
144     def testEmptyMessage(self):
145         nodeid = self._handle_mail('''Content-Type: text/plain;
146   charset="iso-8859-1"
147 From: Chef <chef@bork.bork.bork>
148 To: issue_tracker@your.tracker.email.domain.example
149 Cc: richard@test.test
150 Reply-To: chef@bork.bork.bork
151 Message-Id: <dummy_test_message_id>
152 Subject: [issue] Testing...
154 ''')
155         assert not os.path.exists(SENDMAILDEBUG)
156         self.assertEqual(self.db.issue.get(nodeid, 'title'), 'Testing...')
158     def doNewIssue(self):
159         nodeid = self._handle_mail('''Content-Type: text/plain;
160   charset="iso-8859-1"
161 From: Chef <chef@bork.bork.bork>
162 To: issue_tracker@your.tracker.email.domain.example
163 Cc: richard@test.test
164 Message-Id: <dummy_test_message_id>
165 Subject: [issue] Testing...
167 This is a test submission of a new issue.
168 ''')
169         assert not os.path.exists(SENDMAILDEBUG)
170         l = self.db.issue.get(nodeid, 'nosy')
171         l.sort()
172         self.assertEqual(l, [self.chef_id, self.richard_id])
173         return nodeid
175     def testNewIssue(self):
176         self.doNewIssue()
178     def testNewIssueNosy(self):
179         self.instance.config.ADD_AUTHOR_TO_NOSY = 'yes'
180         nodeid = self._handle_mail('''Content-Type: text/plain;
181   charset="iso-8859-1"
182 From: Chef <chef@bork.bork.bork>
183 To: issue_tracker@your.tracker.email.domain.example
184 Cc: richard@test.test
185 Message-Id: <dummy_test_message_id>
186 Subject: [issue] Testing...
188 This is a test submission of a new issue.
189 ''')
190         assert not os.path.exists(SENDMAILDEBUG)
191         l = self.db.issue.get(nodeid, 'nosy')
192         l.sort()
193         self.assertEqual(l, [self.chef_id, self.richard_id])
195     def testAlternateAddress(self):
196         self._handle_mail('''Content-Type: text/plain;
197   charset="iso-8859-1"
198 From: John Doe <john.doe@test.test>
199 To: issue_tracker@your.tracker.email.domain.example
200 Message-Id: <dummy_test_message_id>
201 Subject: [issue] Testing...
203 This is a test submission of a new issue.
204 ''')
205         userlist = self.db.user.list()
206         assert not os.path.exists(SENDMAILDEBUG)
207         self.assertEqual(userlist, self.db.user.list(),
208             "user created when it shouldn't have been")
210     def testNewIssueNoClass(self):
211         self._handle_mail('''Content-Type: text/plain;
212   charset="iso-8859-1"
213 From: Chef <chef@bork.bork.bork>
214 To: issue_tracker@your.tracker.email.domain.example
215 Cc: richard@test.test
216 Message-Id: <dummy_test_message_id>
217 Subject: Testing...
219 This is a test submission of a new issue.
220 ''')
221         assert not os.path.exists(SENDMAILDEBUG)
223     def testNewIssueAuthMsg(self):
224         # TODO: fix the damn config - this is apalling
225         self.db.config.MESSAGES_TO_AUTHOR = 'yes'
226         self._handle_mail('''Content-Type: text/plain;
227   charset="iso-8859-1"
228 From: Chef <chef@bork.bork.bork>
229 To: issue_tracker@your.tracker.email.domain.example
230 Message-Id: <dummy_test_message_id>
231 Subject: [issue] Testing... [nosy=mary; assignedto=richard]
233 This is a test submission of a new issue.
234 ''')
235         self.compareMessages(self._get_mail(),
236 '''FROM: roundup-admin@your.tracker.email.domain.example
237 TO: chef@bork.bork.bork, mary@test.test, richard@test.test
238 Content-Type: text/plain; charset=utf-8
239 Subject: [issue1] Testing...
240 To: chef@bork.bork.bork, mary@test.test, richard@test.test
241 From: "Bork, Chef" <issue_tracker@your.tracker.email.domain.example>
242 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
243 MIME-Version: 1.0
244 Message-Id: <dummy_test_message_id>
245 X-Roundup-Name: Roundup issue tracker
246 X-Roundup-Loop: hello
247 X-Roundup-Issue-Status: unread
248 Content-Transfer-Encoding: quoted-printable
251 New submission from Bork, Chef <chef@bork.bork.bork>:
253 This is a test submission of a new issue.
255 ----------
256 assignedto: richard
257 messages: 1
258 nosy: Chef, mary, richard
259 status: unread
260 title: Testing...
262 _______________________________________________________________________
263 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
264 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
265 _______________________________________________________________________
266 ''')
268     def testNewIssueNoAuthorInfo(self):
269         self.db.config.MAIL_ADD_AUTHORINFO = 'no'
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: mary@test.test, richard@test.test
285 From: "Bork, Chef" <issue_tracker@your.tracker.email.domain.example>
286 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
287 MIME-Version: 1.0
288 Message-Id: <dummy_test_message_id>
289 X-Roundup-Name: Roundup issue tracker
290 X-Roundup-Loop: hello
291 X-Roundup-Issue-Status: unread
292 Content-Transfer-Encoding: quoted-printable
294 This is a test submission of a new issue.
296 ----------
297 assignedto: richard
298 messages: 1
299 nosy: Chef, mary, richard
300 status: unread
301 title: Testing...
303 _______________________________________________________________________
304 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
305 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
306 _______________________________________________________________________
307 ''')
309     def testNewIssueNoAuthorEmail(self):
310         self.db.config.MAIL_ADD_AUTHOREMAIL = 'no'
311         self._handle_mail('''Content-Type: text/plain;
312   charset="iso-8859-1"
313 From: Chef <chef@bork.bork.bork>
314 To: issue_tracker@your.tracker.email.domain.example
315 Message-Id: <dummy_test_message_id>
316 Subject: [issue] Testing... [nosy=mary; assignedto=richard]
318 This is a test submission of a new issue.
319 ''')
320         self.compareMessages(self._get_mail(),
321 '''FROM: roundup-admin@your.tracker.email.domain.example
322 TO: chef@bork.bork.bork, mary@test.test, richard@test.test
323 Content-Type: text/plain; charset=utf-8
324 Subject: [issue1] Testing...
325 To: mary@test.test, richard@test.test
326 From: "Bork, Chef" <issue_tracker@your.tracker.email.domain.example>
327 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
328 MIME-Version: 1.0
329 Message-Id: <dummy_test_message_id>
330 X-Roundup-Name: Roundup issue tracker
331 X-Roundup-Loop: hello
332 X-Roundup-Issue-Status: unread
333 Content-Transfer-Encoding: quoted-printable
335 New submission from Bork, Chef:
337 This is a test submission of a new issue.
339 ----------
340 assignedto: richard
341 messages: 1
342 nosy: Chef, mary, richard
343 status: unread
344 title: Testing...
346 _______________________________________________________________________
347 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
348 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
349 _______________________________________________________________________
350 ''')
352     multipart_msg = '''From: mary <mary@test.test>
353 To: issue_tracker@your.tracker.email.domain.example
354 Message-Id: <followup_dummy_id>
355 In-Reply-To: <dummy_test_message_id>
356 Subject: [issue1] Testing...
357 Content-Type: multipart/mixed; boundary="bxyzzy"
358 Content-Disposition: inline
361 --bxyzzy
362 Content-Type: multipart/alternative; boundary="bCsyhTFzCvuiizWE"
363 Content-Disposition: inline
365 --bCsyhTFzCvuiizWE
366 Content-Type: text/plain; charset=us-ascii
367 Content-Disposition: inline
369 test attachment first text/plain
371 --bCsyhTFzCvuiizWE
372 Content-Type: application/octet-stream
373 Content-Disposition: attachment; filename="first.dvi"
374 Content-Transfer-Encoding: base64
376 SnVzdCBhIHRlc3QgAQo=
378 --bCsyhTFzCvuiizWE
379 Content-Type: text/plain; charset=us-ascii
380 Content-Disposition: inline
382 test attachment second text/plain
384 --bCsyhTFzCvuiizWE
385 Content-Type: text/html
386 Content-Disposition: inline
388 <html>
389 to be ignored.
390 </html>
392 --bCsyhTFzCvuiizWE--
394 --bxyzzy
395 Content-Type: multipart/alternative; boundary="bCsyhTFzCvuiizWF"
396 Content-Disposition: inline
398 --bCsyhTFzCvuiizWF
399 Content-Type: text/plain; charset=us-ascii
400 Content-Disposition: inline
402 test attachment third text/plain
404 --bCsyhTFzCvuiizWF
405 Content-Type: application/octet-stream
406 Content-Disposition: attachment; filename="second.dvi"
407 Content-Transfer-Encoding: base64
409 SnVzdCBhIHRlc3QK
411 --bCsyhTFzCvuiizWF--
413 --bxyzzy--
414 '''
416     def testMultipartKeepAlternatives(self):
417         self.doNewIssue()
418         self._handle_mail(self.multipart_msg)
419         messages = self.db.issue.get('1', 'messages')
420         messages.sort()
421         msg = self.db.msg.getnode (messages[-1])
422         assert(len(msg.files) == 5)
423         names = {0 : 'first.dvi', 4 : 'second.dvi'}
424         content = {3 : 'test attachment third text/plain\n',
425                    4 : 'Just a test\n'}
426         for n, id in enumerate (msg.files):
427             f = self.db.file.getnode (id)
428             self.assertEqual(f.name, names.get (n, 'unnamed'))
429             if n in content :
430                 self.assertEqual(f.content, content [n])
431         self.assertEqual(msg.content, 'test attachment second text/plain')
433     def testMultipartDropAlternatives(self):
434         self.doNewIssue()
435         self.db.config.MAILGW_IGNORE_ALTERNATIVES = True
436         self._handle_mail(self.multipart_msg)
437         messages = self.db.issue.get('1', 'messages')
438         messages.sort()
439         msg = self.db.msg.getnode (messages[-1])
440         assert(len(msg.files) == 2)
441         names = {1 : 'second.dvi'}
442         content = {0 : 'test attachment third text/plain\n',
443                    1 : 'Just a test\n'}
444         for n, id in enumerate (msg.files):
445             f = self.db.file.getnode (id)
446             self.assertEqual(f.name, names.get (n, 'unnamed'))
447             if n in content :
448                 self.assertEqual(f.content, content [n])
449         self.assertEqual(msg.content, 'test attachment second text/plain')
451     def testSimpleFollowup(self):
452         self.doNewIssue()
453         self._handle_mail('''Content-Type: text/plain;
454   charset="iso-8859-1"
455 From: mary <mary@test.test>
456 To: issue_tracker@your.tracker.email.domain.example
457 Message-Id: <followup_dummy_id>
458 In-Reply-To: <dummy_test_message_id>
459 Subject: [issue1] Testing...
461 This is a second followup
462 ''')
463         self.compareMessages(self._get_mail(),
464 '''FROM: roundup-admin@your.tracker.email.domain.example
465 TO: chef@bork.bork.bork, richard@test.test
466 Content-Type: text/plain; charset=utf-8
467 Subject: [issue1] Testing...
468 To: chef@bork.bork.bork, richard@test.test
469 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
470 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
471 MIME-Version: 1.0
472 Message-Id: <followup_dummy_id>
473 In-Reply-To: <dummy_test_message_id>
474 X-Roundup-Name: Roundup issue tracker
475 X-Roundup-Loop: hello
476 X-Roundup-Issue-Status: chatting
477 Content-Transfer-Encoding: quoted-printable
480 Contrary, Mary <mary@test.test> added the comment:
482 This is a second followup
484 ----------
485 status: unread -> chatting
487 _______________________________________________________________________
488 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
489 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
490 _______________________________________________________________________
491 ''')
493     def testFollowup(self):
494         self.doNewIssue()
496         self._handle_mail('''Content-Type: text/plain;
497   charset="iso-8859-1"
498 From: richard <richard@test.test>
499 To: issue_tracker@your.tracker.email.domain.example
500 Message-Id: <followup_dummy_id>
501 In-Reply-To: <dummy_test_message_id>
502 Subject: [issue1] Testing... [assignedto=mary; nosy=+john]
504 This is a followup
505 ''')
506         l = self.db.issue.get('1', 'nosy')
507         l.sort()
508         self.assertEqual(l, [self.chef_id, self.richard_id, self.mary_id,
509             self.john_id])
511         self.compareMessages(self._get_mail(),
512 '''FROM: roundup-admin@your.tracker.email.domain.example
513 TO: chef@bork.bork.bork, john@test.test, mary@test.test
514 Content-Type: text/plain; charset=utf-8
515 Subject: [issue1] Testing...
516 To: chef@bork.bork.bork, john@test.test, mary@test.test
517 From: richard <issue_tracker@your.tracker.email.domain.example>
518 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
519 MIME-Version: 1.0
520 Message-Id: <followup_dummy_id>
521 In-Reply-To: <dummy_test_message_id>
522 X-Roundup-Name: Roundup issue tracker
523 X-Roundup-Loop: hello
524 X-Roundup-Issue-Status: chatting
525 Content-Transfer-Encoding: quoted-printable
528 richard <richard@test.test> added the comment:
530 This is a followup
532 ----------
533 assignedto:  -> mary
534 nosy: +john, mary
535 status: unread -> chatting
537 _______________________________________________________________________
538 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
539 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
540 _______________________________________________________________________
541 ''')
543     def testPropertyChangeOnly(self):
544         self.doNewIssue()
545         oldvalues = self.db.getnode('issue', '1').copy()
546         oldvalues['assignedto'] = None
547         self.db.issue.set('1', assignedto=self.chef_id)
548         self.db.commit()
549         self.db.issue.nosymessage('1', None, oldvalues)
551         new_mail = ""
552         for line in self._get_mail().split("\n"):
553             if "Message-Id: " in line:
554                 continue
555             if "Date: " in line:
556                 continue
557             new_mail += line+"\n"
559         self.compareMessages(new_mail, """
560 FROM: roundup-admin@your.tracker.email.domain.example
561 TO: chef@bork.bork.bork, richard@test.test
562 Content-Type: text/plain; charset=utf-8
563 Subject: [issue1] Testing...
564 To: chef@bork.bork.bork, richard@test.test
565 From: "Bork, Chef" <issue_tracker@your.tracker.email.domain.example>
566 X-Roundup-Name: Roundup issue tracker
567 X-Roundup-Loop: hello
568 X-Roundup-Issue-Status: unread
569 X-Roundup-Version: 1.3.3
570 MIME-Version: 1.0
571 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
572 Content-Transfer-Encoding: quoted-printable
575 Change by Bork, Chef <chef@bork.bork.bork>:
578 ----------
579 assignedto:  -> Chef
581 _______________________________________________________________________
582 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
583 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
584 _______________________________________________________________________
585 """)
588     #
589     # FOLLOWUP TITLE MATCH
590     #
591     def testFollowupTitleMatch(self):
592         self.doNewIssue()
593         self._handle_mail('''Content-Type: text/plain;
594   charset="iso-8859-1"
595 From: richard <richard@test.test>
596 To: issue_tracker@your.tracker.email.domain.example
597 Message-Id: <followup_dummy_id>
598 Subject: Re: Testing... [assignedto=mary; nosy=+john]
600 This is a followup
601 ''')
602         self.compareMessages(self._get_mail(),
603 '''FROM: roundup-admin@your.tracker.email.domain.example
604 TO: chef@bork.bork.bork, john@test.test, mary@test.test
605 Content-Type: text/plain; charset=utf-8
606 Subject: [issue1] Testing...
607 To: chef@bork.bork.bork, john@test.test, mary@test.test
608 From: richard <issue_tracker@your.tracker.email.domain.example>
609 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
610 MIME-Version: 1.0
611 Message-Id: <followup_dummy_id>
612 In-Reply-To: <dummy_test_message_id>
613 X-Roundup-Name: Roundup issue tracker
614 X-Roundup-Loop: hello
615 X-Roundup-Issue-Status: chatting
616 Content-Transfer-Encoding: quoted-printable
619 richard <richard@test.test> added the comment:
621 This is a followup
623 ----------
624 assignedto:  -> mary
625 nosy: +john, mary
626 status: unread -> chatting
628 _______________________________________________________________________
629 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
630 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
631 _______________________________________________________________________
632 ''')
634     def testFollowupTitleMatchMultiRe(self):
635         nodeid1 = self.doNewIssue()
636         nodeid2 = self._handle_mail('''Content-Type: text/plain;
637   charset="iso-8859-1"
638 From: richard <richard@test.test>
639 To: issue_tracker@your.tracker.email.domain.example
640 Message-Id: <followup_dummy_id>
641 Subject: Re: Testing... [assignedto=mary; nosy=+john]
643 This is a followup
644 ''')
646         nodeid3 = self._handle_mail('''Content-Type: text/plain;
647   charset="iso-8859-1"
648 From: richard <richard@test.test>
649 To: issue_tracker@your.tracker.email.domain.example
650 Message-Id: <followup2_dummy_id>
651 Subject: Ang: Re: Testing...
653 This is a followup
654 ''')
655         self.assertEqual(nodeid1, nodeid2)
656         self.assertEqual(nodeid1, nodeid3)
658     def testFollowupTitleMatchNever(self):
659         nodeid = self.doNewIssue()
660         self.db.config.MAILGW_SUBJECT_CONTENT_MATCH = 'never'
661         self.assertNotEqual(self._handle_mail('''Content-Type: text/plain;
662   charset="iso-8859-1"
663 From: richard <richard@test.test>
664 To: issue_tracker@your.tracker.email.domain.example
665 Message-Id: <followup_dummy_id>
666 Subject: Re: Testing...
668 This is a followup
669 '''), nodeid)
671     def testFollowupTitleMatchNeverInterval(self):
672         nodeid = self.doNewIssue()
673         # force failure of the interval
674         time.sleep(2)
675         self.db.config.MAILGW_SUBJECT_CONTENT_MATCH = 'creation 00:00:01'
676         self.assertNotEqual(self._handle_mail('''Content-Type: text/plain;
677   charset="iso-8859-1"
678 From: richard <richard@test.test>
679 To: issue_tracker@your.tracker.email.domain.example
680 Message-Id: <followup_dummy_id>
681 Subject: Re: Testing...
683 This is a followup
684 '''), nodeid)
687     def testFollowupTitleMatchInterval(self):
688         nodeid = self.doNewIssue()
689         self.db.config.MAILGW_SUBJECT_CONTENT_MATCH = 'creation +1d'
690         self.assertEqual(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 testFollowupNosyAuthor(self):
702         self.doNewIssue()
703         self.db.config.ADD_AUTHOR_TO_NOSY = 'yes'
704         self._handle_mail('''Content-Type: text/plain;
705   charset="iso-8859-1"
706 From: john@test.test
707 To: issue_tracker@your.tracker.email.domain.example
708 Message-Id: <followup_dummy_id>
709 In-Reply-To: <dummy_test_message_id>
710 Subject: [issue1] Testing...
712 This is a followup
713 ''')
715         self.compareMessages(self._get_mail(),
716 '''FROM: roundup-admin@your.tracker.email.domain.example
717 TO: chef@bork.bork.bork, richard@test.test
718 Content-Type: text/plain; charset=utf-8
719 Subject: [issue1] Testing...
720 To: chef@bork.bork.bork, richard@test.test
721 From: John Doe <issue_tracker@your.tracker.email.domain.example>
722 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
723 MIME-Version: 1.0
724 Message-Id: <followup_dummy_id>
725 In-Reply-To: <dummy_test_message_id>
726 X-Roundup-Name: Roundup issue tracker
727 X-Roundup-Loop: hello
728 X-Roundup-Issue-Status: chatting
729 Content-Transfer-Encoding: quoted-printable
732 John Doe <john@test.test> added the comment:
734 This is a followup
736 ----------
737 nosy: +john
738 status: unread -> chatting
740 _______________________________________________________________________
741 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
742 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
743 _______________________________________________________________________
745 ''')
747     def testFollowupNosyRecipients(self):
748         self.doNewIssue()
749         self.db.config.ADD_RECIPIENTS_TO_NOSY = 'yes'
750         self._handle_mail('''Content-Type: text/plain;
751   charset="iso-8859-1"
752 From: richard@test.test
753 To: issue_tracker@your.tracker.email.domain.example
754 Cc: john@test.test
755 Message-Id: <followup_dummy_id>
756 In-Reply-To: <dummy_test_message_id>
757 Subject: [issue1] Testing...
759 This is a followup
760 ''')
761         self.compareMessages(self._get_mail(),
762 '''FROM: roundup-admin@your.tracker.email.domain.example
763 TO: chef@bork.bork.bork
764 Content-Type: text/plain; charset=utf-8
765 Subject: [issue1] Testing...
766 To: chef@bork.bork.bork
767 From: richard <issue_tracker@your.tracker.email.domain.example>
768 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
769 MIME-Version: 1.0
770 Message-Id: <followup_dummy_id>
771 In-Reply-To: <dummy_test_message_id>
772 X-Roundup-Name: Roundup issue tracker
773 X-Roundup-Loop: hello
774 X-Roundup-Issue-Status: chatting
775 Content-Transfer-Encoding: quoted-printable
778 richard <richard@test.test> added the comment:
780 This is a followup
782 ----------
783 nosy: +john
784 status: unread -> chatting
786 _______________________________________________________________________
787 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
788 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
789 _______________________________________________________________________
791 ''')
793     def testFollowupNosyAuthorAndCopy(self):
794         self.doNewIssue()
795         self.db.config.ADD_AUTHOR_TO_NOSY = 'yes'
796         self.db.config.MESSAGES_TO_AUTHOR = 'yes'
797         self._handle_mail('''Content-Type: text/plain;
798   charset="iso-8859-1"
799 From: john@test.test
800 To: issue_tracker@your.tracker.email.domain.example
801 Message-Id: <followup_dummy_id>
802 In-Reply-To: <dummy_test_message_id>
803 Subject: [issue1] Testing...
805 This is a followup
806 ''')
807         self.compareMessages(self._get_mail(),
808 '''FROM: roundup-admin@your.tracker.email.domain.example
809 TO: chef@bork.bork.bork, john@test.test, richard@test.test
810 Content-Type: text/plain; charset=utf-8
811 Subject: [issue1] Testing...
812 To: chef@bork.bork.bork, john@test.test, richard@test.test
813 From: John Doe <issue_tracker@your.tracker.email.domain.example>
814 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
815 MIME-Version: 1.0
816 Message-Id: <followup_dummy_id>
817 In-Reply-To: <dummy_test_message_id>
818 X-Roundup-Name: Roundup issue tracker
819 X-Roundup-Loop: hello
820 X-Roundup-Issue-Status: chatting
821 Content-Transfer-Encoding: quoted-printable
824 John Doe <john@test.test> added the comment:
826 This is a followup
828 ----------
829 nosy: +john
830 status: unread -> chatting
832 _______________________________________________________________________
833 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
834 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
835 _______________________________________________________________________
837 ''')
839     def testFollowupNoNosyAuthor(self):
840         self.doNewIssue()
841         self.instance.config.ADD_AUTHOR_TO_NOSY = 'no'
842         self._handle_mail('''Content-Type: text/plain;
843   charset="iso-8859-1"
844 From: john@test.test
845 To: issue_tracker@your.tracker.email.domain.example
846 Message-Id: <followup_dummy_id>
847 In-Reply-To: <dummy_test_message_id>
848 Subject: [issue1] Testing...
850 This is a followup
851 ''')
852         self.compareMessages(self._get_mail(),
853 '''FROM: roundup-admin@your.tracker.email.domain.example
854 TO: chef@bork.bork.bork, richard@test.test
855 Content-Type: text/plain; charset=utf-8
856 Subject: [issue1] Testing...
857 To: chef@bork.bork.bork, richard@test.test
858 From: John Doe <issue_tracker@your.tracker.email.domain.example>
859 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
860 MIME-Version: 1.0
861 Message-Id: <followup_dummy_id>
862 In-Reply-To: <dummy_test_message_id>
863 X-Roundup-Name: Roundup issue tracker
864 X-Roundup-Loop: hello
865 X-Roundup-Issue-Status: chatting
866 Content-Transfer-Encoding: quoted-printable
869 John Doe <john@test.test> added the comment:
871 This is a followup
873 ----------
874 status: unread -> chatting
876 _______________________________________________________________________
877 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
878 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
879 _______________________________________________________________________
881 ''')
883     def testFollowupNoNosyRecipients(self):
884         self.doNewIssue()
885         self.instance.config.ADD_RECIPIENTS_TO_NOSY = 'no'
886         self._handle_mail('''Content-Type: text/plain;
887   charset="iso-8859-1"
888 From: richard@test.test
889 To: issue_tracker@your.tracker.email.domain.example
890 Cc: john@test.test
891 Message-Id: <followup_dummy_id>
892 In-Reply-To: <dummy_test_message_id>
893 Subject: [issue1] Testing...
895 This is a followup
896 ''')
897         self.compareMessages(self._get_mail(),
898 '''FROM: roundup-admin@your.tracker.email.domain.example
899 TO: chef@bork.bork.bork
900 Content-Type: text/plain; charset=utf-8
901 Subject: [issue1] Testing...
902 To: chef@bork.bork.bork
903 From: richard <issue_tracker@your.tracker.email.domain.example>
904 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
905 MIME-Version: 1.0
906 Message-Id: <followup_dummy_id>
907 In-Reply-To: <dummy_test_message_id>
908 X-Roundup-Name: Roundup issue tracker
909 X-Roundup-Loop: hello
910 X-Roundup-Issue-Status: chatting
911 Content-Transfer-Encoding: quoted-printable
914 richard <richard@test.test> added the comment:
916 This is a followup
918 ----------
919 status: unread -> chatting
921 _______________________________________________________________________
922 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
923 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
924 _______________________________________________________________________
926 ''')
928     def testFollowupEmptyMessage(self):
929         self.doNewIssue()
931         self._handle_mail('''Content-Type: text/plain;
932   charset="iso-8859-1"
933 From: richard <richard@test.test>
934 To: issue_tracker@your.tracker.email.domain.example
935 Message-Id: <followup_dummy_id>
936 In-Reply-To: <dummy_test_message_id>
937 Subject: [issue1] Testing... [assignedto=mary; nosy=+john]
939 ''')
940         l = self.db.issue.get('1', 'nosy')
941         l.sort()
942         self.assertEqual(l, [self.chef_id, self.richard_id, self.mary_id,
943             self.john_id])
945         # should be no file created (ie. no message)
946         assert not os.path.exists(SENDMAILDEBUG)
948     def testFollowupEmptyMessageNoSubject(self):
949         self.doNewIssue()
951         self._handle_mail('''Content-Type: text/plain;
952   charset="iso-8859-1"
953 From: richard <richard@test.test>
954 To: issue_tracker@your.tracker.email.domain.example
955 Message-Id: <followup_dummy_id>
956 In-Reply-To: <dummy_test_message_id>
957 Subject: [issue1] [assignedto=mary; nosy=+john]
959 ''')
960         l = self.db.issue.get('1', 'nosy')
961         l.sort()
962         self.assertEqual(l, [self.chef_id, self.richard_id, self.mary_id,
963             self.john_id])
965         # should be no file created (ie. no message)
966         assert not os.path.exists(SENDMAILDEBUG)
968     def testNosyRemove(self):
969         self.doNewIssue()
971         self._handle_mail('''Content-Type: text/plain;
972   charset="iso-8859-1"
973 From: richard <richard@test.test>
974 To: issue_tracker@your.tracker.email.domain.example
975 Message-Id: <followup_dummy_id>
976 In-Reply-To: <dummy_test_message_id>
977 Subject: [issue1] Testing... [nosy=-richard]
979 ''')
980         l = self.db.issue.get('1', 'nosy')
981         l.sort()
982         self.assertEqual(l, [self.chef_id])
984         # NO NOSY MESSAGE SHOULD BE SENT!
985         assert not os.path.exists(SENDMAILDEBUG)
987     def testNewUserAuthor(self):
988         # first without the permission
989         # heh... just ignore the API for a second ;)
990         self.db.security.role['anonymous'].permissions=[]
991         anonid = self.db.user.lookup('anonymous')
992         self.db.user.set(anonid, roles='Anonymous')
994         l = self.db.user.list()
995         l.sort()
996         message = '''Content-Type: text/plain;
997   charset="iso-8859-1"
998 From: fubar <fubar@bork.bork.bork>
999 To: issue_tracker@your.tracker.email.domain.example
1000 Message-Id: <dummy_test_message_id>
1001 Subject: [issue] Testing...
1003 This is a test submission of a new issue.
1004 '''
1005         try:
1006             self._handle_mail(message)
1007         except Unauthorized, value:
1008             body_diff = self.compareMessages(str(value), """
1009 You are not a registered user.
1011 Unknown address: fubar@bork.bork.bork
1012 """)
1014             assert not body_diff, body_diff
1016         else:
1017             raise AssertionError, "Unathorized not raised when handling mail"
1019         # Add Web Access role to anonymous, and try again to make sure
1020         # we get a "please register at:" message this time.
1021         p = [
1022             self.db.security.getPermission('Create', 'user'),
1023             self.db.security.getPermission('Web Access', None),
1024         ]
1026         self.db.security.role['anonymous'].permissions=p
1028         try:
1029             self._handle_mail(message)
1030         except Unauthorized, value:
1031             body_diff = self.compareMessages(str(value), """
1032 You are not a registered user. Please register at:
1034 http://tracker.example/cgi-bin/roundup.cgi/bugs/user?template=register
1036 ...before sending mail to the tracker.
1038 Unknown address: fubar@bork.bork.bork
1039 """)
1041             assert not body_diff, body_diff
1043         else:
1044             raise AssertionError, "Unathorized not raised when handling mail"
1046         # Make sure list of users is the same as before.
1047         m = self.db.user.list()
1048         m.sort()
1049         self.assertEqual(l, m)
1051         # now with the permission
1052         p = [
1053             self.db.security.getPermission('Create', 'user'),
1054             self.db.security.getPermission('Email Access', None),
1055         ]
1056         self.db.security.role['anonymous'].permissions=p
1057         self._handle_mail(message)
1058         m = self.db.user.list()
1059         m.sort()
1060         self.assertNotEqual(l, m)
1062     def testEnc01(self):
1063         self.doNewIssue()
1064         self._handle_mail('''Content-Type: text/plain;
1065   charset="iso-8859-1"
1066 From: mary <mary@test.test>
1067 To: issue_tracker@your.tracker.email.domain.example
1068 Message-Id: <followup_dummy_id>
1069 In-Reply-To: <dummy_test_message_id>
1070 Subject: [issue1] Testing...
1071 Content-Type: text/plain;
1072         charset="iso-8859-1"
1073 Content-Transfer-Encoding: quoted-printable
1075 A message with encoding (encoded oe =F6)
1077 ''')
1078         self.compareMessages(self._get_mail(),
1079 '''FROM: roundup-admin@your.tracker.email.domain.example
1080 TO: chef@bork.bork.bork, richard@test.test
1081 Content-Type: text/plain; charset=utf-8
1082 Subject: [issue1] Testing...
1083 To: chef@bork.bork.bork, richard@test.test
1084 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
1085 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1086 MIME-Version: 1.0
1087 Message-Id: <followup_dummy_id>
1088 In-Reply-To: <dummy_test_message_id>
1089 X-Roundup-Name: Roundup issue tracker
1090 X-Roundup-Loop: hello
1091 X-Roundup-Issue-Status: chatting
1092 Content-Transfer-Encoding: quoted-printable
1095 Contrary, Mary <mary@test.test> added the comment:
1097 A message with encoding (encoded oe =C3=B6)
1099 ----------
1100 status: unread -> chatting
1102 _______________________________________________________________________
1103 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1104 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1105 _______________________________________________________________________
1106 ''')
1109     def testMultipartEnc01(self):
1110         self.doNewIssue()
1111         self._handle_mail('''Content-Type: text/plain;
1112   charset="iso-8859-1"
1113 From: mary <mary@test.test>
1114 To: issue_tracker@your.tracker.email.domain.example
1115 Message-Id: <followup_dummy_id>
1116 In-Reply-To: <dummy_test_message_id>
1117 Subject: [issue1] Testing...
1118 Content-Type: multipart/mixed;
1119         boundary="----_=_NextPart_000_01"
1121 This message is in MIME format. Since your mail reader does not understand
1122 this format, some or all of this message may not be legible.
1124 ------_=_NextPart_000_01
1125 Content-Type: text/plain;
1126         charset="iso-8859-1"
1127 Content-Transfer-Encoding: quoted-printable
1129 A message with first part encoded (encoded oe =F6)
1131 ''')
1132         self.compareMessages(self._get_mail(),
1133 '''FROM: roundup-admin@your.tracker.email.domain.example
1134 TO: chef@bork.bork.bork, richard@test.test
1135 Content-Type: text/plain; charset=utf-8
1136 Subject: [issue1] Testing...
1137 To: chef@bork.bork.bork, richard@test.test
1138 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
1139 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1140 MIME-Version: 1.0
1141 Message-Id: <followup_dummy_id>
1142 In-Reply-To: <dummy_test_message_id>
1143 X-Roundup-Name: Roundup issue tracker
1144 X-Roundup-Loop: hello
1145 X-Roundup-Issue-Status: chatting
1146 Content-Transfer-Encoding: quoted-printable
1149 Contrary, Mary <mary@test.test> added the comment:
1151 A message with first part encoded (encoded oe =C3=B6)
1153 ----------
1154 status: unread -> chatting
1156 _______________________________________________________________________
1157 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1158 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1159 _______________________________________________________________________
1160 ''')
1162     def testContentDisposition(self):
1163         self.doNewIssue()
1164         self._handle_mail('''Content-Type: text/plain;
1165   charset="iso-8859-1"
1166 From: mary <mary@test.test>
1167 To: issue_tracker@your.tracker.email.domain.example
1168 Message-Id: <followup_dummy_id>
1169 In-Reply-To: <dummy_test_message_id>
1170 Subject: [issue1] Testing...
1171 Content-Type: multipart/mixed; boundary="bCsyhTFzCvuiizWE"
1172 Content-Disposition: inline
1175 --bCsyhTFzCvuiizWE
1176 Content-Type: text/plain; charset=us-ascii
1177 Content-Disposition: inline
1179 test attachment binary
1181 --bCsyhTFzCvuiizWE
1182 Content-Type: application/octet-stream
1183 Content-Disposition: attachment; filename="main.dvi"
1184 Content-Transfer-Encoding: base64
1186 SnVzdCBhIHRlc3QgAQo=
1188 --bCsyhTFzCvuiizWE--
1189 ''')
1190         messages = self.db.issue.get('1', 'messages')
1191         messages.sort()
1192         file = self.db.file.getnode (self.db.msg.get(messages[-1], 'files')[0])
1193         self.assertEqual(file.name, 'main.dvi')
1194         self.assertEqual(file.content, 'Just a test \001\n')
1196     def testFollowupStupidQuoting(self):
1197         self.doNewIssue()
1199         self._handle_mail('''Content-Type: text/plain;
1200   charset="iso-8859-1"
1201 From: richard <richard@test.test>
1202 To: issue_tracker@your.tracker.email.domain.example
1203 Message-Id: <followup_dummy_id>
1204 In-Reply-To: <dummy_test_message_id>
1205 Subject: Re: "[issue1] Testing... "
1207 This is a followup
1208 ''')
1209         self.compareMessages(self._get_mail(),
1210 '''FROM: roundup-admin@your.tracker.email.domain.example
1211 TO: chef@bork.bork.bork
1212 Content-Type: text/plain; charset=utf-8
1213 Subject: [issue1] Testing...
1214 To: chef@bork.bork.bork
1215 From: richard <issue_tracker@your.tracker.email.domain.example>
1216 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1217 MIME-Version: 1.0
1218 Message-Id: <followup_dummy_id>
1219 In-Reply-To: <dummy_test_message_id>
1220 X-Roundup-Name: Roundup issue tracker
1221 X-Roundup-Loop: hello
1222 X-Roundup-Issue-Status: chatting
1223 Content-Transfer-Encoding: quoted-printable
1226 richard <richard@test.test> added the comment:
1228 This is a followup
1230 ----------
1231 status: unread -> chatting
1233 _______________________________________________________________________
1234 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1235 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1236 _______________________________________________________________________
1237 ''')
1239     def testEmailQuoting(self):
1240         self.instance.config.EMAIL_KEEP_QUOTED_TEXT = 'no'
1241         self.innerTestQuoting('''This is a followup
1242 ''')
1244     def testEmailQuotingRemove(self):
1245         self.instance.config.EMAIL_KEEP_QUOTED_TEXT = 'yes'
1246         self.innerTestQuoting('''Blah blah wrote:
1247 > Blah bklaskdfj sdf asdf jlaskdf skj sdkfjl asdf
1248 >  skdjlkjsdfalsdkfjasdlfkj dlfksdfalksd fj
1251 This is a followup
1252 ''')
1254     def innerTestQuoting(self, expect):
1255         nodeid = self.doNewIssue()
1257         messages = self.db.issue.get(nodeid, 'messages')
1259         self._handle_mail('''Content-Type: text/plain;
1260   charset="iso-8859-1"
1261 From: richard <richard@test.test>
1262 To: issue_tracker@your.tracker.email.domain.example
1263 Message-Id: <followup_dummy_id>
1264 In-Reply-To: <dummy_test_message_id>
1265 Subject: Re: [issue1] Testing...
1267 Blah blah wrote:
1268 > Blah bklaskdfj sdf asdf jlaskdf skj sdkfjl asdf
1269 >  skdjlkjsdfalsdkfjasdlfkj dlfksdfalksd fj
1272 This is a followup
1273 ''')
1274         # figure the new message id
1275         newmessages = self.db.issue.get(nodeid, 'messages')
1276         for msg in messages:
1277             newmessages.remove(msg)
1278         messageid = newmessages[0]
1280         self.compareMessages(self.db.msg.get(messageid, 'content'), expect)
1282     def testUserLookup(self):
1283         i = self.db.user.create(username='user1', address='user1@foo.com')
1284         self.assertEqual(uidFromAddress(self.db, ('', 'user1@foo.com'), 0), i)
1285         self.assertEqual(uidFromAddress(self.db, ('', 'USER1@foo.com'), 0), i)
1286         i = self.db.user.create(username='user2', address='USER2@foo.com')
1287         self.assertEqual(uidFromAddress(self.db, ('', 'USER2@foo.com'), 0), i)
1288         self.assertEqual(uidFromAddress(self.db, ('', 'user2@foo.com'), 0), i)
1290     def testUserAlternateLookup(self):
1291         i = self.db.user.create(username='user1', address='user1@foo.com',
1292                                 alternate_addresses='user1@bar.com')
1293         self.assertEqual(uidFromAddress(self.db, ('', 'user1@bar.com'), 0), i)
1294         self.assertEqual(uidFromAddress(self.db, ('', 'USER1@bar.com'), 0), i)
1296     def testUserCreate(self):
1297         i = uidFromAddress(self.db, ('', 'user@foo.com'), 1)
1298         self.assertNotEqual(uidFromAddress(self.db, ('', 'user@bar.com'), 1), i)
1300     def testRFC2822(self):
1301         ascii_header = "[issue243] This is a \"test\" - with 'quotation' marks"
1302         unicode_header = '[issue244] \xd0\xb0\xd0\xbd\xd0\xb4\xd1\x80\xd0\xb5\xd0\xb9'
1303         unicode_encoded = '=?utf-8?q?[issue244]_=D0=B0=D0=BD=D0=B4=D1=80=D0=B5=D0=B9?='
1304         self.assertEqual(rfc2822.encode_header(ascii_header), ascii_header)
1305         self.assertEqual(rfc2822.encode_header(unicode_header), unicode_encoded)
1307     def testRegistrationConfirmation(self):
1308         otk = "Aj4euk4LZSAdwePohj90SME5SpopLETL"
1309         self.db.getOTKManager().set(otk, username='johannes')
1310         self._handle_mail('''Content-Type: text/plain;
1311   charset="iso-8859-1"
1312 From: Chef <chef@bork.bork.bork>
1313 To: issue_tracker@your.tracker.email.domain.example
1314 Cc: richard@test.test
1315 Message-Id: <dummy_test_message_id>
1316 Subject: Re: Complete your registration to Roundup issue tracker
1317  -- key %s
1319 This is a test confirmation of registration.
1320 ''' % otk)
1321         self.db.user.lookup('johannes')
1323     def testFollowupOnNonIssue(self):
1324         self.db.keyword.create(name='Foo')
1325         self._handle_mail('''Content-Type: text/plain;
1326   charset="iso-8859-1"
1327 From: richard <richard@test.test>
1328 To: issue_tracker@your.tracker.email.domain.example
1329 Message-Id: <followup_dummy_id>
1330 In-Reply-To: <dummy_test_message_id>
1331 Subject: [keyword1] Testing... [name=Bar]
1333 ''')
1334         self.assertEqual(self.db.keyword.get('1', 'name'), 'Bar')
1336     def testResentFrom(self):
1337         nodeid = self._handle_mail('''Content-Type: text/plain;
1338   charset="iso-8859-1"
1339 From: Chef <chef@bork.bork.bork>
1340 Resent-From: mary <mary@test.test>
1341 To: issue_tracker@your.tracker.email.domain.example
1342 Cc: richard@test.test
1343 Message-Id: <dummy_test_message_id>
1344 Subject: [issue] Testing...
1346 This is a test submission of a new issue.
1347 ''')
1348         assert not os.path.exists(SENDMAILDEBUG)
1349         l = self.db.issue.get(nodeid, 'nosy')
1350         l.sort()
1351         self.assertEqual(l, [self.richard_id, self.mary_id])
1352         return nodeid
1354     def testDejaVu(self):
1355         self.assertRaises(IgnoreLoop, self._handle_mail,
1356             '''Content-Type: text/plain;
1357   charset="iso-8859-1"
1358 From: Chef <chef@bork.bork.bork>
1359 X-Roundup-Loop: hello
1360 To: issue_tracker@your.tracker.email.domain.example
1361 Cc: richard@test.test
1362 Message-Id: <dummy_test_message_id>
1363 Subject: Re: [issue] Testing...
1365 Hi, I've been mis-configured to loop messages back to myself.
1366 ''')
1368     def testItsBulkStupid(self):
1369         self.assertRaises(IgnoreBulk, self._handle_mail,
1370             '''Content-Type: text/plain;
1371   charset="iso-8859-1"
1372 From: Chef <chef@bork.bork.bork>
1373 Precedence: bulk
1374 To: issue_tracker@your.tracker.email.domain.example
1375 Cc: richard@test.test
1376 Message-Id: <dummy_test_message_id>
1377 Subject: Re: [issue] Testing...
1379 Hi, I'm on holidays, and this is a dumb auto-responder.
1380 ''')
1382     def testAutoReplyEmailsAreIgnored(self):
1383         self.assertRaises(IgnoreBulk, self._handle_mail,
1384             '''Content-Type: text/plain;
1385   charset="iso-8859-1"
1386 From: Chef <chef@bork.bork.bork>
1387 To: issue_tracker@your.tracker.email.domain.example
1388 Cc: richard@test.test
1389 Message-Id: <dummy_test_message_id>
1390 Subject: Re: [issue] Out of office AutoReply: Back next week
1392 Hi, I am back in the office next week
1393 ''')
1395     def testNoSubject(self):
1396         self.assertRaises(MailUsageError, self._handle_mail,
1397             '''Content-Type: text/plain;
1398   charset="iso-8859-1"
1399 From: Chef <chef@bork.bork.bork>
1400 To: issue_tracker@your.tracker.email.domain.example
1401 Cc: richard@test.test
1402 Reply-To: chef@bork.bork.bork
1403 Message-Id: <dummy_test_message_id>
1405 ''')
1407     #
1408     # TEST FOR INVALID DESIGNATOR HANDLING
1409     #
1410     def testInvalidDesignator(self):
1411         self.assertRaises(MailUsageError, self._handle_mail,
1412             '''Content-Type: text/plain;
1413   charset="iso-8859-1"
1414 From: Chef <chef@bork.bork.bork>
1415 To: issue_tracker@your.tracker.email.domain.example
1416 Subject: [frobulated] testing
1417 Cc: richard@test.test
1418 Reply-To: chef@bork.bork.bork
1419 Message-Id: <dummy_test_message_id>
1421 ''')
1422         self.assertRaises(MailUsageError, self._handle_mail,
1423             '''Content-Type: text/plain;
1424   charset="iso-8859-1"
1425 From: Chef <chef@bork.bork.bork>
1426 To: issue_tracker@your.tracker.email.domain.example
1427 Subject: [issue12345] testing
1428 Cc: richard@test.test
1429 Reply-To: chef@bork.bork.bork
1430 Message-Id: <dummy_test_message_id>
1432 ''')
1434     def testInvalidClassLoose(self):
1435         self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'loose'
1436         nodeid = self._handle_mail('''Content-Type: text/plain;
1437   charset="iso-8859-1"
1438 From: Chef <chef@bork.bork.bork>
1439 To: issue_tracker@your.tracker.email.domain.example
1440 Subject: [frobulated] testing
1441 Cc: richard@test.test
1442 Reply-To: chef@bork.bork.bork
1443 Message-Id: <dummy_test_message_id>
1445 ''')
1446         assert not os.path.exists(SENDMAILDEBUG)
1447         self.assertEqual(self.db.issue.get(nodeid, 'title'),
1448             '[frobulated] testing')
1450     def testInvalidClassLooseReply(self):
1451         self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'loose'
1452         nodeid = self._handle_mail('''Content-Type: text/plain;
1453   charset="iso-8859-1"
1454 From: Chef <chef@bork.bork.bork>
1455 To: issue_tracker@your.tracker.email.domain.example
1456 Subject: Re: [frobulated] testing
1457 Cc: richard@test.test
1458 Reply-To: chef@bork.bork.bork
1459 Message-Id: <dummy_test_message_id>
1461 ''')
1462         assert not os.path.exists(SENDMAILDEBUG)
1463         self.assertEqual(self.db.issue.get(nodeid, 'title'),
1464             '[frobulated] testing')
1466     def testInvalidClassLoose(self):
1467         self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'loose'
1468         nodeid = self._handle_mail('''Content-Type: text/plain;
1469   charset="iso-8859-1"
1470 From: Chef <chef@bork.bork.bork>
1471 To: issue_tracker@your.tracker.email.domain.example
1472 Subject: [issue1234] testing
1473 Cc: richard@test.test
1474 Reply-To: chef@bork.bork.bork
1475 Message-Id: <dummy_test_message_id>
1477 ''')
1478         assert not os.path.exists(SENDMAILDEBUG)
1479         self.assertEqual(self.db.issue.get(nodeid, 'title'),
1480             '[issue1234] testing')
1482     def testClassLooseOK(self):
1483         self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'loose'
1484         self.db.keyword.create(name='Foo')
1485         nodeid = self._handle_mail('''Content-Type: text/plain;
1486   charset="iso-8859-1"
1487 From: Chef <chef@bork.bork.bork>
1488 To: issue_tracker@your.tracker.email.domain.example
1489 Subject: [keyword1] Testing... [name=Bar]
1490 Cc: richard@test.test
1491 Reply-To: chef@bork.bork.bork
1492 Message-Id: <dummy_test_message_id>
1494 ''')
1495         assert not os.path.exists(SENDMAILDEBUG)
1496         self.assertEqual(self.db.keyword.get('1', 'name'), 'Bar')
1498     def testClassStrictInvalid(self):
1499         self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'strict'
1500         self.instance.config.MAILGW_DEFAULT_CLASS = ''
1502         message = '''Content-Type: text/plain;
1503   charset="iso-8859-1"
1504 From: Chef <chef@bork.bork.bork>
1505 To: issue_tracker@your.tracker.email.domain.example
1506 Subject: Testing...
1507 Cc: richard@test.test
1508 Reply-To: chef@bork.bork.bork
1509 Message-Id: <dummy_test_message_id>
1511 '''
1512         self.assertRaises(MailUsageError, self._handle_mail, message)
1514     def testClassStrictValid(self):
1515         self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'strict'
1516         self.instance.config.MAILGW_DEFAULT_CLASS = ''
1518         nodeid = self._handle_mail('''Content-Type: text/plain;
1519   charset="iso-8859-1"
1520 From: Chef <chef@bork.bork.bork>
1521 To: issue_tracker@your.tracker.email.domain.example
1522 Subject: [issue] Testing...
1523 Cc: richard@test.test
1524 Reply-To: chef@bork.bork.bork
1525 Message-Id: <dummy_test_message_id>
1527 ''')
1529         assert not os.path.exists(SENDMAILDEBUG)
1530         self.assertEqual(self.db.issue.get(nodeid, 'title'), 'Testing...')
1532     #
1533     # TEST FOR INVALID COMMANDS HANDLING
1534     #
1535     def testInvalidCommands(self):
1536         self.assertRaises(MailUsageError, self._handle_mail,
1537             '''Content-Type: text/plain;
1538   charset="iso-8859-1"
1539 From: Chef <chef@bork.bork.bork>
1540 To: issue_tracker@your.tracker.email.domain.example
1541 Subject: testing [frobulated]
1542 Cc: richard@test.test
1543 Reply-To: chef@bork.bork.bork
1544 Message-Id: <dummy_test_message_id>
1546 ''')
1548     def testInvalidCommandPassthrough(self):
1549         self.instance.config.MAILGW_SUBJECT_SUFFIX_PARSING = 'none'
1550         nodeid = self._handle_mail('''Content-Type: text/plain;
1551   charset="iso-8859-1"
1552 From: Chef <chef@bork.bork.bork>
1553 To: issue_tracker@your.tracker.email.domain.example
1554 Subject: testing [frobulated]
1555 Cc: richard@test.test
1556 Reply-To: chef@bork.bork.bork
1557 Message-Id: <dummy_test_message_id>
1559 ''')
1560         assert not os.path.exists(SENDMAILDEBUG)
1561         self.assertEqual(self.db.issue.get(nodeid, 'title'),
1562             'testing [frobulated]')
1564     def testInvalidCommandPassthroughLoose(self):
1565         self.instance.config.MAILGW_SUBJECT_SUFFIX_PARSING = 'loose'
1566         nodeid = self._handle_mail('''Content-Type: text/plain;
1567   charset="iso-8859-1"
1568 From: Chef <chef@bork.bork.bork>
1569 To: issue_tracker@your.tracker.email.domain.example
1570 Subject: testing [frobulated]
1571 Cc: richard@test.test
1572 Reply-To: chef@bork.bork.bork
1573 Message-Id: <dummy_test_message_id>
1575 ''')
1576         assert not os.path.exists(SENDMAILDEBUG)
1577         self.assertEqual(self.db.issue.get(nodeid, 'title'),
1578             'testing [frobulated]')
1580     def testInvalidCommandPassthroughLooseOK(self):
1581         self.instance.config.MAILGW_SUBJECT_SUFFIX_PARSING = 'loose'
1582         nodeid = self._handle_mail('''Content-Type: text/plain;
1583   charset="iso-8859-1"
1584 From: Chef <chef@bork.bork.bork>
1585 To: issue_tracker@your.tracker.email.domain.example
1586 Subject: testing [assignedto=mary]
1587 Cc: richard@test.test
1588 Reply-To: chef@bork.bork.bork
1589 Message-Id: <dummy_test_message_id>
1591 ''')
1592         assert not os.path.exists(SENDMAILDEBUG)
1593         self.assertEqual(self.db.issue.get(nodeid, 'title'), 'testing')
1594         self.assertEqual(self.db.issue.get(nodeid, 'assignedto'), self.mary_id)
1596     def testCommandDelimiters(self):
1597         self.instance.config.MAILGW_SUBJECT_SUFFIX_DELIMITERS = '{}'
1598         nodeid = self._handle_mail('''Content-Type: text/plain;
1599   charset="iso-8859-1"
1600 From: Chef <chef@bork.bork.bork>
1601 To: issue_tracker@your.tracker.email.domain.example
1602 Subject: testing {assignedto=mary}
1603 Cc: richard@test.test
1604 Reply-To: chef@bork.bork.bork
1605 Message-Id: <dummy_test_message_id>
1607 ''')
1608         assert not os.path.exists(SENDMAILDEBUG)
1609         self.assertEqual(self.db.issue.get(nodeid, 'title'), 'testing')
1610         self.assertEqual(self.db.issue.get(nodeid, 'assignedto'), self.mary_id)
1612     def testPrefixDelimiters(self):
1613         self.instance.config.MAILGW_SUBJECT_SUFFIX_DELIMITERS = '{}'
1614         self.db.keyword.create(name='Foo')
1615         self._handle_mail('''Content-Type: text/plain;
1616   charset="iso-8859-1"
1617 From: richard <richard@test.test>
1618 To: issue_tracker@your.tracker.email.domain.example
1619 Message-Id: <followup_dummy_id>
1620 In-Reply-To: <dummy_test_message_id>
1621 Subject: {keyword1} Testing... {name=Bar}
1623 ''')
1624         assert not os.path.exists(SENDMAILDEBUG)
1625         self.assertEqual(self.db.keyword.get('1', 'name'), 'Bar')
1627     def testCommandDelimitersIgnore(self):
1628         self.instance.config.MAILGW_SUBJECT_SUFFIX_DELIMITERS = '{}'
1629         nodeid = self._handle_mail('''Content-Type: text/plain;
1630   charset="iso-8859-1"
1631 From: Chef <chef@bork.bork.bork>
1632 To: issue_tracker@your.tracker.email.domain.example
1633 Subject: testing [assignedto=mary]
1634 Cc: richard@test.test
1635 Reply-To: chef@bork.bork.bork
1636 Message-Id: <dummy_test_message_id>
1638 ''')
1639         assert not os.path.exists(SENDMAILDEBUG)
1640         self.assertEqual(self.db.issue.get(nodeid, 'title'),
1641             'testing [assignedto=mary]')
1642         self.assertEqual(self.db.issue.get(nodeid, 'assignedto'), None)
1644     def testReplytoMatch(self):
1645         self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'loose'
1646         nodeid = self.doNewIssue()
1647         nodeid2 = self._handle_mail('''Content-Type: text/plain;
1648   charset="iso-8859-1"
1649 From: Chef <chef@bork.bork.bork>
1650 To: issue_tracker@your.tracker.email.domain.example
1651 Message-Id: <dummy_test_message_id2>
1652 In-Reply-To: <dummy_test_message_id>
1653 Subject: Testing...
1655 Followup message.
1656 ''')
1658         nodeid3 = self._handle_mail('''Content-Type: text/plain;
1659   charset="iso-8859-1"
1660 From: Chef <chef@bork.bork.bork>
1661 To: issue_tracker@your.tracker.email.domain.example
1662 Message-Id: <dummy_test_message_id3>
1663 In-Reply-To: <dummy_test_message_id2>
1664 Subject: Testing...
1666 Yet another message in the same thread/issue.
1667 ''')
1669         self.assertEqual(nodeid, nodeid2)
1670         self.assertEqual(nodeid, nodeid3)
1672     def testHelpSubject(self):
1673         message = '''Content-Type: text/plain;
1674   charset="iso-8859-1"
1675 From: Chef <chef@bork.bork.bork>
1676 To: issue_tracker@your.tracker.email.domain.example
1677 Message-Id: <dummy_test_message_id2>
1678 In-Reply-To: <dummy_test_message_id>
1679 Subject: hElp
1682 '''
1683         self.assertRaises(MailUsageHelp, self._handle_mail, message)
1685     def testMaillistSubject(self):
1686         self.instance.config.MAILGW_SUBJECT_SUFFIX_DELIMITERS = '[]'
1687         self.db.keyword.create(name='Foo')
1688         self._handle_mail('''Content-Type: text/plain;
1689   charset="iso-8859-1"
1690 From: Chef <chef@bork.bork.bork>
1691 To: issue_tracker@your.tracker.email.domain.example
1692 Subject: [mailinglist-name] [keyword1] Testing.. [name=Bar]
1693 Cc: richard@test.test
1694 Reply-To: chef@bork.bork.bork
1695 Message-Id: <dummy_test_message_id>
1697 ''')
1699         assert not os.path.exists(SENDMAILDEBUG)
1700         self.assertEqual(self.db.keyword.get('1', 'name'), 'Bar')
1702     def testUnknownPrefixSubject(self):
1703         self.db.keyword.create(name='Foo')
1704         self._handle_mail('''Content-Type: text/plain;
1705   charset="iso-8859-1"
1706 From: Chef <chef@bork.bork.bork>
1707 To: issue_tracker@your.tracker.email.domain.example
1708 Subject: VeryStrangeRe: [keyword1] Testing.. [name=Bar]
1709 Cc: richard@test.test
1710 Reply-To: chef@bork.bork.bork
1711 Message-Id: <dummy_test_message_id>
1713 ''')
1715         assert not os.path.exists(SENDMAILDEBUG)
1716         self.assertEqual(self.db.keyword.get('1', 'name'), 'Bar')
1718     def testIssueidLast(self):
1719         nodeid1 = self.doNewIssue()
1720         nodeid2 = self._handle_mail('''Content-Type: text/plain;
1721   charset="iso-8859-1"
1722 From: mary <mary@test.test>
1723 To: issue_tracker@your.tracker.email.domain.example
1724 Message-Id: <followup_dummy_id>
1725 In-Reply-To: <dummy_test_message_id>
1726 Subject: New title [issue1]
1728 This is a second followup
1729 ''')
1731         assert nodeid1 == nodeid2
1732         self.assertEqual(self.db.issue.get(nodeid2, 'title'), "Testing...")
1735 def test_suite():
1736     suite = unittest.TestSuite()
1737     suite.addTest(unittest.makeSuite(MailgwTestCase))
1738     return suite
1740 if __name__ == '__main__':
1741     runner = unittest.TextTestRunner()
1742     unittest.main(testRunner=runner)
1744 # vim: set filetype=python sts=4 sw=4 et si :