Code

Fix handling of non-ascii in realname in the nosy mailer, this used to
[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.db.user.set(self.mary_id,
1185             realname='\xe4\xf6\xfc\xc4\xd6\xdc\xdf, Mary'.decode
1186             ('latin-1').encode('utf-8'))
1187         self.doNewIssue()
1188         self._handle_mail('''Content-Type: text/plain;
1189   charset="iso-8859-1"
1190 From: mary <mary@test.test>
1191 To: issue_tracker@your.tracker.email.domain.example
1192 Message-Id: <followup_dummy_id>
1193 In-Reply-To: <dummy_test_message_id>
1194 Subject: [issue1] Testing...
1195 Content-Type: text/plain;
1196         charset="iso-8859-1"
1197 Content-Transfer-Encoding: quoted-printable
1199 A message with encoding (encoded oe =F6)
1201 ''')
1202         self.compareMessages(self._get_mail(),
1203 '''FROM: roundup-admin@your.tracker.email.domain.example
1204 TO: chef@bork.bork.bork, richard@test.test
1205 Content-Type: text/plain; charset="utf-8"
1206 Subject: [issue1] Testing...
1207 To: chef@bork.bork.bork, richard@test.test
1208 From: =?utf-8?b?w6TDtsO8w4TDlsOcw58sIE1hcnk=?=
1209  <issue_tracker@your.tracker.email.domain.example>
1210 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1211 MIME-Version: 1.0
1212 Message-Id: <followup_dummy_id>
1213 In-Reply-To: <dummy_test_message_id>
1214 X-Roundup-Name: Roundup issue tracker
1215 X-Roundup-Loop: hello
1216 X-Roundup-Issue-Status: chatting
1217 Content-Transfer-Encoding: quoted-printable
1220 =C3=A4=C3=B6=C3=BC=C3=84=C3=96=C3=9C=C3=9F, Mary <mary@test.test> added the=
1221  comment:
1223 A message with encoding (encoded oe =C3=B6)
1225 ----------
1226 status: unread -> chatting
1228 _______________________________________________________________________
1229 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1230 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1231 _______________________________________________________________________
1232 ''')
1234     def testEncNonUTF8(self):
1235         self.doNewIssue()
1236         self.instance.config.EMAIL_CHARSET = 'iso-8859-1'
1237         self._handle_mail('''Content-Type: text/plain;
1238   charset="iso-8859-1"
1239 From: mary <mary@test.test>
1240 To: issue_tracker@your.tracker.email.domain.example
1241 Message-Id: <followup_dummy_id>
1242 In-Reply-To: <dummy_test_message_id>
1243 Subject: [issue1] Testing...
1244 Content-Type: text/plain;
1245         charset="iso-8859-1"
1246 Content-Transfer-Encoding: quoted-printable
1248 A message with encoding (encoded oe =F6)
1250 ''')
1251         self.compareMessages(self._get_mail(),
1252 '''FROM: roundup-admin@your.tracker.email.domain.example
1253 TO: chef@bork.bork.bork, richard@test.test
1254 Content-Type: text/plain; charset="iso-8859-1"
1255 Subject: [issue1] Testing...
1256 To: chef@bork.bork.bork, richard@test.test
1257 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
1258 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1259 MIME-Version: 1.0
1260 Message-Id: <followup_dummy_id>
1261 In-Reply-To: <dummy_test_message_id>
1262 X-Roundup-Name: Roundup issue tracker
1263 X-Roundup-Loop: hello
1264 X-Roundup-Issue-Status: chatting
1265 Content-Transfer-Encoding: quoted-printable
1268 Contrary, Mary <mary@test.test> added the comment:
1270 A message with encoding (encoded oe =F6)
1272 ----------
1273 status: unread -> chatting
1275 _______________________________________________________________________
1276 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1277 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1278 _______________________________________________________________________
1279 ''')
1282     def testMultipartEnc01(self):
1283         self.doNewIssue()
1284         self._handle_mail('''Content-Type: text/plain;
1285   charset="iso-8859-1"
1286 From: mary <mary@test.test>
1287 To: issue_tracker@your.tracker.email.domain.example
1288 Message-Id: <followup_dummy_id>
1289 In-Reply-To: <dummy_test_message_id>
1290 Subject: [issue1] Testing...
1291 Content-Type: multipart/mixed;
1292         boundary="----_=_NextPart_000_01"
1294 This message is in MIME format. Since your mail reader does not understand
1295 this format, some or all of this message may not be legible.
1297 ------_=_NextPart_000_01
1298 Content-Type: text/plain;
1299         charset="iso-8859-1"
1300 Content-Transfer-Encoding: quoted-printable
1302 A message with first part encoded (encoded oe =F6)
1304 ''')
1305         self.compareMessages(self._get_mail(),
1306 '''FROM: roundup-admin@your.tracker.email.domain.example
1307 TO: chef@bork.bork.bork, richard@test.test
1308 Content-Type: text/plain; charset="utf-8"
1309 Subject: [issue1] Testing...
1310 To: chef@bork.bork.bork, richard@test.test
1311 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
1312 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1313 MIME-Version: 1.0
1314 Message-Id: <followup_dummy_id>
1315 In-Reply-To: <dummy_test_message_id>
1316 X-Roundup-Name: Roundup issue tracker
1317 X-Roundup-Loop: hello
1318 X-Roundup-Issue-Status: chatting
1319 Content-Transfer-Encoding: quoted-printable
1322 Contrary, Mary <mary@test.test> added the comment:
1324 A message with first part encoded (encoded oe =C3=B6)
1326 ----------
1327 status: unread -> chatting
1329 _______________________________________________________________________
1330 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1331 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1332 _______________________________________________________________________
1333 ''')
1335     def testContentDisposition(self):
1336         self.doNewIssue()
1337         self._handle_mail('''Content-Type: text/plain;
1338   charset="iso-8859-1"
1339 From: mary <mary@test.test>
1340 To: issue_tracker@your.tracker.email.domain.example
1341 Message-Id: <followup_dummy_id>
1342 In-Reply-To: <dummy_test_message_id>
1343 Subject: [issue1] Testing...
1344 Content-Type: multipart/mixed; boundary="bCsyhTFzCvuiizWE"
1345 Content-Disposition: inline
1348 --bCsyhTFzCvuiizWE
1349 Content-Type: text/plain; charset=us-ascii
1350 Content-Disposition: inline
1352 test attachment binary
1354 --bCsyhTFzCvuiizWE
1355 Content-Type: application/octet-stream
1356 Content-Disposition: attachment; filename="main.dvi"
1357 Content-Transfer-Encoding: base64
1359 SnVzdCBhIHRlc3QgAQo=
1361 --bCsyhTFzCvuiizWE--
1362 ''')
1363         messages = self.db.issue.get('1', 'messages')
1364         messages.sort()
1365         file = self.db.file.getnode (self.db.msg.get(messages[-1], 'files')[0])
1366         self.assertEqual(file.name, 'main.dvi')
1367         self.assertEqual(file.content, 'Just a test \001\n')
1369     def testFollowupStupidQuoting(self):
1370         self.doNewIssue()
1372         self._handle_mail('''Content-Type: text/plain;
1373   charset="iso-8859-1"
1374 From: richard <richard@test.test>
1375 To: issue_tracker@your.tracker.email.domain.example
1376 Message-Id: <followup_dummy_id>
1377 In-Reply-To: <dummy_test_message_id>
1378 Subject: Re: "[issue1] Testing... "
1380 This is a followup
1381 ''')
1382         self.compareMessages(self._get_mail(),
1383 '''FROM: roundup-admin@your.tracker.email.domain.example
1384 TO: chef@bork.bork.bork
1385 Content-Type: text/plain; charset="utf-8"
1386 Subject: [issue1] Testing...
1387 To: chef@bork.bork.bork
1388 From: richard <issue_tracker@your.tracker.email.domain.example>
1389 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1390 MIME-Version: 1.0
1391 Message-Id: <followup_dummy_id>
1392 In-Reply-To: <dummy_test_message_id>
1393 X-Roundup-Name: Roundup issue tracker
1394 X-Roundup-Loop: hello
1395 X-Roundup-Issue-Status: chatting
1396 Content-Transfer-Encoding: quoted-printable
1399 richard <richard@test.test> added the comment:
1401 This is a followup
1403 ----------
1404 status: unread -> chatting
1406 _______________________________________________________________________
1407 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1408 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1409 _______________________________________________________________________
1410 ''')
1412     def testEmailQuoting(self):
1413         self.instance.config.EMAIL_KEEP_QUOTED_TEXT = 'no'
1414         self.innerTestQuoting('''This is a followup
1415 ''')
1417     def testEmailQuotingRemove(self):
1418         self.instance.config.EMAIL_KEEP_QUOTED_TEXT = 'yes'
1419         self.innerTestQuoting('''Blah blah wrote:
1420 > Blah bklaskdfj sdf asdf jlaskdf skj sdkfjl asdf
1421 >  skdjlkjsdfalsdkfjasdlfkj dlfksdfalksd fj
1424 This is a followup
1425 ''')
1427     def innerTestQuoting(self, expect):
1428         nodeid = self.doNewIssue()
1430         messages = self.db.issue.get(nodeid, 'messages')
1432         self._handle_mail('''Content-Type: text/plain;
1433   charset="iso-8859-1"
1434 From: richard <richard@test.test>
1435 To: issue_tracker@your.tracker.email.domain.example
1436 Message-Id: <followup_dummy_id>
1437 In-Reply-To: <dummy_test_message_id>
1438 Subject: Re: [issue1] Testing...
1440 Blah blah wrote:
1441 > Blah bklaskdfj sdf asdf jlaskdf skj sdkfjl asdf
1442 >  skdjlkjsdfalsdkfjasdlfkj dlfksdfalksd fj
1445 This is a followup
1446 ''')
1447         # figure the new message id
1448         newmessages = self.db.issue.get(nodeid, 'messages')
1449         for msg in messages:
1450             newmessages.remove(msg)
1451         messageid = newmessages[0]
1453         self.compareMessages(self.db.msg.get(messageid, 'content'), expect)
1455     def testUserLookup(self):
1456         i = self.db.user.create(username='user1', address='user1@foo.com')
1457         self.assertEqual(uidFromAddress(self.db, ('', 'user1@foo.com'), 0), i)
1458         self.assertEqual(uidFromAddress(self.db, ('', 'USER1@foo.com'), 0), i)
1459         i = self.db.user.create(username='user2', address='USER2@foo.com')
1460         self.assertEqual(uidFromAddress(self.db, ('', 'USER2@foo.com'), 0), i)
1461         self.assertEqual(uidFromAddress(self.db, ('', 'user2@foo.com'), 0), i)
1463     def testUserAlternateLookup(self):
1464         i = self.db.user.create(username='user1', address='user1@foo.com',
1465                                 alternate_addresses='user1@bar.com')
1466         self.assertEqual(uidFromAddress(self.db, ('', 'user1@bar.com'), 0), i)
1467         self.assertEqual(uidFromAddress(self.db, ('', 'USER1@bar.com'), 0), i)
1469     def testUserCreate(self):
1470         i = uidFromAddress(self.db, ('', 'user@foo.com'), 1)
1471         self.assertNotEqual(uidFromAddress(self.db, ('', 'user@bar.com'), 1), i)
1473     def testRFC2822(self):
1474         ascii_header = "[issue243] This is a \"test\" - with 'quotation' marks"
1475         unicode_header = '[issue244] \xd0\xb0\xd0\xbd\xd0\xb4\xd1\x80\xd0\xb5\xd0\xb9'
1476         unicode_encoded = '=?utf-8?q?[issue244]_=D0=B0=D0=BD=D0=B4=D1=80=D0=B5=D0=B9?='
1477         self.assertEqual(rfc2822.encode_header(ascii_header), ascii_header)
1478         self.assertEqual(rfc2822.encode_header(unicode_header), unicode_encoded)
1480     def testRegistrationConfirmation(self):
1481         otk = "Aj4euk4LZSAdwePohj90SME5SpopLETL"
1482         self.db.getOTKManager().set(otk, username='johannes')
1483         self._handle_mail('''Content-Type: text/plain;
1484   charset="iso-8859-1"
1485 From: Chef <chef@bork.bork.bork>
1486 To: issue_tracker@your.tracker.email.domain.example
1487 Cc: richard@test.test
1488 Message-Id: <dummy_test_message_id>
1489 Subject: Re: Complete your registration to Roundup issue tracker
1490  -- key %s
1492 This is a test confirmation of registration.
1493 ''' % otk)
1494         self.db.user.lookup('johannes')
1496     def testFollowupOnNonIssue(self):
1497         self.db.keyword.create(name='Foo')
1498         self._handle_mail('''Content-Type: text/plain;
1499   charset="iso-8859-1"
1500 From: richard <richard@test.test>
1501 To: issue_tracker@your.tracker.email.domain.example
1502 Message-Id: <followup_dummy_id>
1503 In-Reply-To: <dummy_test_message_id>
1504 Subject: [keyword1] Testing... [name=Bar]
1506 ''')
1507         self.assertEqual(self.db.keyword.get('1', 'name'), 'Bar')
1509     def testResentFrom(self):
1510         nodeid = self._handle_mail('''Content-Type: text/plain;
1511   charset="iso-8859-1"
1512 From: Chef <chef@bork.bork.bork>
1513 Resent-From: mary <mary@test.test>
1514 To: issue_tracker@your.tracker.email.domain.example
1515 Cc: richard@test.test
1516 Message-Id: <dummy_test_message_id>
1517 Subject: [issue] Testing...
1519 This is a test submission of a new issue.
1520 ''')
1521         assert not os.path.exists(SENDMAILDEBUG)
1522         l = self.db.issue.get(nodeid, 'nosy')
1523         l.sort()
1524         self.assertEqual(l, [self.richard_id, self.mary_id])
1525         return nodeid
1527     def testDejaVu(self):
1528         self.assertRaises(IgnoreLoop, self._handle_mail,
1529             '''Content-Type: text/plain;
1530   charset="iso-8859-1"
1531 From: Chef <chef@bork.bork.bork>
1532 X-Roundup-Loop: hello
1533 To: issue_tracker@your.tracker.email.domain.example
1534 Cc: richard@test.test
1535 Message-Id: <dummy_test_message_id>
1536 Subject: Re: [issue] Testing...
1538 Hi, I've been mis-configured to loop messages back to myself.
1539 ''')
1541     def testItsBulkStupid(self):
1542         self.assertRaises(IgnoreBulk, self._handle_mail,
1543             '''Content-Type: text/plain;
1544   charset="iso-8859-1"
1545 From: Chef <chef@bork.bork.bork>
1546 Precedence: bulk
1547 To: issue_tracker@your.tracker.email.domain.example
1548 Cc: richard@test.test
1549 Message-Id: <dummy_test_message_id>
1550 Subject: Re: [issue] Testing...
1552 Hi, I'm on holidays, and this is a dumb auto-responder.
1553 ''')
1555     def testAutoReplyEmailsAreIgnored(self):
1556         self.assertRaises(IgnoreBulk, self._handle_mail,
1557             '''Content-Type: text/plain;
1558   charset="iso-8859-1"
1559 From: Chef <chef@bork.bork.bork>
1560 To: issue_tracker@your.tracker.email.domain.example
1561 Cc: richard@test.test
1562 Message-Id: <dummy_test_message_id>
1563 Subject: Re: [issue] Out of office AutoReply: Back next week
1565 Hi, I am back in the office next week
1566 ''')
1568     def testNoSubject(self):
1569         self.assertRaises(MailUsageError, self._handle_mail,
1570             '''Content-Type: text/plain;
1571   charset="iso-8859-1"
1572 From: Chef <chef@bork.bork.bork>
1573 To: issue_tracker@your.tracker.email.domain.example
1574 Cc: richard@test.test
1575 Reply-To: chef@bork.bork.bork
1576 Message-Id: <dummy_test_message_id>
1578 ''')
1580     #
1581     # TEST FOR INVALID DESIGNATOR HANDLING
1582     #
1583     def testInvalidDesignator(self):
1584         self.assertRaises(MailUsageError, self._handle_mail,
1585             '''Content-Type: text/plain;
1586   charset="iso-8859-1"
1587 From: Chef <chef@bork.bork.bork>
1588 To: issue_tracker@your.tracker.email.domain.example
1589 Subject: [frobulated] testing
1590 Cc: richard@test.test
1591 Reply-To: chef@bork.bork.bork
1592 Message-Id: <dummy_test_message_id>
1594 ''')
1595         self.assertRaises(MailUsageError, self._handle_mail,
1596             '''Content-Type: text/plain;
1597   charset="iso-8859-1"
1598 From: Chef <chef@bork.bork.bork>
1599 To: issue_tracker@your.tracker.email.domain.example
1600 Subject: [issue12345] testing
1601 Cc: richard@test.test
1602 Reply-To: chef@bork.bork.bork
1603 Message-Id: <dummy_test_message_id>
1605 ''')
1607     def testInvalidClassLoose(self):
1608         self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'loose'
1609         nodeid = self._handle_mail('''Content-Type: text/plain;
1610   charset="iso-8859-1"
1611 From: Chef <chef@bork.bork.bork>
1612 To: issue_tracker@your.tracker.email.domain.example
1613 Subject: [frobulated] testing
1614 Cc: richard@test.test
1615 Reply-To: chef@bork.bork.bork
1616 Message-Id: <dummy_test_message_id>
1618 ''')
1619         assert not os.path.exists(SENDMAILDEBUG)
1620         self.assertEqual(self.db.issue.get(nodeid, 'title'),
1621             '[frobulated] testing')
1623     def testInvalidClassLooseReply(self):
1624         self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'loose'
1625         nodeid = self._handle_mail('''Content-Type: text/plain;
1626   charset="iso-8859-1"
1627 From: Chef <chef@bork.bork.bork>
1628 To: issue_tracker@your.tracker.email.domain.example
1629 Subject: Re: [frobulated] testing
1630 Cc: richard@test.test
1631 Reply-To: chef@bork.bork.bork
1632 Message-Id: <dummy_test_message_id>
1634 ''')
1635         assert not os.path.exists(SENDMAILDEBUG)
1636         self.assertEqual(self.db.issue.get(nodeid, 'title'),
1637             '[frobulated] testing')
1639     def testInvalidClassLoose(self):
1640         self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'loose'
1641         nodeid = self._handle_mail('''Content-Type: text/plain;
1642   charset="iso-8859-1"
1643 From: Chef <chef@bork.bork.bork>
1644 To: issue_tracker@your.tracker.email.domain.example
1645 Subject: [issue1234] testing
1646 Cc: richard@test.test
1647 Reply-To: chef@bork.bork.bork
1648 Message-Id: <dummy_test_message_id>
1650 ''')
1651         assert not os.path.exists(SENDMAILDEBUG)
1652         self.assertEqual(self.db.issue.get(nodeid, 'title'),
1653             '[issue1234] testing')
1655     def testClassLooseOK(self):
1656         self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'loose'
1657         self.db.keyword.create(name='Foo')
1658         nodeid = 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 Subject: [keyword1] Testing... [name=Bar]
1663 Cc: richard@test.test
1664 Reply-To: chef@bork.bork.bork
1665 Message-Id: <dummy_test_message_id>
1667 ''')
1668         assert not os.path.exists(SENDMAILDEBUG)
1669         self.assertEqual(self.db.keyword.get('1', 'name'), 'Bar')
1671     def testClassStrictInvalid(self):
1672         self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'strict'
1673         self.instance.config.MAILGW_DEFAULT_CLASS = ''
1675         message = '''Content-Type: text/plain;
1676   charset="iso-8859-1"
1677 From: Chef <chef@bork.bork.bork>
1678 To: issue_tracker@your.tracker.email.domain.example
1679 Subject: Testing...
1680 Cc: richard@test.test
1681 Reply-To: chef@bork.bork.bork
1682 Message-Id: <dummy_test_message_id>
1684 '''
1685         self.assertRaises(MailUsageError, self._handle_mail, message)
1687     def testClassStrictValid(self):
1688         self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'strict'
1689         self.instance.config.MAILGW_DEFAULT_CLASS = ''
1691         nodeid = self._handle_mail('''Content-Type: text/plain;
1692   charset="iso-8859-1"
1693 From: Chef <chef@bork.bork.bork>
1694 To: issue_tracker@your.tracker.email.domain.example
1695 Subject: [issue] Testing...
1696 Cc: richard@test.test
1697 Reply-To: chef@bork.bork.bork
1698 Message-Id: <dummy_test_message_id>
1700 ''')
1702         assert not os.path.exists(SENDMAILDEBUG)
1703         self.assertEqual(self.db.issue.get(nodeid, 'title'), 'Testing...')
1705     #
1706     # TEST FOR INVALID COMMANDS HANDLING
1707     #
1708     def testInvalidCommands(self):
1709         self.assertRaises(MailUsageError, self._handle_mail,
1710             '''Content-Type: text/plain;
1711   charset="iso-8859-1"
1712 From: Chef <chef@bork.bork.bork>
1713 To: issue_tracker@your.tracker.email.domain.example
1714 Subject: testing [frobulated]
1715 Cc: richard@test.test
1716 Reply-To: chef@bork.bork.bork
1717 Message-Id: <dummy_test_message_id>
1719 ''')
1721     def testInvalidCommandPassthrough(self):
1722         self.instance.config.MAILGW_SUBJECT_SUFFIX_PARSING = 'none'
1723         nodeid = self._handle_mail('''Content-Type: text/plain;
1724   charset="iso-8859-1"
1725 From: Chef <chef@bork.bork.bork>
1726 To: issue_tracker@your.tracker.email.domain.example
1727 Subject: testing [frobulated]
1728 Cc: richard@test.test
1729 Reply-To: chef@bork.bork.bork
1730 Message-Id: <dummy_test_message_id>
1732 ''')
1733         assert not os.path.exists(SENDMAILDEBUG)
1734         self.assertEqual(self.db.issue.get(nodeid, 'title'),
1735             'testing [frobulated]')
1737     def testInvalidCommandPassthroughLoose(self):
1738         self.instance.config.MAILGW_SUBJECT_SUFFIX_PARSING = 'loose'
1739         nodeid = self._handle_mail('''Content-Type: text/plain;
1740   charset="iso-8859-1"
1741 From: Chef <chef@bork.bork.bork>
1742 To: issue_tracker@your.tracker.email.domain.example
1743 Subject: testing [frobulated]
1744 Cc: richard@test.test
1745 Reply-To: chef@bork.bork.bork
1746 Message-Id: <dummy_test_message_id>
1748 ''')
1749         assert not os.path.exists(SENDMAILDEBUG)
1750         self.assertEqual(self.db.issue.get(nodeid, 'title'),
1751             'testing [frobulated]')
1753     def testInvalidCommandPassthroughLooseOK(self):
1754         self.instance.config.MAILGW_SUBJECT_SUFFIX_PARSING = 'loose'
1755         nodeid = self._handle_mail('''Content-Type: text/plain;
1756   charset="iso-8859-1"
1757 From: Chef <chef@bork.bork.bork>
1758 To: issue_tracker@your.tracker.email.domain.example
1759 Subject: testing [assignedto=mary]
1760 Cc: richard@test.test
1761 Reply-To: chef@bork.bork.bork
1762 Message-Id: <dummy_test_message_id>
1764 ''')
1765         assert not os.path.exists(SENDMAILDEBUG)
1766         self.assertEqual(self.db.issue.get(nodeid, 'title'), 'testing')
1767         self.assertEqual(self.db.issue.get(nodeid, 'assignedto'), self.mary_id)
1769     def testCommandDelimiters(self):
1770         self.instance.config.MAILGW_SUBJECT_SUFFIX_DELIMITERS = '{}'
1771         nodeid = self._handle_mail('''Content-Type: text/plain;
1772   charset="iso-8859-1"
1773 From: Chef <chef@bork.bork.bork>
1774 To: issue_tracker@your.tracker.email.domain.example
1775 Subject: testing {assignedto=mary}
1776 Cc: richard@test.test
1777 Reply-To: chef@bork.bork.bork
1778 Message-Id: <dummy_test_message_id>
1780 ''')
1781         assert not os.path.exists(SENDMAILDEBUG)
1782         self.assertEqual(self.db.issue.get(nodeid, 'title'), 'testing')
1783         self.assertEqual(self.db.issue.get(nodeid, 'assignedto'), self.mary_id)
1785     def testPrefixDelimiters(self):
1786         self.instance.config.MAILGW_SUBJECT_SUFFIX_DELIMITERS = '{}'
1787         self.db.keyword.create(name='Foo')
1788         self._handle_mail('''Content-Type: text/plain;
1789   charset="iso-8859-1"
1790 From: richard <richard@test.test>
1791 To: issue_tracker@your.tracker.email.domain.example
1792 Message-Id: <followup_dummy_id>
1793 In-Reply-To: <dummy_test_message_id>
1794 Subject: {keyword1} Testing... {name=Bar}
1796 ''')
1797         assert not os.path.exists(SENDMAILDEBUG)
1798         self.assertEqual(self.db.keyword.get('1', 'name'), 'Bar')
1800     def testCommandDelimitersIgnore(self):
1801         self.instance.config.MAILGW_SUBJECT_SUFFIX_DELIMITERS = '{}'
1802         nodeid = self._handle_mail('''Content-Type: text/plain;
1803   charset="iso-8859-1"
1804 From: Chef <chef@bork.bork.bork>
1805 To: issue_tracker@your.tracker.email.domain.example
1806 Subject: testing [assignedto=mary]
1807 Cc: richard@test.test
1808 Reply-To: chef@bork.bork.bork
1809 Message-Id: <dummy_test_message_id>
1811 ''')
1812         assert not os.path.exists(SENDMAILDEBUG)
1813         self.assertEqual(self.db.issue.get(nodeid, 'title'),
1814             'testing [assignedto=mary]')
1815         self.assertEqual(self.db.issue.get(nodeid, 'assignedto'), None)
1817     def testReplytoMatch(self):
1818         self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'loose'
1819         nodeid = self.doNewIssue()
1820         nodeid2 = self._handle_mail('''Content-Type: text/plain;
1821   charset="iso-8859-1"
1822 From: Chef <chef@bork.bork.bork>
1823 To: issue_tracker@your.tracker.email.domain.example
1824 Message-Id: <dummy_test_message_id2>
1825 In-Reply-To: <dummy_test_message_id>
1826 Subject: Testing...
1828 Followup message.
1829 ''')
1831         nodeid3 = self._handle_mail('''Content-Type: text/plain;
1832   charset="iso-8859-1"
1833 From: Chef <chef@bork.bork.bork>
1834 To: issue_tracker@your.tracker.email.domain.example
1835 Message-Id: <dummy_test_message_id3>
1836 In-Reply-To: <dummy_test_message_id2>
1837 Subject: Testing...
1839 Yet another message in the same thread/issue.
1840 ''')
1842         self.assertEqual(nodeid, nodeid2)
1843         self.assertEqual(nodeid, nodeid3)
1845     def testHelpSubject(self):
1846         message = '''Content-Type: text/plain;
1847   charset="iso-8859-1"
1848 From: Chef <chef@bork.bork.bork>
1849 To: issue_tracker@your.tracker.email.domain.example
1850 Message-Id: <dummy_test_message_id2>
1851 In-Reply-To: <dummy_test_message_id>
1852 Subject: hElp
1855 '''
1856         self.assertRaises(MailUsageHelp, self._handle_mail, message)
1858     def testMaillistSubject(self):
1859         self.instance.config.MAILGW_SUBJECT_SUFFIX_DELIMITERS = '[]'
1860         self.db.keyword.create(name='Foo')
1861         self._handle_mail('''Content-Type: text/plain;
1862   charset="iso-8859-1"
1863 From: Chef <chef@bork.bork.bork>
1864 To: issue_tracker@your.tracker.email.domain.example
1865 Subject: [mailinglist-name] [keyword1] Testing.. [name=Bar]
1866 Cc: richard@test.test
1867 Reply-To: chef@bork.bork.bork
1868 Message-Id: <dummy_test_message_id>
1870 ''')
1872         assert not os.path.exists(SENDMAILDEBUG)
1873         self.assertEqual(self.db.keyword.get('1', 'name'), 'Bar')
1875     def testUnknownPrefixSubject(self):
1876         self.db.keyword.create(name='Foo')
1877         self._handle_mail('''Content-Type: text/plain;
1878   charset="iso-8859-1"
1879 From: Chef <chef@bork.bork.bork>
1880 To: issue_tracker@your.tracker.email.domain.example
1881 Subject: VeryStrangeRe: [keyword1] Testing.. [name=Bar]
1882 Cc: richard@test.test
1883 Reply-To: chef@bork.bork.bork
1884 Message-Id: <dummy_test_message_id>
1886 ''')
1888         assert not os.path.exists(SENDMAILDEBUG)
1889         self.assertEqual(self.db.keyword.get('1', 'name'), 'Bar')
1891     def testIssueidLast(self):
1892         nodeid1 = self.doNewIssue()
1893         nodeid2 = self._handle_mail('''Content-Type: text/plain;
1894   charset="iso-8859-1"
1895 From: mary <mary@test.test>
1896 To: issue_tracker@your.tracker.email.domain.example
1897 Message-Id: <followup_dummy_id>
1898 In-Reply-To: <dummy_test_message_id>
1899 Subject: New title [issue1]
1901 This is a second followup
1902 ''')
1904         assert nodeid1 == nodeid2
1905         self.assertEqual(self.db.issue.get(nodeid2, 'title'), "Testing...")
1907     def testSecurityMessagePermissionContent(self):
1908         id = self.doNewIssue()
1909         issue = self.db.issue.getnode (id)
1910         self.db.security.addRole(name='Nomsg')
1911         self.db.security.addPermissionToRole('Nomsg', 'Email Access')
1912         for cl in 'issue', 'file', 'keyword':
1913             for p in 'View', 'Edit', 'Create':
1914                 self.db.security.addPermissionToRole('Nomsg', p, cl)
1915         self.db.user.set(self.mary_id, roles='Nomsg')
1916         nodeid = self._handle_mail('''Content-Type: text/plain;
1917   charset="iso-8859-1"
1918 From: Chef <chef@bork.bork.bork>
1919 To: issue_tracker@your.tracker.email.domain.example
1920 Message-Id: <dummy_test_message_id>
1921 Subject: [issue%(id)s] Testing... [nosy=+mary]
1923 Just a test reply
1924 '''%locals())
1925         assert os.path.exists(SENDMAILDEBUG)
1926         self.compareMessages(self._get_mail(),
1927 '''FROM: roundup-admin@your.tracker.email.domain.example
1928 TO: chef@bork.bork.bork, richard@test.test
1929 Content-Type: text/plain; charset="utf-8"
1930 Subject: [issue1] Testing...
1931 To: richard@test.test
1932 From: "Bork, Chef" <issue_tracker@your.tracker.email.domain.example>
1933 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1934 MIME-Version: 1.0
1935 Message-Id: <dummy_test_message_id>
1936 X-Roundup-Name: Roundup issue tracker
1937 X-Roundup-Loop: hello
1938 X-Roundup-Issue-Status: chatting
1939 Content-Transfer-Encoding: quoted-printable
1942 Bork, Chef <chef@bork.bork.bork> added the comment:
1944 Just a test reply
1946 ----------
1947 nosy: +mary
1948 status: unread -> chatting
1950 _______________________________________________________________________
1951 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1952 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1953 _______________________________________________________________________
1954 ''')
1957 def test_suite():
1958     suite = unittest.TestSuite()
1959     suite.addTest(unittest.makeSuite(MailgwTestCase))
1960     return suite
1962 if __name__ == '__main__':
1963     runner = unittest.TextTestRunner()
1964     unittest.main(testRunner=runner)
1966 # vim: set filetype=python sts=4 sw=4 et si :