Code

251b47cde591f84dbf720ffbf94d4ad2dd305be5
[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             replace = {}
55             for key in new.keys():
56                 if key.startswith('from '):
57                     # skip the unix from line
58                     continue
59                 if key.lower() == 'x-roundup-version':
60                     # version changes constantly, so handle it specially
61                     if new[key] != __version__:
62                         res.append('  %s: %r != %r' % (key, __version__,
63                             new[key]))
64                 elif key.lower() == 'content-type' and 'boundary=' in new[key]:
65                     # handle mime messages
66                     newmime = new[key].split('=',1)[-1].strip('"')
67                     oldmime = old.get(key, '').split('=',1)[-1].strip('"')
68                     replace ['--' + newmime] = '--' + oldmime
69                     replace ['--' + newmime + '--'] = '--' + oldmime + '--'
70                 elif new.get(key, '') != old.get(key, ''):
71                     res.append('  %s: %r != %r' % (key, old.get(key, ''),
72                         new.get(key, '')))
74             body_diff = self.compareStrings(new.fp.read(), old.fp.read(),
75                 replace=replace)
76             if body_diff:
77                 res.append('')
78                 res.extend(body_diff)
80             if res:
81                 res.insert(0, 'Generated message not correct (diff follows):')
82                 raise AssertionError, '\n'.join(res)
84     def compareStrings(self, s2, s1, replace={}):
85         '''Note the reversal of s2 and s1 - difflib.SequenceMatcher wants
86            the first to be the "original" but in the calls in this file,
87            the second arg is the original. Ho hum.
88            Do replacements over the replace dict -- used for mime boundary
89         '''
90         l1 = s1.strip().split('\n')
91         l2 = [replace.get(i,i) for i in s2.strip().split('\n')]
92         if l1 == l2:
93             return
94         s = difflib.SequenceMatcher(None, l1, l2)
95         res = []
96         for value, s1s, s1e, s2s, s2e in s.get_opcodes():
97             if value == 'equal':
98                 for i in range(s1s, s1e):
99                     res.append('  %s'%l1[i])
100             elif value == 'delete':
101                 for i in range(s1s, s1e):
102                     res.append('- %s'%l1[i])
103             elif value == 'insert':
104                 for i in range(s2s, s2e):
105                     res.append('+ %s'%l2[i])
106             elif value == 'replace':
107                 for i, j in zip(range(s1s, s1e), range(s2s, s2e)):
108                     res.append('- %s'%l1[i])
109                     res.append('+ %s'%l2[j])
111         return res
113 class MailgwTestCase(unittest.TestCase, DiffHelper):
114     count = 0
115     schema = 'classic'
116     def setUp(self):
117         MailgwTestCase.count = MailgwTestCase.count + 1
118         self.dirname = '_test_mailgw_%s'%self.count
119         # set up and open a tracker
120         self.instance = db_test_base.setupTracker(self.dirname)
122         # and open the database
123         self.db = self.instance.open('admin')
124         self.chef_id = self.db.user.create(username='Chef',
125             address='chef@bork.bork.bork', realname='Bork, Chef', roles='User')
126         self.richard_id = self.db.user.create(username='richard',
127             address='richard@test.test', roles='User')
128         self.mary_id = self.db.user.create(username='mary',
129             address='mary@test.test', roles='User', realname='Contrary, Mary')
130         self.john_id = self.db.user.create(username='john',
131             address='john@test.test', roles='User', realname='John Doe',
132             alternate_addresses='jondoe@test.test\njohn.doe@test.test')
134     def tearDown(self):
135         if os.path.exists(SENDMAILDEBUG):
136             os.remove(SENDMAILDEBUG)
137         self.db.close()
138         try:
139             shutil.rmtree(self.dirname)
140         except OSError, error:
141             if error.errno not in (errno.ENOENT, errno.ESRCH): raise
143     def _handle_mail(self, message):
144         # handler will open a new db handle. On single-threaded
145         # databases we'll have to close our current connection
146         self.db.commit()
147         self.db.close()
148         handler = self.instance.MailGW(self.instance)
149         handler.trapExceptions = 0
150         ret = handler.main(StringIO(message))
151         # handler had its own database, open new connection
152         self.db = self.instance.open('admin')
153         return ret
155     def _get_mail(self):
156         f = open(SENDMAILDEBUG)
157         try:
158             return f.read()
159         finally:
160             f.close()
162     def testEmptyMessage(self):
163         nodeid = self._handle_mail('''Content-Type: text/plain;
164   charset="iso-8859-1"
165 From: Chef <chef@bork.bork.bork>
166 To: issue_tracker@your.tracker.email.domain.example
167 Cc: richard@test.test
168 Reply-To: chef@bork.bork.bork
169 Message-Id: <dummy_test_message_id>
170 Subject: [issue] Testing...
172 ''')
173         assert not os.path.exists(SENDMAILDEBUG)
174         self.assertEqual(self.db.issue.get(nodeid, 'title'), 'Testing...')
176     def doNewIssue(self):
177         nodeid = self._handle_mail('''Content-Type: text/plain;
178   charset="iso-8859-1"
179 From: Chef <chef@bork.bork.bork>
180 To: issue_tracker@your.tracker.email.domain.example
181 Cc: richard@test.test
182 Message-Id: <dummy_test_message_id>
183 Subject: [issue] Testing...
185 This is a test submission of a new issue.
186 ''')
187         assert not os.path.exists(SENDMAILDEBUG)
188         l = self.db.issue.get(nodeid, 'nosy')
189         l.sort()
190         self.assertEqual(l, [self.chef_id, self.richard_id])
191         return nodeid
193     def testNewIssue(self):
194         self.doNewIssue()
196     def testNewIssueNosy(self):
197         self.instance.config.ADD_AUTHOR_TO_NOSY = 'yes'
198         nodeid = self._handle_mail('''Content-Type: text/plain;
199   charset="iso-8859-1"
200 From: Chef <chef@bork.bork.bork>
201 To: issue_tracker@your.tracker.email.domain.example
202 Cc: richard@test.test
203 Message-Id: <dummy_test_message_id>
204 Subject: [issue] Testing...
206 This is a test submission of a new issue.
207 ''')
208         assert not os.path.exists(SENDMAILDEBUG)
209         l = self.db.issue.get(nodeid, 'nosy')
210         l.sort()
211         self.assertEqual(l, [self.chef_id, self.richard_id])
213     def testAlternateAddress(self):
214         self._handle_mail('''Content-Type: text/plain;
215   charset="iso-8859-1"
216 From: John Doe <john.doe@test.test>
217 To: issue_tracker@your.tracker.email.domain.example
218 Message-Id: <dummy_test_message_id>
219 Subject: [issue] Testing...
221 This is a test submission of a new issue.
222 ''')
223         userlist = self.db.user.list()
224         assert not os.path.exists(SENDMAILDEBUG)
225         self.assertEqual(userlist, self.db.user.list(),
226             "user created when it shouldn't have been")
228     def testNewIssueNoClass(self):
229         self._handle_mail('''Content-Type: text/plain;
230   charset="iso-8859-1"
231 From: Chef <chef@bork.bork.bork>
232 To: issue_tracker@your.tracker.email.domain.example
233 Cc: richard@test.test
234 Message-Id: <dummy_test_message_id>
235 Subject: Testing...
237 This is a test submission of a new issue.
238 ''')
239         assert not os.path.exists(SENDMAILDEBUG)
241     def testNewIssueAuthMsg(self):
242         # TODO: fix the damn config - this is apalling
243         self.db.config.MESSAGES_TO_AUTHOR = 'yes'
244         self._handle_mail('''Content-Type: text/plain;
245   charset="iso-8859-1"
246 From: Chef <chef@bork.bork.bork>
247 To: issue_tracker@your.tracker.email.domain.example
248 Message-Id: <dummy_test_message_id>
249 Subject: [issue] Testing... [nosy=mary; assignedto=richard]
251 This is a test submission of a new issue.
252 ''')
253         self.compareMessages(self._get_mail(),
254 '''FROM: roundup-admin@your.tracker.email.domain.example
255 TO: chef@bork.bork.bork, mary@test.test, richard@test.test
256 Content-Type: text/plain; charset="utf-8"
257 Subject: [issue1] Testing...
258 To: chef@bork.bork.bork, mary@test.test, richard@test.test
259 From: "Bork, Chef" <issue_tracker@your.tracker.email.domain.example>
260 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
261 MIME-Version: 1.0
262 Message-Id: <dummy_test_message_id>
263 X-Roundup-Name: Roundup issue tracker
264 X-Roundup-Loop: hello
265 X-Roundup-Issue-Status: unread
266 Content-Transfer-Encoding: quoted-printable
269 New submission from Bork, Chef <chef@bork.bork.bork>:
271 This is a test submission of a new issue.
273 ----------
274 assignedto: richard
275 messages: 1
276 nosy: Chef, mary, richard
277 status: unread
278 title: Testing...
280 _______________________________________________________________________
281 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
282 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
283 _______________________________________________________________________
284 ''')
286     def testNewIssueNoAuthorInfo(self):
287         self.db.config.MAIL_ADD_AUTHORINFO = 'no'
288         self._handle_mail('''Content-Type: text/plain;
289   charset="iso-8859-1"
290 From: Chef <chef@bork.bork.bork>
291 To: issue_tracker@your.tracker.email.domain.example
292 Message-Id: <dummy_test_message_id>
293 Subject: [issue] Testing... [nosy=mary; assignedto=richard]
295 This is a test submission of a new issue.
296 ''')
297         self.compareMessages(self._get_mail(),
298 '''FROM: roundup-admin@your.tracker.email.domain.example
299 TO: chef@bork.bork.bork, mary@test.test, richard@test.test
300 Content-Type: text/plain; charset="utf-8"
301 Subject: [issue1] Testing...
302 To: mary@test.test, richard@test.test
303 From: "Bork, Chef" <issue_tracker@your.tracker.email.domain.example>
304 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
305 MIME-Version: 1.0
306 Message-Id: <dummy_test_message_id>
307 X-Roundup-Name: Roundup issue tracker
308 X-Roundup-Loop: hello
309 X-Roundup-Issue-Status: unread
310 Content-Transfer-Encoding: quoted-printable
312 This is a test submission of a new issue.
314 ----------
315 assignedto: richard
316 messages: 1
317 nosy: Chef, mary, richard
318 status: unread
319 title: Testing...
321 _______________________________________________________________________
322 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
323 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
324 _______________________________________________________________________
325 ''')
327     def testNewIssueNoAuthorEmail(self):
328         self.db.config.MAIL_ADD_AUTHOREMAIL = 'no'
329         self._handle_mail('''Content-Type: text/plain;
330   charset="iso-8859-1"
331 From: Chef <chef@bork.bork.bork>
332 To: issue_tracker@your.tracker.email.domain.example
333 Message-Id: <dummy_test_message_id>
334 Subject: [issue] Testing... [nosy=mary; assignedto=richard]
336 This is a test submission of a new issue.
337 ''')
338         self.compareMessages(self._get_mail(),
339 '''FROM: roundup-admin@your.tracker.email.domain.example
340 TO: chef@bork.bork.bork, mary@test.test, richard@test.test
341 Content-Type: text/plain; charset="utf-8"
342 Subject: [issue1] Testing...
343 To: mary@test.test, richard@test.test
344 From: "Bork, Chef" <issue_tracker@your.tracker.email.domain.example>
345 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
346 MIME-Version: 1.0
347 Message-Id: <dummy_test_message_id>
348 X-Roundup-Name: Roundup issue tracker
349 X-Roundup-Loop: hello
350 X-Roundup-Issue-Status: unread
351 Content-Transfer-Encoding: quoted-printable
353 New submission from Bork, Chef:
355 This is a test submission of a new issue.
357 ----------
358 assignedto: richard
359 messages: 1
360 nosy: Chef, mary, richard
361 status: unread
362 title: Testing...
364 _______________________________________________________________________
365 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
366 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
367 _______________________________________________________________________
368 ''')
370     multipart_msg = '''From: mary <mary@test.test>
371 To: issue_tracker@your.tracker.email.domain.example
372 Message-Id: <followup_dummy_id>
373 In-Reply-To: <dummy_test_message_id>
374 Subject: [issue1] Testing...
375 Content-Type: multipart/mixed; boundary="bxyzzy"
376 Content-Disposition: inline
379 --bxyzzy
380 Content-Type: multipart/alternative; boundary="bCsyhTFzCvuiizWE"
381 Content-Disposition: inline
383 --bCsyhTFzCvuiizWE
384 Content-Type: text/plain; charset=us-ascii
385 Content-Disposition: inline
387 test attachment first text/plain
389 --bCsyhTFzCvuiizWE
390 Content-Type: application/octet-stream
391 Content-Disposition: attachment; filename="first.dvi"
392 Content-Transfer-Encoding: base64
394 SnVzdCBhIHRlc3QgAQo=
396 --bCsyhTFzCvuiizWE
397 Content-Type: text/plain; charset=us-ascii
398 Content-Disposition: inline
400 test attachment second text/plain
402 --bCsyhTFzCvuiizWE
403 Content-Type: text/html
404 Content-Disposition: inline
406 <html>
407 to be ignored.
408 </html>
410 --bCsyhTFzCvuiizWE--
412 --bxyzzy
413 Content-Type: multipart/alternative; boundary="bCsyhTFzCvuiizWF"
414 Content-Disposition: inline
416 --bCsyhTFzCvuiizWF
417 Content-Type: text/plain; charset=us-ascii
418 Content-Disposition: inline
420 test attachment third text/plain
422 --bCsyhTFzCvuiizWF
423 Content-Type: application/octet-stream
424 Content-Disposition: attachment; filename="second.dvi"
425 Content-Transfer-Encoding: base64
427 SnVzdCBhIHRlc3QK
429 --bCsyhTFzCvuiizWF--
431 --bxyzzy--
432 '''
434     def testMultipartKeepAlternatives(self):
435         self.doNewIssue()
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) == 5)
441         names = {0 : 'first.dvi', 4 : 'second.dvi'}
442         content = {3 : 'test attachment third text/plain\n',
443                    4 : '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 testMultipartDropAlternatives(self):
452         self.doNewIssue()
453         self.db.config.MAILGW_IGNORE_ALTERNATIVES = True
454         self._handle_mail(self.multipart_msg)
455         messages = self.db.issue.get('1', 'messages')
456         messages.sort()
457         msg = self.db.msg.getnode (messages[-1])
458         assert(len(msg.files) == 2)
459         names = {1 : 'second.dvi'}
460         content = {0 : 'test attachment third text/plain\n',
461                    1 : 'Just a test\n'}
462         for n, id in enumerate (msg.files):
463             f = self.db.file.getnode (id)
464             self.assertEqual(f.name, names.get (n, 'unnamed'))
465             if n in content :
466                 self.assertEqual(f.content, content [n])
467         self.assertEqual(msg.content, 'test attachment second text/plain')
469     def testSimpleFollowup(self):
470         self.doNewIssue()
471         self._handle_mail('''Content-Type: text/plain;
472   charset="iso-8859-1"
473 From: mary <mary@test.test>
474 To: issue_tracker@your.tracker.email.domain.example
475 Message-Id: <followup_dummy_id>
476 In-Reply-To: <dummy_test_message_id>
477 Subject: [issue1] Testing...
479 This is a second followup
480 ''')
481         self.compareMessages(self._get_mail(),
482 '''FROM: roundup-admin@your.tracker.email.domain.example
483 TO: chef@bork.bork.bork, richard@test.test
484 Content-Type: text/plain; charset="utf-8"
485 Subject: [issue1] Testing...
486 To: chef@bork.bork.bork, richard@test.test
487 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
488 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
489 MIME-Version: 1.0
490 Message-Id: <followup_dummy_id>
491 In-Reply-To: <dummy_test_message_id>
492 X-Roundup-Name: Roundup issue tracker
493 X-Roundup-Loop: hello
494 X-Roundup-Issue-Status: chatting
495 Content-Transfer-Encoding: quoted-printable
498 Contrary, Mary <mary@test.test> added the comment:
500 This is a second followup
502 ----------
503 status: unread -> chatting
505 _______________________________________________________________________
506 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
507 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
508 _______________________________________________________________________
509 ''')
511     def testFollowup(self):
512         self.doNewIssue()
514         self._handle_mail('''Content-Type: text/plain;
515   charset="iso-8859-1"
516 From: richard <richard@test.test>
517 To: issue_tracker@your.tracker.email.domain.example
518 Message-Id: <followup_dummy_id>
519 In-Reply-To: <dummy_test_message_id>
520 Subject: [issue1] Testing... [assignedto=mary; nosy=+john]
522 This is a followup
523 ''')
524         l = self.db.issue.get('1', 'nosy')
525         l.sort()
526         self.assertEqual(l, [self.chef_id, self.richard_id, self.mary_id,
527             self.john_id])
529         self.compareMessages(self._get_mail(),
530 '''FROM: roundup-admin@your.tracker.email.domain.example
531 TO: chef@bork.bork.bork, john@test.test, mary@test.test
532 Content-Type: text/plain; charset="utf-8"
533 Subject: [issue1] Testing...
534 To: chef@bork.bork.bork, john@test.test, mary@test.test
535 From: richard <issue_tracker@your.tracker.email.domain.example>
536 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
537 MIME-Version: 1.0
538 Message-Id: <followup_dummy_id>
539 In-Reply-To: <dummy_test_message_id>
540 X-Roundup-Name: Roundup issue tracker
541 X-Roundup-Loop: hello
542 X-Roundup-Issue-Status: chatting
543 Content-Transfer-Encoding: quoted-printable
546 richard <richard@test.test> added the comment:
548 This is a followup
550 ----------
551 assignedto:  -> mary
552 nosy: +john, mary
553 status: unread -> chatting
555 _______________________________________________________________________
556 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
557 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
558 _______________________________________________________________________
559 ''')
561     def testPropertyChangeOnly(self):
562         self.doNewIssue()
563         oldvalues = self.db.getnode('issue', '1').copy()
564         oldvalues['assignedto'] = None
565         # reconstruct old behaviour: This would reuse the
566         # database-handle from the doNewIssue above which has committed
567         # as user "Chef". So we close and reopen the db as that user.
568         self.db.close()
569         self.db = self.instance.open('Chef')
570         self.db.issue.set('1', assignedto=self.chef_id)
571         self.db.commit()
572         self.db.issue.nosymessage('1', None, oldvalues)
574         new_mail = ""
575         for line in self._get_mail().split("\n"):
576             if "Message-Id: " in line:
577                 continue
578             if "Date: " in line:
579                 continue
580             new_mail += line+"\n"
582         self.compareMessages(new_mail, """
583 FROM: roundup-admin@your.tracker.email.domain.example
584 TO: chef@bork.bork.bork, richard@test.test
585 Content-Type: text/plain; charset="utf-8"
586 Subject: [issue1] Testing...
587 To: chef@bork.bork.bork, richard@test.test
588 From: "Bork, Chef" <issue_tracker@your.tracker.email.domain.example>
589 X-Roundup-Name: Roundup issue tracker
590 X-Roundup-Loop: hello
591 X-Roundup-Issue-Status: unread
592 X-Roundup-Version: 1.3.3
593 MIME-Version: 1.0
594 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
595 Content-Transfer-Encoding: quoted-printable
598 Change by Bork, Chef <chef@bork.bork.bork>:
601 ----------
602 assignedto:  -> Chef
604 _______________________________________________________________________
605 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
606 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
607 _______________________________________________________________________
608 """)
611     #
612     # FOLLOWUP TITLE MATCH
613     #
614     def testFollowupTitleMatch(self):
615         self.doNewIssue()
616         self._handle_mail('''Content-Type: text/plain;
617   charset="iso-8859-1"
618 From: richard <richard@test.test>
619 To: issue_tracker@your.tracker.email.domain.example
620 Message-Id: <followup_dummy_id>
621 Subject: Re: Testing... [assignedto=mary; nosy=+john]
623 This is a followup
624 ''')
625         self.compareMessages(self._get_mail(),
626 '''FROM: roundup-admin@your.tracker.email.domain.example
627 TO: chef@bork.bork.bork, john@test.test, mary@test.test
628 Content-Type: text/plain; charset="utf-8"
629 Subject: [issue1] Testing...
630 To: chef@bork.bork.bork, john@test.test, mary@test.test
631 From: richard <issue_tracker@your.tracker.email.domain.example>
632 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
633 MIME-Version: 1.0
634 Message-Id: <followup_dummy_id>
635 In-Reply-To: <dummy_test_message_id>
636 X-Roundup-Name: Roundup issue tracker
637 X-Roundup-Loop: hello
638 X-Roundup-Issue-Status: chatting
639 Content-Transfer-Encoding: quoted-printable
642 richard <richard@test.test> added the comment:
644 This is a followup
646 ----------
647 assignedto:  -> mary
648 nosy: +john, mary
649 status: unread -> chatting
651 _______________________________________________________________________
652 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
653 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
654 _______________________________________________________________________
655 ''')
657     def testFollowupTitleMatchMultiRe(self):
658         nodeid1 = self.doNewIssue()
659         nodeid2 = self._handle_mail('''Content-Type: text/plain;
660   charset="iso-8859-1"
661 From: richard <richard@test.test>
662 To: issue_tracker@your.tracker.email.domain.example
663 Message-Id: <followup_dummy_id>
664 Subject: Re: Testing... [assignedto=mary; nosy=+john]
666 This is a followup
667 ''')
669         nodeid3 = self._handle_mail('''Content-Type: text/plain;
670   charset="iso-8859-1"
671 From: richard <richard@test.test>
672 To: issue_tracker@your.tracker.email.domain.example
673 Message-Id: <followup2_dummy_id>
674 Subject: Ang: Re: Testing...
676 This is a followup
677 ''')
678         self.assertEqual(nodeid1, nodeid2)
679         self.assertEqual(nodeid1, nodeid3)
681     def testFollowupTitleMatchNever(self):
682         nodeid = self.doNewIssue()
683         self.db.config.MAILGW_SUBJECT_CONTENT_MATCH = 'never'
684         self.assertNotEqual(self._handle_mail('''Content-Type: text/plain;
685   charset="iso-8859-1"
686 From: richard <richard@test.test>
687 To: issue_tracker@your.tracker.email.domain.example
688 Message-Id: <followup_dummy_id>
689 Subject: Re: Testing...
691 This is a followup
692 '''), nodeid)
694     def testFollowupTitleMatchNeverInterval(self):
695         nodeid = self.doNewIssue()
696         # force failure of the interval
697         time.sleep(2)
698         self.db.config.MAILGW_SUBJECT_CONTENT_MATCH = 'creation 00:00:01'
699         self.assertNotEqual(self._handle_mail('''Content-Type: text/plain;
700   charset="iso-8859-1"
701 From: richard <richard@test.test>
702 To: issue_tracker@your.tracker.email.domain.example
703 Message-Id: <followup_dummy_id>
704 Subject: Re: Testing...
706 This is a followup
707 '''), nodeid)
710     def testFollowupTitleMatchInterval(self):
711         nodeid = self.doNewIssue()
712         self.db.config.MAILGW_SUBJECT_CONTENT_MATCH = 'creation +1d'
713         self.assertEqual(self._handle_mail('''Content-Type: text/plain;
714   charset="iso-8859-1"
715 From: richard <richard@test.test>
716 To: issue_tracker@your.tracker.email.domain.example
717 Message-Id: <followup_dummy_id>
718 Subject: Re: Testing...
720 This is a followup
721 '''), nodeid)
724     def testFollowupNosyAuthor(self):
725         self.doNewIssue()
726         self.db.config.ADD_AUTHOR_TO_NOSY = 'yes'
727         self._handle_mail('''Content-Type: text/plain;
728   charset="iso-8859-1"
729 From: john@test.test
730 To: issue_tracker@your.tracker.email.domain.example
731 Message-Id: <followup_dummy_id>
732 In-Reply-To: <dummy_test_message_id>
733 Subject: [issue1] Testing...
735 This is a followup
736 ''')
738         self.compareMessages(self._get_mail(),
739 '''FROM: roundup-admin@your.tracker.email.domain.example
740 TO: chef@bork.bork.bork, richard@test.test
741 Content-Type: text/plain; charset="utf-8"
742 Subject: [issue1] Testing...
743 To: chef@bork.bork.bork, richard@test.test
744 From: John Doe <issue_tracker@your.tracker.email.domain.example>
745 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
746 MIME-Version: 1.0
747 Message-Id: <followup_dummy_id>
748 In-Reply-To: <dummy_test_message_id>
749 X-Roundup-Name: Roundup issue tracker
750 X-Roundup-Loop: hello
751 X-Roundup-Issue-Status: chatting
752 Content-Transfer-Encoding: quoted-printable
755 John Doe <john@test.test> added the comment:
757 This is a followup
759 ----------
760 nosy: +john
761 status: unread -> chatting
763 _______________________________________________________________________
764 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
765 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
766 _______________________________________________________________________
768 ''')
770     def testFollowupNosyRecipients(self):
771         self.doNewIssue()
772         self.db.config.ADD_RECIPIENTS_TO_NOSY = 'yes'
773         self._handle_mail('''Content-Type: text/plain;
774   charset="iso-8859-1"
775 From: richard@test.test
776 To: issue_tracker@your.tracker.email.domain.example
777 Cc: john@test.test
778 Message-Id: <followup_dummy_id>
779 In-Reply-To: <dummy_test_message_id>
780 Subject: [issue1] Testing...
782 This is a followup
783 ''')
784         self.compareMessages(self._get_mail(),
785 '''FROM: roundup-admin@your.tracker.email.domain.example
786 TO: chef@bork.bork.bork
787 Content-Type: text/plain; charset="utf-8"
788 Subject: [issue1] Testing...
789 To: chef@bork.bork.bork
790 From: richard <issue_tracker@your.tracker.email.domain.example>
791 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
792 MIME-Version: 1.0
793 Message-Id: <followup_dummy_id>
794 In-Reply-To: <dummy_test_message_id>
795 X-Roundup-Name: Roundup issue tracker
796 X-Roundup-Loop: hello
797 X-Roundup-Issue-Status: chatting
798 Content-Transfer-Encoding: quoted-printable
801 richard <richard@test.test> added the comment:
803 This is a followup
805 ----------
806 nosy: +john
807 status: unread -> chatting
809 _______________________________________________________________________
810 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
811 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
812 _______________________________________________________________________
814 ''')
816     def testFollowupNosyAuthorAndCopy(self):
817         self.doNewIssue()
818         self.db.config.ADD_AUTHOR_TO_NOSY = 'yes'
819         self.db.config.MESSAGES_TO_AUTHOR = 'yes'
820         self._handle_mail('''Content-Type: text/plain;
821   charset="iso-8859-1"
822 From: john@test.test
823 To: issue_tracker@your.tracker.email.domain.example
824 Message-Id: <followup_dummy_id>
825 In-Reply-To: <dummy_test_message_id>
826 Subject: [issue1] Testing...
828 This is a followup
829 ''')
830         self.compareMessages(self._get_mail(),
831 '''FROM: roundup-admin@your.tracker.email.domain.example
832 TO: chef@bork.bork.bork, john@test.test, richard@test.test
833 Content-Type: text/plain; charset="utf-8"
834 Subject: [issue1] Testing...
835 To: chef@bork.bork.bork, john@test.test, richard@test.test
836 From: John Doe <issue_tracker@your.tracker.email.domain.example>
837 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
838 MIME-Version: 1.0
839 Message-Id: <followup_dummy_id>
840 In-Reply-To: <dummy_test_message_id>
841 X-Roundup-Name: Roundup issue tracker
842 X-Roundup-Loop: hello
843 X-Roundup-Issue-Status: chatting
844 Content-Transfer-Encoding: quoted-printable
847 John Doe <john@test.test> added the comment:
849 This is a followup
851 ----------
852 nosy: +john
853 status: unread -> chatting
855 _______________________________________________________________________
856 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
857 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
858 _______________________________________________________________________
860 ''')
862     def testFollowupNoNosyAuthor(self):
863         self.doNewIssue()
864         self.instance.config.ADD_AUTHOR_TO_NOSY = 'no'
865         self._handle_mail('''Content-Type: text/plain;
866   charset="iso-8859-1"
867 From: john@test.test
868 To: issue_tracker@your.tracker.email.domain.example
869 Message-Id: <followup_dummy_id>
870 In-Reply-To: <dummy_test_message_id>
871 Subject: [issue1] Testing...
873 This is a followup
874 ''')
875         self.compareMessages(self._get_mail(),
876 '''FROM: roundup-admin@your.tracker.email.domain.example
877 TO: chef@bork.bork.bork, richard@test.test
878 Content-Type: text/plain; charset="utf-8"
879 Subject: [issue1] Testing...
880 To: chef@bork.bork.bork, richard@test.test
881 From: John Doe <issue_tracker@your.tracker.email.domain.example>
882 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
883 MIME-Version: 1.0
884 Message-Id: <followup_dummy_id>
885 In-Reply-To: <dummy_test_message_id>
886 X-Roundup-Name: Roundup issue tracker
887 X-Roundup-Loop: hello
888 X-Roundup-Issue-Status: chatting
889 Content-Transfer-Encoding: quoted-printable
892 John Doe <john@test.test> added the comment:
894 This is a followup
896 ----------
897 status: unread -> chatting
899 _______________________________________________________________________
900 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
901 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
902 _______________________________________________________________________
904 ''')
906     def testFollowupNoNosyRecipients(self):
907         self.doNewIssue()
908         self.instance.config.ADD_RECIPIENTS_TO_NOSY = 'no'
909         self._handle_mail('''Content-Type: text/plain;
910   charset="iso-8859-1"
911 From: richard@test.test
912 To: issue_tracker@your.tracker.email.domain.example
913 Cc: john@test.test
914 Message-Id: <followup_dummy_id>
915 In-Reply-To: <dummy_test_message_id>
916 Subject: [issue1] Testing...
918 This is a followup
919 ''')
920         self.compareMessages(self._get_mail(),
921 '''FROM: roundup-admin@your.tracker.email.domain.example
922 TO: chef@bork.bork.bork
923 Content-Type: text/plain; charset="utf-8"
924 Subject: [issue1] Testing...
925 To: chef@bork.bork.bork
926 From: richard <issue_tracker@your.tracker.email.domain.example>
927 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
928 MIME-Version: 1.0
929 Message-Id: <followup_dummy_id>
930 In-Reply-To: <dummy_test_message_id>
931 X-Roundup-Name: Roundup issue tracker
932 X-Roundup-Loop: hello
933 X-Roundup-Issue-Status: chatting
934 Content-Transfer-Encoding: quoted-printable
937 richard <richard@test.test> added the comment:
939 This is a followup
941 ----------
942 status: unread -> chatting
944 _______________________________________________________________________
945 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
946 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
947 _______________________________________________________________________
949 ''')
951     def testFollowupEmptyMessage(self):
952         self.doNewIssue()
954         self._handle_mail('''Content-Type: text/plain;
955   charset="iso-8859-1"
956 From: richard <richard@test.test>
957 To: issue_tracker@your.tracker.email.domain.example
958 Message-Id: <followup_dummy_id>
959 In-Reply-To: <dummy_test_message_id>
960 Subject: [issue1] Testing... [assignedto=mary; nosy=+john]
962 ''')
963         l = self.db.issue.get('1', 'nosy')
964         l.sort()
965         self.assertEqual(l, [self.chef_id, self.richard_id, self.mary_id,
966             self.john_id])
968         # should be no file created (ie. no message)
969         assert not os.path.exists(SENDMAILDEBUG)
971     def testFollowupEmptyMessageNoSubject(self):
972         self.doNewIssue()
974         self._handle_mail('''Content-Type: text/plain;
975   charset="iso-8859-1"
976 From: richard <richard@test.test>
977 To: issue_tracker@your.tracker.email.domain.example
978 Message-Id: <followup_dummy_id>
979 In-Reply-To: <dummy_test_message_id>
980 Subject: [issue1] [assignedto=mary; nosy=+john]
982 ''')
983         l = self.db.issue.get('1', 'nosy')
984         l.sort()
985         self.assertEqual(l, [self.chef_id, self.richard_id, self.mary_id,
986             self.john_id])
988         # should be no file created (ie. no message)
989         assert not os.path.exists(SENDMAILDEBUG)
991     def testNosyRemove(self):
992         self.doNewIssue()
994         self._handle_mail('''Content-Type: text/plain;
995   charset="iso-8859-1"
996 From: richard <richard@test.test>
997 To: issue_tracker@your.tracker.email.domain.example
998 Message-Id: <followup_dummy_id>
999 In-Reply-To: <dummy_test_message_id>
1000 Subject: [issue1] Testing... [nosy=-richard]
1002 ''')
1003         l = self.db.issue.get('1', 'nosy')
1004         l.sort()
1005         self.assertEqual(l, [self.chef_id])
1007         # NO NOSY MESSAGE SHOULD BE SENT!
1008         assert not os.path.exists(SENDMAILDEBUG)
1010     def testNewUserAuthor(self):
1012         l = self.db.user.list()
1013         l.sort()
1014         message = '''Content-Type: text/plain;
1015   charset="iso-8859-1"
1016 From: fubar <fubar@bork.bork.bork>
1017 To: issue_tracker@your.tracker.email.domain.example
1018 Message-Id: <dummy_test_message_id>
1019 Subject: [issue] Testing...
1021 This is a test submission of a new issue.
1022 '''
1023         def hook (db, **kw):
1024             ''' set up callback for db open '''
1025             db.security.role['anonymous'].permissions=[]
1026             anonid = db.user.lookup('anonymous')
1027             db.user.set(anonid, roles='Anonymous')
1028         self.instance.schema_hook = hook
1029         try:
1030             self._handle_mail(message)
1031         except Unauthorized, value:
1032             body_diff = self.compareMessages(str(value), """
1033 You are not a registered user.
1035 Unknown address: fubar@bork.bork.bork
1036 """)
1038             assert not body_diff, body_diff
1040         else:
1041             raise AssertionError, "Unathorized not raised when handling mail"
1044         def hook (db, **kw):
1045             ''' set up callback for db open '''
1046             # Add Web Access role to anonymous, and try again to make sure
1047             # we get a "please register at:" message this time.
1048             p = [
1049                 db.security.getPermission('Register', 'user'),
1050                 db.security.getPermission('Web Access', None),
1051             ]
1052             db.security.role['anonymous'].permissions=p
1053         self.instance.schema_hook = hook
1054         try:
1055             self._handle_mail(message)
1056         except Unauthorized, value:
1057             body_diff = self.compareMessages(str(value), """
1058 You are not a registered user. Please register at:
1060 http://tracker.example/cgi-bin/roundup.cgi/bugs/user?template=register
1062 ...before sending mail to the tracker.
1064 Unknown address: fubar@bork.bork.bork
1065 """)
1067             assert not body_diff, body_diff
1069         else:
1070             raise AssertionError, "Unathorized not raised when handling mail"
1072         # Make sure list of users is the same as before.
1073         m = self.db.user.list()
1074         m.sort()
1075         self.assertEqual(l, m)
1077         def hook (db, **kw):
1078             ''' set up callback for db open '''
1079             # now with the permission
1080             p = [
1081                 db.security.getPermission('Register', 'user'),
1082                 db.security.getPermission('Email Access', None),
1083             ]
1084             db.security.role['anonymous'].permissions=p
1085         self.instance.schema_hook = hook
1086         self._handle_mail(message)
1087         m = self.db.user.list()
1088         m.sort()
1089         self.assertNotEqual(l, m)
1091     def testNewUserAuthorEncodedName(self):
1092         l = set(self.db.user.list())
1093         # From: name has Euro symbol in it
1094         message = '''Content-Type: text/plain;
1095   charset="iso-8859-1"
1096 From: =?utf8?b?SOKCrGxsbw==?= <fubar@bork.bork.bork>
1097 To: issue_tracker@your.tracker.email.domain.example
1098 Message-Id: <dummy_test_message_id>
1099 Subject: [issue] Testing...
1101 This is a test submission of a new issue.
1102 '''
1103         def hook (db, **kw):
1104             ''' set up callback for db open '''
1105             p = [
1106                 db.security.getPermission('Register', 'user'),
1107                 db.security.getPermission('Email Access', None),
1108                 db.security.getPermission('Create', 'issue'),
1109                 db.security.getPermission('Create', 'msg'),
1110             ]
1111             db.security.role['anonymous'].permissions = p
1112         self.instance.schema_hook = hook
1113         self._handle_mail(message)
1114         m = set(self.db.user.list())
1115         new = list(m - l)[0]
1116         name = self.db.user.get(new, 'realname')
1117         self.assertEquals(name, 'H€llo')
1119     def testUnknownUser(self):
1120         l = set(self.db.user.list())
1121         message = '''Content-Type: text/plain;
1122   charset="iso-8859-1"
1123 From: Nonexisting User <nonexisting@bork.bork.bork>
1124 To: issue_tracker@your.tracker.email.domain.example
1125 Message-Id: <dummy_test_message_id>
1126 Subject: [issue] Testing nonexisting user...
1128 This is a test submission of a new issue.
1129 '''
1130         self.db.close()
1131         handler = self.instance.MailGW(self.instance)
1132         # we want a bounce message:
1133         handler.trapExceptions = 1
1134         ret = handler.main(StringIO(message))
1135         self.compareMessages(self._get_mail(),
1136 '''FROM: Roundup issue tracker <roundup-admin@your.tracker.email.domain.example>
1137 TO: nonexisting@bork.bork.bork
1138 From nobody Tue Jul 14 12:04:11 2009
1139 Content-Type: multipart/mixed; boundary="===============0639262320=="
1140 MIME-Version: 1.0
1141 Subject: Failed issue tracker submission
1142 To: nonexisting@bork.bork.bork
1143 From: Roundup issue tracker <roundup-admin@your.tracker.email.domain.example>
1144 Date: Tue, 14 Jul 2009 12:04:11 +0000
1145 Precedence: bulk
1146 X-Roundup-Name: Roundup issue tracker
1147 X-Roundup-Loop: hello
1148 X-Roundup-Version: 1.4.8
1149 MIME-Version: 1.0
1151 --===============0639262320==
1152 Content-Type: text/plain; charset="us-ascii"
1153 MIME-Version: 1.0
1154 Content-Transfer-Encoding: 7bit
1158 You are not a registered user. Please register at:
1160 http://tracker.example/cgi-bin/roundup.cgi/bugs/user?template=register
1162 ...before sending mail to the tracker.
1164 Unknown address: nonexisting@bork.bork.bork
1166 --===============0639262320==
1167 Content-Type: text/plain; charset="us-ascii"
1168 MIME-Version: 1.0
1169 Content-Transfer-Encoding: 7bit
1171 Content-Type: text/plain;
1172   charset="iso-8859-1"
1173 From: Nonexisting User <nonexisting@bork.bork.bork>
1174 To: issue_tracker@your.tracker.email.domain.example
1175 Message-Id: <dummy_test_message_id>
1176 Subject: [issue] Testing nonexisting user...
1178 This is a test submission of a new issue.
1180 --===============0639262320==--
1181 ''')
1183     def testEnc01(self):
1184         self.doNewIssue()
1185         self._handle_mail('''Content-Type: text/plain;
1186   charset="iso-8859-1"
1187 From: mary <mary@test.test>
1188 To: issue_tracker@your.tracker.email.domain.example
1189 Message-Id: <followup_dummy_id>
1190 In-Reply-To: <dummy_test_message_id>
1191 Subject: [issue1] Testing...
1192 Content-Type: text/plain;
1193         charset="iso-8859-1"
1194 Content-Transfer-Encoding: quoted-printable
1196 A message with encoding (encoded oe =F6)
1198 ''')
1199         self.compareMessages(self._get_mail(),
1200 '''FROM: roundup-admin@your.tracker.email.domain.example
1201 TO: chef@bork.bork.bork, richard@test.test
1202 Content-Type: text/plain; charset="utf-8"
1203 Subject: [issue1] Testing...
1204 To: chef@bork.bork.bork, richard@test.test
1205 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
1206 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1207 MIME-Version: 1.0
1208 Message-Id: <followup_dummy_id>
1209 In-Reply-To: <dummy_test_message_id>
1210 X-Roundup-Name: Roundup issue tracker
1211 X-Roundup-Loop: hello
1212 X-Roundup-Issue-Status: chatting
1213 Content-Transfer-Encoding: quoted-printable
1216 Contrary, Mary <mary@test.test> added the comment:
1218 A message with encoding (encoded oe =C3=B6)
1220 ----------
1221 status: unread -> chatting
1223 _______________________________________________________________________
1224 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1225 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1226 _______________________________________________________________________
1227 ''')
1229     def testEncNonUTF8(self):
1230         self.doNewIssue()
1231         self.instance.config.EMAIL_CHARSET = 'iso-8859-1'
1232         self._handle_mail('''Content-Type: text/plain;
1233   charset="iso-8859-1"
1234 From: mary <mary@test.test>
1235 To: issue_tracker@your.tracker.email.domain.example
1236 Message-Id: <followup_dummy_id>
1237 In-Reply-To: <dummy_test_message_id>
1238 Subject: [issue1] Testing...
1239 Content-Type: text/plain;
1240         charset="iso-8859-1"
1241 Content-Transfer-Encoding: quoted-printable
1243 A message with encoding (encoded oe =F6)
1245 ''')
1246         self.compareMessages(self._get_mail(),
1247 '''FROM: roundup-admin@your.tracker.email.domain.example
1248 TO: chef@bork.bork.bork, richard@test.test
1249 Content-Type: text/plain; charset="iso-8859-1"
1250 Subject: [issue1] Testing...
1251 To: chef@bork.bork.bork, richard@test.test
1252 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
1253 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1254 MIME-Version: 1.0
1255 Message-Id: <followup_dummy_id>
1256 In-Reply-To: <dummy_test_message_id>
1257 X-Roundup-Name: Roundup issue tracker
1258 X-Roundup-Loop: hello
1259 X-Roundup-Issue-Status: chatting
1260 Content-Transfer-Encoding: quoted-printable
1263 Contrary, Mary <mary@test.test> added the comment:
1265 A message with encoding (encoded oe =F6)
1267 ----------
1268 status: unread -> chatting
1270 _______________________________________________________________________
1271 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1272 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1273 _______________________________________________________________________
1274 ''')
1277     def testMultipartEnc01(self):
1278         self.doNewIssue()
1279         self._handle_mail('''Content-Type: text/plain;
1280   charset="iso-8859-1"
1281 From: mary <mary@test.test>
1282 To: issue_tracker@your.tracker.email.domain.example
1283 Message-Id: <followup_dummy_id>
1284 In-Reply-To: <dummy_test_message_id>
1285 Subject: [issue1] Testing...
1286 Content-Type: multipart/mixed;
1287         boundary="----_=_NextPart_000_01"
1289 This message is in MIME format. Since your mail reader does not understand
1290 this format, some or all of this message may not be legible.
1292 ------_=_NextPart_000_01
1293 Content-Type: text/plain;
1294         charset="iso-8859-1"
1295 Content-Transfer-Encoding: quoted-printable
1297 A message with first part encoded (encoded oe =F6)
1299 ''')
1300         self.compareMessages(self._get_mail(),
1301 '''FROM: roundup-admin@your.tracker.email.domain.example
1302 TO: chef@bork.bork.bork, richard@test.test
1303 Content-Type: text/plain; charset="utf-8"
1304 Subject: [issue1] Testing...
1305 To: chef@bork.bork.bork, richard@test.test
1306 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
1307 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1308 MIME-Version: 1.0
1309 Message-Id: <followup_dummy_id>
1310 In-Reply-To: <dummy_test_message_id>
1311 X-Roundup-Name: Roundup issue tracker
1312 X-Roundup-Loop: hello
1313 X-Roundup-Issue-Status: chatting
1314 Content-Transfer-Encoding: quoted-printable
1317 Contrary, Mary <mary@test.test> added the comment:
1319 A message with first part encoded (encoded oe =C3=B6)
1321 ----------
1322 status: unread -> chatting
1324 _______________________________________________________________________
1325 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1326 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1327 _______________________________________________________________________
1328 ''')
1330     def testContentDisposition(self):
1331         self.doNewIssue()
1332         self._handle_mail('''Content-Type: text/plain;
1333   charset="iso-8859-1"
1334 From: mary <mary@test.test>
1335 To: issue_tracker@your.tracker.email.domain.example
1336 Message-Id: <followup_dummy_id>
1337 In-Reply-To: <dummy_test_message_id>
1338 Subject: [issue1] Testing...
1339 Content-Type: multipart/mixed; boundary="bCsyhTFzCvuiizWE"
1340 Content-Disposition: inline
1343 --bCsyhTFzCvuiizWE
1344 Content-Type: text/plain; charset=us-ascii
1345 Content-Disposition: inline
1347 test attachment binary
1349 --bCsyhTFzCvuiizWE
1350 Content-Type: application/octet-stream
1351 Content-Disposition: attachment; filename="main.dvi"
1352 Content-Transfer-Encoding: base64
1354 SnVzdCBhIHRlc3QgAQo=
1356 --bCsyhTFzCvuiizWE--
1357 ''')
1358         messages = self.db.issue.get('1', 'messages')
1359         messages.sort()
1360         file = self.db.file.getnode (self.db.msg.get(messages[-1], 'files')[0])
1361         self.assertEqual(file.name, 'main.dvi')
1362         self.assertEqual(file.content, 'Just a test \001\n')
1364     def testFollowupStupidQuoting(self):
1365         self.doNewIssue()
1367         self._handle_mail('''Content-Type: text/plain;
1368   charset="iso-8859-1"
1369 From: richard <richard@test.test>
1370 To: issue_tracker@your.tracker.email.domain.example
1371 Message-Id: <followup_dummy_id>
1372 In-Reply-To: <dummy_test_message_id>
1373 Subject: Re: "[issue1] Testing... "
1375 This is a followup
1376 ''')
1377         self.compareMessages(self._get_mail(),
1378 '''FROM: roundup-admin@your.tracker.email.domain.example
1379 TO: chef@bork.bork.bork
1380 Content-Type: text/plain; charset="utf-8"
1381 Subject: [issue1] Testing...
1382 To: chef@bork.bork.bork
1383 From: richard <issue_tracker@your.tracker.email.domain.example>
1384 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1385 MIME-Version: 1.0
1386 Message-Id: <followup_dummy_id>
1387 In-Reply-To: <dummy_test_message_id>
1388 X-Roundup-Name: Roundup issue tracker
1389 X-Roundup-Loop: hello
1390 X-Roundup-Issue-Status: chatting
1391 Content-Transfer-Encoding: quoted-printable
1394 richard <richard@test.test> added the comment:
1396 This is a followup
1398 ----------
1399 status: unread -> chatting
1401 _______________________________________________________________________
1402 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1403 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1404 _______________________________________________________________________
1405 ''')
1407     def testEmailQuoting(self):
1408         self.instance.config.EMAIL_KEEP_QUOTED_TEXT = 'no'
1409         self.innerTestQuoting('''This is a followup
1410 ''')
1412     def testEmailQuotingRemove(self):
1413         self.instance.config.EMAIL_KEEP_QUOTED_TEXT = 'yes'
1414         self.innerTestQuoting('''Blah blah wrote:
1415 > Blah bklaskdfj sdf asdf jlaskdf skj sdkfjl asdf
1416 >  skdjlkjsdfalsdkfjasdlfkj dlfksdfalksd fj
1419 This is a followup
1420 ''')
1422     def innerTestQuoting(self, expect):
1423         nodeid = self.doNewIssue()
1425         messages = self.db.issue.get(nodeid, 'messages')
1427         self._handle_mail('''Content-Type: text/plain;
1428   charset="iso-8859-1"
1429 From: richard <richard@test.test>
1430 To: issue_tracker@your.tracker.email.domain.example
1431 Message-Id: <followup_dummy_id>
1432 In-Reply-To: <dummy_test_message_id>
1433 Subject: Re: [issue1] Testing...
1435 Blah blah wrote:
1436 > Blah bklaskdfj sdf asdf jlaskdf skj sdkfjl asdf
1437 >  skdjlkjsdfalsdkfjasdlfkj dlfksdfalksd fj
1440 This is a followup
1441 ''')
1442         # figure the new message id
1443         newmessages = self.db.issue.get(nodeid, 'messages')
1444         for msg in messages:
1445             newmessages.remove(msg)
1446         messageid = newmessages[0]
1448         self.compareMessages(self.db.msg.get(messageid, 'content'), expect)
1450     def testUserLookup(self):
1451         i = self.db.user.create(username='user1', address='user1@foo.com')
1452         self.assertEqual(uidFromAddress(self.db, ('', 'user1@foo.com'), 0), i)
1453         self.assertEqual(uidFromAddress(self.db, ('', 'USER1@foo.com'), 0), i)
1454         i = self.db.user.create(username='user2', address='USER2@foo.com')
1455         self.assertEqual(uidFromAddress(self.db, ('', 'USER2@foo.com'), 0), i)
1456         self.assertEqual(uidFromAddress(self.db, ('', 'user2@foo.com'), 0), i)
1458     def testUserAlternateLookup(self):
1459         i = self.db.user.create(username='user1', address='user1@foo.com',
1460                                 alternate_addresses='user1@bar.com')
1461         self.assertEqual(uidFromAddress(self.db, ('', 'user1@bar.com'), 0), i)
1462         self.assertEqual(uidFromAddress(self.db, ('', 'USER1@bar.com'), 0), i)
1464     def testUserCreate(self):
1465         i = uidFromAddress(self.db, ('', 'user@foo.com'), 1)
1466         self.assertNotEqual(uidFromAddress(self.db, ('', 'user@bar.com'), 1), i)
1468     def testRFC2822(self):
1469         ascii_header = "[issue243] This is a \"test\" - with 'quotation' marks"
1470         unicode_header = '[issue244] \xd0\xb0\xd0\xbd\xd0\xb4\xd1\x80\xd0\xb5\xd0\xb9'
1471         unicode_encoded = '=?utf-8?q?[issue244]_=D0=B0=D0=BD=D0=B4=D1=80=D0=B5=D0=B9?='
1472         self.assertEqual(rfc2822.encode_header(ascii_header), ascii_header)
1473         self.assertEqual(rfc2822.encode_header(unicode_header), unicode_encoded)
1475     def testRegistrationConfirmation(self):
1476         otk = "Aj4euk4LZSAdwePohj90SME5SpopLETL"
1477         self.db.getOTKManager().set(otk, username='johannes')
1478         self._handle_mail('''Content-Type: text/plain;
1479   charset="iso-8859-1"
1480 From: Chef <chef@bork.bork.bork>
1481 To: issue_tracker@your.tracker.email.domain.example
1482 Cc: richard@test.test
1483 Message-Id: <dummy_test_message_id>
1484 Subject: Re: Complete your registration to Roundup issue tracker
1485  -- key %s
1487 This is a test confirmation of registration.
1488 ''' % otk)
1489         self.db.user.lookup('johannes')
1491     def testFollowupOnNonIssue(self):
1492         self.db.keyword.create(name='Foo')
1493         self._handle_mail('''Content-Type: text/plain;
1494   charset="iso-8859-1"
1495 From: richard <richard@test.test>
1496 To: issue_tracker@your.tracker.email.domain.example
1497 Message-Id: <followup_dummy_id>
1498 In-Reply-To: <dummy_test_message_id>
1499 Subject: [keyword1] Testing... [name=Bar]
1501 ''')
1502         self.assertEqual(self.db.keyword.get('1', 'name'), 'Bar')
1504     def testResentFrom(self):
1505         nodeid = self._handle_mail('''Content-Type: text/plain;
1506   charset="iso-8859-1"
1507 From: Chef <chef@bork.bork.bork>
1508 Resent-From: mary <mary@test.test>
1509 To: issue_tracker@your.tracker.email.domain.example
1510 Cc: richard@test.test
1511 Message-Id: <dummy_test_message_id>
1512 Subject: [issue] Testing...
1514 This is a test submission of a new issue.
1515 ''')
1516         assert not os.path.exists(SENDMAILDEBUG)
1517         l = self.db.issue.get(nodeid, 'nosy')
1518         l.sort()
1519         self.assertEqual(l, [self.richard_id, self.mary_id])
1520         return nodeid
1522     def testDejaVu(self):
1523         self.assertRaises(IgnoreLoop, self._handle_mail,
1524             '''Content-Type: text/plain;
1525   charset="iso-8859-1"
1526 From: Chef <chef@bork.bork.bork>
1527 X-Roundup-Loop: hello
1528 To: issue_tracker@your.tracker.email.domain.example
1529 Cc: richard@test.test
1530 Message-Id: <dummy_test_message_id>
1531 Subject: Re: [issue] Testing...
1533 Hi, I've been mis-configured to loop messages back to myself.
1534 ''')
1536     def testItsBulkStupid(self):
1537         self.assertRaises(IgnoreBulk, self._handle_mail,
1538             '''Content-Type: text/plain;
1539   charset="iso-8859-1"
1540 From: Chef <chef@bork.bork.bork>
1541 Precedence: bulk
1542 To: issue_tracker@your.tracker.email.domain.example
1543 Cc: richard@test.test
1544 Message-Id: <dummy_test_message_id>
1545 Subject: Re: [issue] Testing...
1547 Hi, I'm on holidays, and this is a dumb auto-responder.
1548 ''')
1550     def testAutoReplyEmailsAreIgnored(self):
1551         self.assertRaises(IgnoreBulk, self._handle_mail,
1552             '''Content-Type: text/plain;
1553   charset="iso-8859-1"
1554 From: Chef <chef@bork.bork.bork>
1555 To: issue_tracker@your.tracker.email.domain.example
1556 Cc: richard@test.test
1557 Message-Id: <dummy_test_message_id>
1558 Subject: Re: [issue] Out of office AutoReply: Back next week
1560 Hi, I am back in the office next week
1561 ''')
1563     def testNoSubject(self):
1564         self.assertRaises(MailUsageError, self._handle_mail,
1565             '''Content-Type: text/plain;
1566   charset="iso-8859-1"
1567 From: Chef <chef@bork.bork.bork>
1568 To: issue_tracker@your.tracker.email.domain.example
1569 Cc: richard@test.test
1570 Reply-To: chef@bork.bork.bork
1571 Message-Id: <dummy_test_message_id>
1573 ''')
1575     #
1576     # TEST FOR INVALID DESIGNATOR HANDLING
1577     #
1578     def testInvalidDesignator(self):
1579         self.assertRaises(MailUsageError, self._handle_mail,
1580             '''Content-Type: text/plain;
1581   charset="iso-8859-1"
1582 From: Chef <chef@bork.bork.bork>
1583 To: issue_tracker@your.tracker.email.domain.example
1584 Subject: [frobulated] testing
1585 Cc: richard@test.test
1586 Reply-To: chef@bork.bork.bork
1587 Message-Id: <dummy_test_message_id>
1589 ''')
1590         self.assertRaises(MailUsageError, self._handle_mail,
1591             '''Content-Type: text/plain;
1592   charset="iso-8859-1"
1593 From: Chef <chef@bork.bork.bork>
1594 To: issue_tracker@your.tracker.email.domain.example
1595 Subject: [issue12345] testing
1596 Cc: richard@test.test
1597 Reply-To: chef@bork.bork.bork
1598 Message-Id: <dummy_test_message_id>
1600 ''')
1602     def testInvalidClassLoose(self):
1603         self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'loose'
1604         nodeid = self._handle_mail('''Content-Type: text/plain;
1605   charset="iso-8859-1"
1606 From: Chef <chef@bork.bork.bork>
1607 To: issue_tracker@your.tracker.email.domain.example
1608 Subject: [frobulated] testing
1609 Cc: richard@test.test
1610 Reply-To: chef@bork.bork.bork
1611 Message-Id: <dummy_test_message_id>
1613 ''')
1614         assert not os.path.exists(SENDMAILDEBUG)
1615         self.assertEqual(self.db.issue.get(nodeid, 'title'),
1616             '[frobulated] testing')
1618     def testInvalidClassLooseReply(self):
1619         self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'loose'
1620         nodeid = self._handle_mail('''Content-Type: text/plain;
1621   charset="iso-8859-1"
1622 From: Chef <chef@bork.bork.bork>
1623 To: issue_tracker@your.tracker.email.domain.example
1624 Subject: Re: [frobulated] testing
1625 Cc: richard@test.test
1626 Reply-To: chef@bork.bork.bork
1627 Message-Id: <dummy_test_message_id>
1629 ''')
1630         assert not os.path.exists(SENDMAILDEBUG)
1631         self.assertEqual(self.db.issue.get(nodeid, 'title'),
1632             '[frobulated] testing')
1634     def testInvalidClassLoose(self):
1635         self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'loose'
1636         nodeid = self._handle_mail('''Content-Type: text/plain;
1637   charset="iso-8859-1"
1638 From: Chef <chef@bork.bork.bork>
1639 To: issue_tracker@your.tracker.email.domain.example
1640 Subject: [issue1234] testing
1641 Cc: richard@test.test
1642 Reply-To: chef@bork.bork.bork
1643 Message-Id: <dummy_test_message_id>
1645 ''')
1646         assert not os.path.exists(SENDMAILDEBUG)
1647         self.assertEqual(self.db.issue.get(nodeid, 'title'),
1648             '[issue1234] testing')
1650     def testClassLooseOK(self):
1651         self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'loose'
1652         self.db.keyword.create(name='Foo')
1653         nodeid = self._handle_mail('''Content-Type: text/plain;
1654   charset="iso-8859-1"
1655 From: Chef <chef@bork.bork.bork>
1656 To: issue_tracker@your.tracker.email.domain.example
1657 Subject: [keyword1] Testing... [name=Bar]
1658 Cc: richard@test.test
1659 Reply-To: chef@bork.bork.bork
1660 Message-Id: <dummy_test_message_id>
1662 ''')
1663         assert not os.path.exists(SENDMAILDEBUG)
1664         self.assertEqual(self.db.keyword.get('1', 'name'), 'Bar')
1666     def testClassStrictInvalid(self):
1667         self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'strict'
1668         self.instance.config.MAILGW_DEFAULT_CLASS = ''
1670         message = '''Content-Type: text/plain;
1671   charset="iso-8859-1"
1672 From: Chef <chef@bork.bork.bork>
1673 To: issue_tracker@your.tracker.email.domain.example
1674 Subject: Testing...
1675 Cc: richard@test.test
1676 Reply-To: chef@bork.bork.bork
1677 Message-Id: <dummy_test_message_id>
1679 '''
1680         self.assertRaises(MailUsageError, self._handle_mail, message)
1682     def testClassStrictValid(self):
1683         self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'strict'
1684         self.instance.config.MAILGW_DEFAULT_CLASS = ''
1686         nodeid = self._handle_mail('''Content-Type: text/plain;
1687   charset="iso-8859-1"
1688 From: Chef <chef@bork.bork.bork>
1689 To: issue_tracker@your.tracker.email.domain.example
1690 Subject: [issue] Testing...
1691 Cc: richard@test.test
1692 Reply-To: chef@bork.bork.bork
1693 Message-Id: <dummy_test_message_id>
1695 ''')
1697         assert not os.path.exists(SENDMAILDEBUG)
1698         self.assertEqual(self.db.issue.get(nodeid, 'title'), 'Testing...')
1700     #
1701     # TEST FOR INVALID COMMANDS HANDLING
1702     #
1703     def testInvalidCommands(self):
1704         self.assertRaises(MailUsageError, self._handle_mail,
1705             '''Content-Type: text/plain;
1706   charset="iso-8859-1"
1707 From: Chef <chef@bork.bork.bork>
1708 To: issue_tracker@your.tracker.email.domain.example
1709 Subject: testing [frobulated]
1710 Cc: richard@test.test
1711 Reply-To: chef@bork.bork.bork
1712 Message-Id: <dummy_test_message_id>
1714 ''')
1716     def testInvalidCommandPassthrough(self):
1717         self.instance.config.MAILGW_SUBJECT_SUFFIX_PARSING = 'none'
1718         nodeid = self._handle_mail('''Content-Type: text/plain;
1719   charset="iso-8859-1"
1720 From: Chef <chef@bork.bork.bork>
1721 To: issue_tracker@your.tracker.email.domain.example
1722 Subject: testing [frobulated]
1723 Cc: richard@test.test
1724 Reply-To: chef@bork.bork.bork
1725 Message-Id: <dummy_test_message_id>
1727 ''')
1728         assert not os.path.exists(SENDMAILDEBUG)
1729         self.assertEqual(self.db.issue.get(nodeid, 'title'),
1730             'testing [frobulated]')
1732     def testInvalidCommandPassthroughLoose(self):
1733         self.instance.config.MAILGW_SUBJECT_SUFFIX_PARSING = 'loose'
1734         nodeid = self._handle_mail('''Content-Type: text/plain;
1735   charset="iso-8859-1"
1736 From: Chef <chef@bork.bork.bork>
1737 To: issue_tracker@your.tracker.email.domain.example
1738 Subject: testing [frobulated]
1739 Cc: richard@test.test
1740 Reply-To: chef@bork.bork.bork
1741 Message-Id: <dummy_test_message_id>
1743 ''')
1744         assert not os.path.exists(SENDMAILDEBUG)
1745         self.assertEqual(self.db.issue.get(nodeid, 'title'),
1746             'testing [frobulated]')
1748     def testInvalidCommandPassthroughLooseOK(self):
1749         self.instance.config.MAILGW_SUBJECT_SUFFIX_PARSING = 'loose'
1750         nodeid = self._handle_mail('''Content-Type: text/plain;
1751   charset="iso-8859-1"
1752 From: Chef <chef@bork.bork.bork>
1753 To: issue_tracker@your.tracker.email.domain.example
1754 Subject: testing [assignedto=mary]
1755 Cc: richard@test.test
1756 Reply-To: chef@bork.bork.bork
1757 Message-Id: <dummy_test_message_id>
1759 ''')
1760         assert not os.path.exists(SENDMAILDEBUG)
1761         self.assertEqual(self.db.issue.get(nodeid, 'title'), 'testing')
1762         self.assertEqual(self.db.issue.get(nodeid, 'assignedto'), self.mary_id)
1764     def testCommandDelimiters(self):
1765         self.instance.config.MAILGW_SUBJECT_SUFFIX_DELIMITERS = '{}'
1766         nodeid = self._handle_mail('''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 Subject: testing {assignedto=mary}
1771 Cc: richard@test.test
1772 Reply-To: chef@bork.bork.bork
1773 Message-Id: <dummy_test_message_id>
1775 ''')
1776         assert not os.path.exists(SENDMAILDEBUG)
1777         self.assertEqual(self.db.issue.get(nodeid, 'title'), 'testing')
1778         self.assertEqual(self.db.issue.get(nodeid, 'assignedto'), self.mary_id)
1780     def testPrefixDelimiters(self):
1781         self.instance.config.MAILGW_SUBJECT_SUFFIX_DELIMITERS = '{}'
1782         self.db.keyword.create(name='Foo')
1783         self._handle_mail('''Content-Type: text/plain;
1784   charset="iso-8859-1"
1785 From: richard <richard@test.test>
1786 To: issue_tracker@your.tracker.email.domain.example
1787 Message-Id: <followup_dummy_id>
1788 In-Reply-To: <dummy_test_message_id>
1789 Subject: {keyword1} Testing... {name=Bar}
1791 ''')
1792         assert not os.path.exists(SENDMAILDEBUG)
1793         self.assertEqual(self.db.keyword.get('1', 'name'), 'Bar')
1795     def testCommandDelimitersIgnore(self):
1796         self.instance.config.MAILGW_SUBJECT_SUFFIX_DELIMITERS = '{}'
1797         nodeid = 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: testing [assignedto=mary]
1802 Cc: richard@test.test
1803 Reply-To: chef@bork.bork.bork
1804 Message-Id: <dummy_test_message_id>
1806 ''')
1807         assert not os.path.exists(SENDMAILDEBUG)
1808         self.assertEqual(self.db.issue.get(nodeid, 'title'),
1809             'testing [assignedto=mary]')
1810         self.assertEqual(self.db.issue.get(nodeid, 'assignedto'), None)
1812     def testReplytoMatch(self):
1813         self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'loose'
1814         nodeid = self.doNewIssue()
1815         nodeid2 = self._handle_mail('''Content-Type: text/plain;
1816   charset="iso-8859-1"
1817 From: Chef <chef@bork.bork.bork>
1818 To: issue_tracker@your.tracker.email.domain.example
1819 Message-Id: <dummy_test_message_id2>
1820 In-Reply-To: <dummy_test_message_id>
1821 Subject: Testing...
1823 Followup message.
1824 ''')
1826         nodeid3 = self._handle_mail('''Content-Type: text/plain;
1827   charset="iso-8859-1"
1828 From: Chef <chef@bork.bork.bork>
1829 To: issue_tracker@your.tracker.email.domain.example
1830 Message-Id: <dummy_test_message_id3>
1831 In-Reply-To: <dummy_test_message_id2>
1832 Subject: Testing...
1834 Yet another message in the same thread/issue.
1835 ''')
1837         self.assertEqual(nodeid, nodeid2)
1838         self.assertEqual(nodeid, nodeid3)
1840     def testHelpSubject(self):
1841         message = '''Content-Type: text/plain;
1842   charset="iso-8859-1"
1843 From: Chef <chef@bork.bork.bork>
1844 To: issue_tracker@your.tracker.email.domain.example
1845 Message-Id: <dummy_test_message_id2>
1846 In-Reply-To: <dummy_test_message_id>
1847 Subject: hElp
1850 '''
1851         self.assertRaises(MailUsageHelp, self._handle_mail, message)
1853     def testMaillistSubject(self):
1854         self.instance.config.MAILGW_SUBJECT_SUFFIX_DELIMITERS = '[]'
1855         self.db.keyword.create(name='Foo')
1856         self._handle_mail('''Content-Type: text/plain;
1857   charset="iso-8859-1"
1858 From: Chef <chef@bork.bork.bork>
1859 To: issue_tracker@your.tracker.email.domain.example
1860 Subject: [mailinglist-name] [keyword1] Testing.. [name=Bar]
1861 Cc: richard@test.test
1862 Reply-To: chef@bork.bork.bork
1863 Message-Id: <dummy_test_message_id>
1865 ''')
1867         assert not os.path.exists(SENDMAILDEBUG)
1868         self.assertEqual(self.db.keyword.get('1', 'name'), 'Bar')
1870     def testUnknownPrefixSubject(self):
1871         self.db.keyword.create(name='Foo')
1872         self._handle_mail('''Content-Type: text/plain;
1873   charset="iso-8859-1"
1874 From: Chef <chef@bork.bork.bork>
1875 To: issue_tracker@your.tracker.email.domain.example
1876 Subject: VeryStrangeRe: [keyword1] Testing.. [name=Bar]
1877 Cc: richard@test.test
1878 Reply-To: chef@bork.bork.bork
1879 Message-Id: <dummy_test_message_id>
1881 ''')
1883         assert not os.path.exists(SENDMAILDEBUG)
1884         self.assertEqual(self.db.keyword.get('1', 'name'), 'Bar')
1886     def testIssueidLast(self):
1887         nodeid1 = self.doNewIssue()
1888         nodeid2 = self._handle_mail('''Content-Type: text/plain;
1889   charset="iso-8859-1"
1890 From: mary <mary@test.test>
1891 To: issue_tracker@your.tracker.email.domain.example
1892 Message-Id: <followup_dummy_id>
1893 In-Reply-To: <dummy_test_message_id>
1894 Subject: New title [issue1]
1896 This is a second followup
1897 ''')
1899         assert nodeid1 == nodeid2
1900         self.assertEqual(self.db.issue.get(nodeid2, 'title'), "Testing...")
1902     def testSecurityMessagePermissionContent(self):
1903         id = self.doNewIssue()
1904         issue = self.db.issue.getnode (id)
1905         self.db.security.addRole(name='Nomsg')
1906         self.db.security.addPermissionToRole('Nomsg', 'Email Access')
1907         for cl in 'issue', 'file', 'keyword':
1908             for p in 'View', 'Edit', 'Create':
1909                 self.db.security.addPermissionToRole('Nomsg', p, cl)
1910         self.db.user.set(self.mary_id, roles='Nomsg')
1911         nodeid = self._handle_mail('''Content-Type: text/plain;
1912   charset="iso-8859-1"
1913 From: Chef <chef@bork.bork.bork>
1914 To: issue_tracker@your.tracker.email.domain.example
1915 Message-Id: <dummy_test_message_id>
1916 Subject: [issue%(id)s] Testing... [nosy=+mary]
1918 Just a test reply
1919 '''%locals())
1920         assert os.path.exists(SENDMAILDEBUG)
1921         self.compareMessages(self._get_mail(),
1922 '''FROM: roundup-admin@your.tracker.email.domain.example
1923 TO: chef@bork.bork.bork, richard@test.test
1924 Content-Type: text/plain; charset="utf-8"
1925 Subject: [issue1] Testing...
1926 To: richard@test.test
1927 From: "Bork, Chef" <issue_tracker@your.tracker.email.domain.example>
1928 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1929 MIME-Version: 1.0
1930 Message-Id: <dummy_test_message_id>
1931 X-Roundup-Name: Roundup issue tracker
1932 X-Roundup-Loop: hello
1933 X-Roundup-Issue-Status: chatting
1934 Content-Transfer-Encoding: quoted-printable
1937 Bork, Chef <chef@bork.bork.bork> added the comment:
1939 Just a test reply
1941 ----------
1942 nosy: +mary
1943 status: unread -> chatting
1945 _______________________________________________________________________
1946 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1947 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1948 _______________________________________________________________________
1949 ''')
1952 def test_suite():
1953     suite = unittest.TestSuite()
1954     suite.addTest(unittest.makeSuite(MailgwTestCase))
1955     return suite
1957 if __name__ == '__main__':
1958     runner = unittest.TextTestRunner()
1959     unittest.main(testRunner=runner)
1961 # vim: set filetype=python sts=4 sw=4 et si :