Code

e15e2928585e441f7fc3c6eb08000e3d6e056c6b
[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
30 import memorydb
32 class Message(rfc822.Message):
33     """String-based Message class with equivalence test."""
34     def __init__(self, s):
35         rfc822.Message.__init__(self, StringIO(s.strip()))
37     def __eq__(self, other):
38         return (self.dict == other.dict and
39                 self.fp.read() == other.fp.read())
41 class Tracker(object):
42     def open(self, journaltag):
43         return self.db
45 class DiffHelper:
46     def compareMessages(self, new, old):
47         """Compare messages for semantic equivalence."""
48         new, old = Message(new), Message(old)
50         # all Roundup-generated messages have "Precedence: bulk"
51         old['Precedence'] = 'bulk'
53         # don't try to compare the date
54         del new['date'], old['date']
56         if not new == old:
57             res = []
59             replace = {}
60             for key in new.keys():
61                 if key.startswith('from '):
62                     # skip the unix from line
63                     continue
64                 if key.lower() == 'x-roundup-version':
65                     # version changes constantly, so handle it specially
66                     if new[key] != __version__:
67                         res.append('  %s: %r != %r' % (key, __version__,
68                             new[key]))
69                 elif key.lower() == 'content-type' and 'boundary=' in new[key]:
70                     # handle mime messages
71                     newmime = new[key].split('=',1)[-1].strip('"')
72                     oldmime = old.get(key, '').split('=',1)[-1].strip('"')
73                     replace ['--' + newmime] = '--' + oldmime
74                     replace ['--' + newmime + '--'] = '--' + oldmime + '--'
75                 elif new.get(key, '') != old.get(key, ''):
76                     res.append('  %s: %r != %r' % (key, old.get(key, ''),
77                         new.get(key, '')))
79             body_diff = self.compareStrings(new.fp.read(), old.fp.read(),
80                 replace=replace)
81             if body_diff:
82                 res.append('')
83                 res.extend(body_diff)
85             if res:
86                 res.insert(0, 'Generated message not correct (diff follows, expected vs. actual):')
87                 raise AssertionError, '\n'.join(res)
89     def compareStrings(self, s2, s1, replace={}):
90         '''Note the reversal of s2 and s1 - difflib.SequenceMatcher wants
91            the first to be the "original" but in the calls in this file,
92            the second arg is the original. Ho hum.
93            Do replacements over the replace dict -- used for mime boundary
94         '''
95         l1 = s1.strip().split('\n')
96         l2 = [replace.get(i,i) for i in s2.strip().split('\n')]
97         if l1 == l2:
98             return
99         s = difflib.SequenceMatcher(None, l1, l2)
100         res = []
101         for value, s1s, s1e, s2s, s2e in s.get_opcodes():
102             if value == 'equal':
103                 for i in range(s1s, s1e):
104                     res.append('  %s'%l1[i])
105             elif value == 'delete':
106                 for i in range(s1s, s1e):
107                     res.append('- %s'%l1[i])
108             elif value == 'insert':
109                 for i in range(s2s, s2e):
110                     res.append('+ %s'%l2[i])
111             elif value == 'replace':
112                 for i, j in zip(range(s1s, s1e), range(s2s, s2e)):
113                     res.append('- %s'%l1[i])
114                     res.append('+ %s'%l2[j])
116         return res
118 class MailgwTestCase(unittest.TestCase, DiffHelper):
119     count = 0
120     schema = 'classic'
121     def setUp(self):
122         MailgwTestCase.count = MailgwTestCase.count + 1
124         # and open the database / "instance"
125         self.db = memorydb.create('admin')
126         self.instance = Tracker()
127         self.instance.db = self.db
128         self.instance.config = self.db.config
129         self.instance.MailGW = MailGW
131         self.chef_id = self.db.user.create(username='Chef',
132             address='chef@bork.bork.bork', realname='Bork, Chef', roles='User')
133         self.richard_id = self.db.user.create(username='richard',
134             address='richard@test.test', roles='User')
135         self.mary_id = self.db.user.create(username='mary',
136             address='mary@test.test', roles='User', realname='Contrary, Mary')
137         self.john_id = self.db.user.create(username='john',
138             address='john@test.test', roles='User', realname='John Doe',
139             alternate_addresses='jondoe@test.test\njohn.doe@test.test')
141     def tearDown(self):
142         if os.path.exists(SENDMAILDEBUG):
143             os.remove(SENDMAILDEBUG)
144         self.db.close()
146     def _handle_mail(self, message):
147         handler = self.instance.MailGW(self.instance)
148         handler.trapExceptions = 0
149         return handler.main(StringIO(message))
151     def _get_mail(self):
152         f = open(SENDMAILDEBUG)
153         try:
154             return f.read()
155         finally:
156             f.close()
158     def testEmptyMessage(self):
159         nodeid = self._handle_mail('''Content-Type: text/plain;
160   charset="iso-8859-1"
161 From: Chef <chef@bork.bork.bork>
162 To: issue_tracker@your.tracker.email.domain.example
163 Cc: richard@test.test
164 Reply-To: chef@bork.bork.bork
165 Message-Id: <dummy_test_message_id>
166 Subject: [issue] Testing...
168 ''')
169         assert not os.path.exists(SENDMAILDEBUG)
170         self.assertEqual(self.db.issue.get(nodeid, 'title'), 'Testing...')
172     def testMessageWithFromInIt(self):
173         nodeid = self._handle_mail('''Content-Type: text/plain;
174   charset="iso-8859-1"
175 From: Chef <chef@bork.bork.bork>
176 To: issue_tracker@your.tracker.email.domain.example
177 Cc: richard@test.test
178 Reply-To: chef@bork.bork.bork
179 Message-Id: <dummy_test_message_id>
180 Subject: [issue] Testing...
182 From here to there!
183 ''')
184         assert not os.path.exists(SENDMAILDEBUG)
185         msgid = self.db.issue.get(nodeid, 'msg')[0]
186         self.assertEqual(self.db.issue.get(msgid, 'content'), 'From here to there!')
188     def doNewIssue(self):
189         nodeid = self._handle_mail('''Content-Type: text/plain;
190   charset="iso-8859-1"
191 From: Chef <chef@bork.bork.bork>
192 To: issue_tracker@your.tracker.email.domain.example
193 Cc: richard@test.test
194 Message-Id: <dummy_test_message_id>
195 Subject: [issue] Testing...
197 This is a test submission of a new issue.
198 ''')
199         assert not os.path.exists(SENDMAILDEBUG)
200         l = self.db.issue.get(nodeid, 'nosy')
201         l.sort()
202         self.assertEqual(l, [self.chef_id, self.richard_id])
203         return nodeid
205     def testNewIssue(self):
206         self.doNewIssue()
208     def testNewIssueNosy(self):
209         self.instance.config.ADD_AUTHOR_TO_NOSY = 'yes'
210         nodeid = self._handle_mail('''Content-Type: text/plain;
211   charset="iso-8859-1"
212 From: Chef <chef@bork.bork.bork>
213 To: issue_tracker@your.tracker.email.domain.example
214 Cc: richard@test.test
215 Message-Id: <dummy_test_message_id>
216 Subject: [issue] Testing...
218 This is a test submission of a new issue.
219 ''')
220         assert not os.path.exists(SENDMAILDEBUG)
221         l = self.db.issue.get(nodeid, 'nosy')
222         l.sort()
223         self.assertEqual(l, [self.chef_id, self.richard_id])
225     def testAlternateAddress(self):
226         self._handle_mail('''Content-Type: text/plain;
227   charset="iso-8859-1"
228 From: John Doe <john.doe@test.test>
229 To: issue_tracker@your.tracker.email.domain.example
230 Message-Id: <dummy_test_message_id>
231 Subject: [issue] Testing...
233 This is a test submission of a new issue.
234 ''')
235         userlist = self.db.user.list()
236         assert not os.path.exists(SENDMAILDEBUG)
237         self.assertEqual(userlist, self.db.user.list(),
238             "user created when it shouldn't have been")
240     def testNewIssueNoClass(self):
241         self._handle_mail('''Content-Type: text/plain;
242   charset="iso-8859-1"
243 From: Chef <chef@bork.bork.bork>
244 To: issue_tracker@your.tracker.email.domain.example
245 Cc: richard@test.test
246 Message-Id: <dummy_test_message_id>
247 Subject: Testing...
249 This is a test submission of a new issue.
250 ''')
251         assert not os.path.exists(SENDMAILDEBUG)
253     def testNewIssueAuthMsg(self):
254         # TODO: fix the damn config - this is apalling
255         self.db.config.MESSAGES_TO_AUTHOR = 'yes'
256         self._handle_mail('''Content-Type: text/plain;
257   charset="iso-8859-1"
258 From: Chef <chef@bork.bork.bork>
259 To: issue_tracker@your.tracker.email.domain.example
260 Message-Id: <dummy_test_message_id>
261 Subject: [issue] Testing... [nosy=mary; assignedto=richard]
263 This is a test submission of a new issue.
264 ''')
265         self.compareMessages(self._get_mail(),
266 '''FROM: roundup-admin@your.tracker.email.domain.example
267 TO: chef@bork.bork.bork, mary@test.test, richard@test.test
268 Content-Type: text/plain; charset="utf-8"
269 Subject: [issue1] Testing...
270 To: chef@bork.bork.bork, mary@test.test, richard@test.test
271 From: "Bork, Chef" <issue_tracker@your.tracker.email.domain.example>
272 Reply-To: Roundup issue tracker
273  <issue_tracker@your.tracker.email.domain.example>
274 MIME-Version: 1.0
275 Message-Id: <dummy_test_message_id>
276 X-Roundup-Name: Roundup issue tracker
277 X-Roundup-Loop: hello
278 X-Roundup-Issue-Status: unread
279 Content-Transfer-Encoding: quoted-printable
282 New submission from Bork, Chef <chef@bork.bork.bork>:
284 This is a test submission of a new issue.
286 ----------
287 assignedto: richard
288 messages: 1
289 nosy: Chef, mary, richard
290 status: unread
291 title: Testing...
293 _______________________________________________________________________
294 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
295 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
296 _______________________________________________________________________
297 ''')
299     def testNewIssueNoAuthorInfo(self):
300         self.db.config.MAIL_ADD_AUTHORINFO = 'no'
301         self._handle_mail('''Content-Type: text/plain;
302   charset="iso-8859-1"
303 From: Chef <chef@bork.bork.bork>
304 To: issue_tracker@your.tracker.email.domain.example
305 Message-Id: <dummy_test_message_id>
306 Subject: [issue] Testing... [nosy=mary; assignedto=richard]
308 This is a test submission of a new issue.
309 ''')
310         self.compareMessages(self._get_mail(),
311 '''FROM: roundup-admin@your.tracker.email.domain.example
312 TO: chef@bork.bork.bork, mary@test.test, richard@test.test
313 Content-Type: text/plain; charset="utf-8"
314 Subject: [issue1] Testing...
315 To: mary@test.test, richard@test.test
316 From: "Bork, Chef" <issue_tracker@your.tracker.email.domain.example>
317 Reply-To: Roundup issue tracker
318  <issue_tracker@your.tracker.email.domain.example>
319 MIME-Version: 1.0
320 Message-Id: <dummy_test_message_id>
321 X-Roundup-Name: Roundup issue tracker
322 X-Roundup-Loop: hello
323 X-Roundup-Issue-Status: unread
324 Content-Transfer-Encoding: quoted-printable
326 This is a test submission of a new issue.
328 ----------
329 assignedto: richard
330 messages: 1
331 nosy: Chef, mary, richard
332 status: unread
333 title: Testing...
335 _______________________________________________________________________
336 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
337 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
338 _______________________________________________________________________
339 ''')
341     def testNewIssueNoAuthorEmail(self):
342         self.db.config.MAIL_ADD_AUTHOREMAIL = 'no'
343         self._handle_mail('''Content-Type: text/plain;
344   charset="iso-8859-1"
345 From: Chef <chef@bork.bork.bork>
346 To: issue_tracker@your.tracker.email.domain.example
347 Message-Id: <dummy_test_message_id>
348 Subject: [issue] Testing... [nosy=mary; assignedto=richard]
350 This is a test submission of a new issue.
351 ''')
352         self.compareMessages(self._get_mail(),
353 '''FROM: roundup-admin@your.tracker.email.domain.example
354 TO: chef@bork.bork.bork, mary@test.test, richard@test.test
355 Content-Type: text/plain; charset="utf-8"
356 Subject: [issue1] Testing...
357 To: mary@test.test, richard@test.test
358 From: "Bork, Chef" <issue_tracker@your.tracker.email.domain.example>
359 Reply-To: Roundup issue tracker
360  <issue_tracker@your.tracker.email.domain.example>
361 MIME-Version: 1.0
362 Message-Id: <dummy_test_message_id>
363 X-Roundup-Name: Roundup issue tracker
364 X-Roundup-Loop: hello
365 X-Roundup-Issue-Status: unread
366 Content-Transfer-Encoding: quoted-printable
368 New submission from Bork, Chef:
370 This is a test submission of a new issue.
372 ----------
373 assignedto: richard
374 messages: 1
375 nosy: Chef, mary, richard
376 status: unread
377 title: Testing...
379 _______________________________________________________________________
380 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
381 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
382 _______________________________________________________________________
383 ''')
385     multipart_msg = '''From: mary <mary@test.test>
386 To: issue_tracker@your.tracker.email.domain.example
387 Message-Id: <followup_dummy_id>
388 In-Reply-To: <dummy_test_message_id>
389 Subject: [issue1] Testing...
390 Content-Type: multipart/mixed; boundary="bxyzzy"
391 Content-Disposition: inline
394 --bxyzzy
395 Content-Type: multipart/alternative; boundary="bCsyhTFzCvuiizWE"
396 Content-Disposition: inline
398 --bCsyhTFzCvuiizWE
399 Content-Type: text/plain; charset=us-ascii
400 Content-Disposition: inline
402 test attachment first text/plain
404 --bCsyhTFzCvuiizWE
405 Content-Type: application/octet-stream
406 Content-Disposition: attachment; filename="first.dvi"
407 Content-Transfer-Encoding: base64
409 SnVzdCBhIHRlc3QgAQo=
411 --bCsyhTFzCvuiizWE
412 Content-Type: text/plain; charset=us-ascii
413 Content-Disposition: inline
415 test attachment second text/plain
417 --bCsyhTFzCvuiizWE
418 Content-Type: text/html
419 Content-Disposition: inline
421 <html>
422 to be ignored.
423 </html>
425 --bCsyhTFzCvuiizWE--
427 --bxyzzy
428 Content-Type: multipart/alternative; boundary="bCsyhTFzCvuiizWF"
429 Content-Disposition: inline
431 --bCsyhTFzCvuiizWF
432 Content-Type: text/plain; charset=us-ascii
433 Content-Disposition: inline
435 test attachment third text/plain
437 --bCsyhTFzCvuiizWF
438 Content-Type: application/octet-stream
439 Content-Disposition: attachment; filename="second.dvi"
440 Content-Transfer-Encoding: base64
442 SnVzdCBhIHRlc3QK
444 --bCsyhTFzCvuiizWF--
446 --bxyzzy--
447 '''
449     def testMultipartKeepAlternatives(self):
450         self.doNewIssue()
451         self._handle_mail(self.multipart_msg)
452         messages = self.db.issue.get('1', 'messages')
453         messages.sort()
454         msg = self.db.msg.getnode (messages[-1])
455         assert(len(msg.files) == 5)
456         names = {0 : 'first.dvi', 4 : 'second.dvi'}
457         content = {3 : 'test attachment third text/plain\n',
458                    4 : 'Just a test\n'}
459         for n, id in enumerate (msg.files):
460             f = self.db.file.getnode (id)
461             self.assertEqual(f.name, names.get (n, 'unnamed'))
462             if n in content :
463                 self.assertEqual(f.content, content [n])
464         self.assertEqual(msg.content, 'test attachment second text/plain')
466     def testMultipartDropAlternatives(self):
467         self.doNewIssue()
468         self.db.config.MAILGW_IGNORE_ALTERNATIVES = True
469         self._handle_mail(self.multipart_msg)
470         messages = self.db.issue.get('1', 'messages')
471         messages.sort()
472         msg = self.db.msg.getnode (messages[-1])
473         assert(len(msg.files) == 2)
474         names = {1 : 'second.dvi'}
475         content = {0 : 'test attachment third text/plain\n',
476                    1 : 'Just a test\n'}
477         for n, id in enumerate (msg.files):
478             f = self.db.file.getnode (id)
479             self.assertEqual(f.name, names.get (n, 'unnamed'))
480             if n in content :
481                 self.assertEqual(f.content, content [n])
482         self.assertEqual(msg.content, 'test attachment second text/plain')
484     def testSimpleFollowup(self):
485         self.doNewIssue()
486         self._handle_mail('''Content-Type: text/plain;
487   charset="iso-8859-1"
488 From: mary <mary@test.test>
489 To: issue_tracker@your.tracker.email.domain.example
490 Message-Id: <followup_dummy_id>
491 In-Reply-To: <dummy_test_message_id>
492 Subject: [issue1] Testing...
494 This is a second followup
495 ''')
496         self.compareMessages(self._get_mail(),
497 '''FROM: roundup-admin@your.tracker.email.domain.example
498 TO: chef@bork.bork.bork, richard@test.test
499 Content-Type: text/plain; charset="utf-8"
500 Subject: [issue1] Testing...
501 To: chef@bork.bork.bork, richard@test.test
502 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
503 Reply-To: Roundup issue tracker
504  <issue_tracker@your.tracker.email.domain.example>
505 MIME-Version: 1.0
506 Message-Id: <followup_dummy_id>
507 In-Reply-To: <dummy_test_message_id>
508 X-Roundup-Name: Roundup issue tracker
509 X-Roundup-Loop: hello
510 X-Roundup-Issue-Status: chatting
511 Content-Transfer-Encoding: quoted-printable
514 Contrary, Mary <mary@test.test> added the comment:
516 This is a second followup
518 ----------
519 status: unread -> chatting
521 _______________________________________________________________________
522 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
523 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
524 _______________________________________________________________________
525 ''')
527     def testFollowup(self):
528         self.doNewIssue()
530         self._handle_mail('''Content-Type: text/plain;
531   charset="iso-8859-1"
532 From: richard <richard@test.test>
533 To: issue_tracker@your.tracker.email.domain.example
534 Message-Id: <followup_dummy_id>
535 In-Reply-To: <dummy_test_message_id>
536 Subject: [issue1] Testing... [assignedto=mary; nosy=+john]
538 This is a followup
539 ''')
540         l = self.db.issue.get('1', 'nosy')
541         l.sort()
542         self.assertEqual(l, [self.chef_id, self.richard_id, self.mary_id,
543             self.john_id])
545         self.compareMessages(self._get_mail(),
546 '''FROM: roundup-admin@your.tracker.email.domain.example
547 TO: chef@bork.bork.bork, john@test.test, mary@test.test
548 Content-Type: text/plain; charset="utf-8"
549 Subject: [issue1] Testing...
550 To: chef@bork.bork.bork, john@test.test, mary@test.test
551 From: richard <issue_tracker@your.tracker.email.domain.example>
552 Reply-To: Roundup issue tracker
553  <issue_tracker@your.tracker.email.domain.example>
554 MIME-Version: 1.0
555 Message-Id: <followup_dummy_id>
556 In-Reply-To: <dummy_test_message_id>
557 X-Roundup-Name: Roundup issue tracker
558 X-Roundup-Loop: hello
559 X-Roundup-Issue-Status: chatting
560 Content-Transfer-Encoding: quoted-printable
563 richard <richard@test.test> added the comment:
565 This is a followup
567 ----------
568 assignedto:  -> mary
569 nosy: +john, mary
570 status: unread -> chatting
572 _______________________________________________________________________
573 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
574 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
575 _______________________________________________________________________
576 ''')
578     def testPropertyChangeOnly(self):
579         self.doNewIssue()
580         oldvalues = self.db.getnode('issue', '1').copy()
581         oldvalues['assignedto'] = None
582         # reconstruct old behaviour: This would reuse the
583         # database-handle from the doNewIssue above which has committed
584         # as user "Chef". So we close and reopen the db as that user.
585         self.db.close()
586         self.db = self.instance.open('Chef')
587         self.db.issue.set('1', assignedto=self.chef_id)
588         self.db.commit()
589         self.db.issue.nosymessage('1', None, oldvalues)
591         new_mail = ""
592         for line in self._get_mail().split("\n"):
593             if "Message-Id: " in line:
594                 continue
595             if "Date: " in line:
596                 continue
597             new_mail += line+"\n"
599         self.compareMessages(new_mail, """
600 FROM: roundup-admin@your.tracker.email.domain.example
601 TO: chef@bork.bork.bork, richard@test.test
602 Content-Type: text/plain; charset="utf-8"
603 Subject: [issue1] Testing...
604 To: chef@bork.bork.bork, richard@test.test
605 From: "Bork, Chef" <issue_tracker@your.tracker.email.domain.example>
606 X-Roundup-Name: Roundup issue tracker
607 X-Roundup-Loop: hello
608 X-Roundup-Issue-Status: unread
609 X-Roundup-Version: 1.3.3
610 MIME-Version: 1.0
611 Reply-To: Roundup issue tracker
612  <issue_tracker@your.tracker.email.domain.example>
613 Content-Transfer-Encoding: quoted-printable
616 Change by Bork, Chef <chef@bork.bork.bork>:
619 ----------
620 assignedto:  -> Chef
622 _______________________________________________________________________
623 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
624 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
625 _______________________________________________________________________
626 """)
629     #
630     # FOLLOWUP TITLE MATCH
631     #
632     def testFollowupTitleMatch(self):
633         self.doNewIssue()
634         self._handle_mail('''Content-Type: text/plain;
635   charset="iso-8859-1"
636 From: richard <richard@test.test>
637 To: issue_tracker@your.tracker.email.domain.example
638 Message-Id: <followup_dummy_id>
639 Subject: Re: Testing... [assignedto=mary; nosy=+john]
641 This is a followup
642 ''')
643         self.compareMessages(self._get_mail(),
644 '''FROM: roundup-admin@your.tracker.email.domain.example
645 TO: chef@bork.bork.bork, john@test.test, mary@test.test
646 Content-Type: text/plain; charset="utf-8"
647 Subject: [issue1] Testing...
648 To: chef@bork.bork.bork, john@test.test, mary@test.test
649 From: richard <issue_tracker@your.tracker.email.domain.example>
650 Reply-To: Roundup issue tracker
651  <issue_tracker@your.tracker.email.domain.example>
652 MIME-Version: 1.0
653 Message-Id: <followup_dummy_id>
654 In-Reply-To: <dummy_test_message_id>
655 X-Roundup-Name: Roundup issue tracker
656 X-Roundup-Loop: hello
657 X-Roundup-Issue-Status: chatting
658 Content-Transfer-Encoding: quoted-printable
661 richard <richard@test.test> added the comment:
663 This is a followup
665 ----------
666 assignedto:  -> mary
667 nosy: +john, mary
668 status: unread -> chatting
670 _______________________________________________________________________
671 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
672 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
673 _______________________________________________________________________
674 ''')
676     def testFollowupTitleMatchMultiRe(self):
677         nodeid1 = self.doNewIssue()
678         nodeid2 = self._handle_mail('''Content-Type: text/plain;
679   charset="iso-8859-1"
680 From: richard <richard@test.test>
681 To: issue_tracker@your.tracker.email.domain.example
682 Message-Id: <followup_dummy_id>
683 Subject: Re: Testing... [assignedto=mary; nosy=+john]
685 This is a followup
686 ''')
688         nodeid3 = self._handle_mail('''Content-Type: text/plain;
689   charset="iso-8859-1"
690 From: richard <richard@test.test>
691 To: issue_tracker@your.tracker.email.domain.example
692 Message-Id: <followup2_dummy_id>
693 Subject: Ang: Re: Testing...
695 This is a followup
696 ''')
697         self.assertEqual(nodeid1, nodeid2)
698         self.assertEqual(nodeid1, nodeid3)
700     def testFollowupTitleMatchNever(self):
701         nodeid = self.doNewIssue()
702         self.db.config.MAILGW_SUBJECT_CONTENT_MATCH = 'never'
703         self.assertNotEqual(self._handle_mail('''Content-Type: text/plain;
704   charset="iso-8859-1"
705 From: richard <richard@test.test>
706 To: issue_tracker@your.tracker.email.domain.example
707 Message-Id: <followup_dummy_id>
708 Subject: Re: Testing...
710 This is a followup
711 '''), nodeid)
713     def testFollowupTitleMatchNeverInterval(self):
714         nodeid = self.doNewIssue()
715         # force failure of the interval
716         time.sleep(2)
717         self.db.config.MAILGW_SUBJECT_CONTENT_MATCH = 'creation 00:00:01'
718         self.assertNotEqual(self._handle_mail('''Content-Type: text/plain;
719   charset="iso-8859-1"
720 From: richard <richard@test.test>
721 To: issue_tracker@your.tracker.email.domain.example
722 Message-Id: <followup_dummy_id>
723 Subject: Re: Testing...
725 This is a followup
726 '''), nodeid)
729     def testFollowupTitleMatchInterval(self):
730         nodeid = self.doNewIssue()
731         self.db.config.MAILGW_SUBJECT_CONTENT_MATCH = 'creation +1d'
732         self.assertEqual(self._handle_mail('''Content-Type: text/plain;
733   charset="iso-8859-1"
734 From: richard <richard@test.test>
735 To: issue_tracker@your.tracker.email.domain.example
736 Message-Id: <followup_dummy_id>
737 Subject: Re: Testing...
739 This is a followup
740 '''), nodeid)
743     def testFollowupNosyAuthor(self):
744         self.doNewIssue()
745         self.db.config.ADD_AUTHOR_TO_NOSY = 'yes'
746         self._handle_mail('''Content-Type: text/plain;
747   charset="iso-8859-1"
748 From: john@test.test
749 To: issue_tracker@your.tracker.email.domain.example
750 Message-Id: <followup_dummy_id>
751 In-Reply-To: <dummy_test_message_id>
752 Subject: [issue1] Testing...
754 This is a followup
755 ''')
757         self.compareMessages(self._get_mail(),
758 '''FROM: roundup-admin@your.tracker.email.domain.example
759 TO: chef@bork.bork.bork, richard@test.test
760 Content-Type: text/plain; charset="utf-8"
761 Subject: [issue1] Testing...
762 To: chef@bork.bork.bork, richard@test.test
763 From: John Doe <issue_tracker@your.tracker.email.domain.example>
764 Reply-To: Roundup issue tracker
765  <issue_tracker@your.tracker.email.domain.example>
766 MIME-Version: 1.0
767 Message-Id: <followup_dummy_id>
768 In-Reply-To: <dummy_test_message_id>
769 X-Roundup-Name: Roundup issue tracker
770 X-Roundup-Loop: hello
771 X-Roundup-Issue-Status: chatting
772 Content-Transfer-Encoding: quoted-printable
775 John Doe <john@test.test> added the comment:
777 This is a followup
779 ----------
780 nosy: +john
781 status: unread -> chatting
783 _______________________________________________________________________
784 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
785 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
786 _______________________________________________________________________
788 ''')
790     def testFollowupNosyRecipients(self):
791         self.doNewIssue()
792         self.db.config.ADD_RECIPIENTS_TO_NOSY = 'yes'
793         self._handle_mail('''Content-Type: text/plain;
794   charset="iso-8859-1"
795 From: richard@test.test
796 To: issue_tracker@your.tracker.email.domain.example
797 Cc: john@test.test
798 Message-Id: <followup_dummy_id>
799 In-Reply-To: <dummy_test_message_id>
800 Subject: [issue1] Testing...
802 This is a followup
803 ''')
804         self.compareMessages(self._get_mail(),
805 '''FROM: roundup-admin@your.tracker.email.domain.example
806 TO: chef@bork.bork.bork
807 Content-Type: text/plain; charset="utf-8"
808 Subject: [issue1] Testing...
809 To: chef@bork.bork.bork
810 From: richard <issue_tracker@your.tracker.email.domain.example>
811 Reply-To: Roundup issue tracker
812  <issue_tracker@your.tracker.email.domain.example>
813 MIME-Version: 1.0
814 Message-Id: <followup_dummy_id>
815 In-Reply-To: <dummy_test_message_id>
816 X-Roundup-Name: Roundup issue tracker
817 X-Roundup-Loop: hello
818 X-Roundup-Issue-Status: chatting
819 Content-Transfer-Encoding: quoted-printable
822 richard <richard@test.test> added the comment:
824 This is a followup
826 ----------
827 nosy: +john
828 status: unread -> chatting
830 _______________________________________________________________________
831 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
832 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
833 _______________________________________________________________________
835 ''')
837     def testFollowupNosyAuthorAndCopy(self):
838         self.doNewIssue()
839         self.db.config.ADD_AUTHOR_TO_NOSY = 'yes'
840         self.db.config.MESSAGES_TO_AUTHOR = 'yes'
841         self._handle_mail('''Content-Type: text/plain;
842   charset="iso-8859-1"
843 From: john@test.test
844 To: issue_tracker@your.tracker.email.domain.example
845 Message-Id: <followup_dummy_id>
846 In-Reply-To: <dummy_test_message_id>
847 Subject: [issue1] Testing...
849 This is a followup
850 ''')
851         self.compareMessages(self._get_mail(),
852 '''FROM: roundup-admin@your.tracker.email.domain.example
853 TO: chef@bork.bork.bork, john@test.test, richard@test.test
854 Content-Type: text/plain; charset="utf-8"
855 Subject: [issue1] Testing...
856 To: chef@bork.bork.bork, john@test.test, richard@test.test
857 From: John Doe <issue_tracker@your.tracker.email.domain.example>
858 Reply-To: Roundup issue tracker
859  <issue_tracker@your.tracker.email.domain.example>
860 MIME-Version: 1.0
861 Message-Id: <followup_dummy_id>
862 In-Reply-To: <dummy_test_message_id>
863 X-Roundup-Name: Roundup issue tracker
864 X-Roundup-Loop: hello
865 X-Roundup-Issue-Status: chatting
866 Content-Transfer-Encoding: quoted-printable
869 John Doe <john@test.test> added the comment:
871 This is a followup
873 ----------
874 nosy: +john
875 status: unread -> chatting
877 _______________________________________________________________________
878 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
879 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
880 _______________________________________________________________________
882 ''')
884     def testFollowupNoNosyAuthor(self):
885         self.doNewIssue()
886         self.instance.config.ADD_AUTHOR_TO_NOSY = 'no'
887         self._handle_mail('''Content-Type: text/plain;
888   charset="iso-8859-1"
889 From: john@test.test
890 To: issue_tracker@your.tracker.email.domain.example
891 Message-Id: <followup_dummy_id>
892 In-Reply-To: <dummy_test_message_id>
893 Subject: [issue1] Testing...
895 This is a followup
896 ''')
897         self.compareMessages(self._get_mail(),
898 '''FROM: roundup-admin@your.tracker.email.domain.example
899 TO: chef@bork.bork.bork, richard@test.test
900 Content-Type: text/plain; charset="utf-8"
901 Subject: [issue1] Testing...
902 To: chef@bork.bork.bork, richard@test.test
903 From: John Doe <issue_tracker@your.tracker.email.domain.example>
904 Reply-To: Roundup issue tracker
905  <issue_tracker@your.tracker.email.domain.example>
906 MIME-Version: 1.0
907 Message-Id: <followup_dummy_id>
908 In-Reply-To: <dummy_test_message_id>
909 X-Roundup-Name: Roundup issue tracker
910 X-Roundup-Loop: hello
911 X-Roundup-Issue-Status: chatting
912 Content-Transfer-Encoding: quoted-printable
915 John Doe <john@test.test> added the comment:
917 This is a followup
919 ----------
920 status: unread -> chatting
922 _______________________________________________________________________
923 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
924 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
925 _______________________________________________________________________
927 ''')
929     def testFollowupNoNosyRecipients(self):
930         self.doNewIssue()
931         self.instance.config.ADD_RECIPIENTS_TO_NOSY = 'no'
932         self._handle_mail('''Content-Type: text/plain;
933   charset="iso-8859-1"
934 From: richard@test.test
935 To: issue_tracker@your.tracker.email.domain.example
936 Cc: john@test.test
937 Message-Id: <followup_dummy_id>
938 In-Reply-To: <dummy_test_message_id>
939 Subject: [issue1] Testing...
941 This is a followup
942 ''')
943         self.compareMessages(self._get_mail(),
944 '''FROM: roundup-admin@your.tracker.email.domain.example
945 TO: chef@bork.bork.bork
946 Content-Type: text/plain; charset="utf-8"
947 Subject: [issue1] Testing...
948 To: chef@bork.bork.bork
949 From: richard <issue_tracker@your.tracker.email.domain.example>
950 Reply-To: Roundup issue tracker
951  <issue_tracker@your.tracker.email.domain.example>
952 MIME-Version: 1.0
953 Message-Id: <followup_dummy_id>
954 In-Reply-To: <dummy_test_message_id>
955 X-Roundup-Name: Roundup issue tracker
956 X-Roundup-Loop: hello
957 X-Roundup-Issue-Status: chatting
958 Content-Transfer-Encoding: quoted-printable
961 richard <richard@test.test> added the comment:
963 This is a followup
965 ----------
966 status: unread -> chatting
968 _______________________________________________________________________
969 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
970 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
971 _______________________________________________________________________
973 ''')
975     def testFollowupEmptyMessage(self):
976         self.doNewIssue()
978         self._handle_mail('''Content-Type: text/plain;
979   charset="iso-8859-1"
980 From: richard <richard@test.test>
981 To: issue_tracker@your.tracker.email.domain.example
982 Message-Id: <followup_dummy_id>
983 In-Reply-To: <dummy_test_message_id>
984 Subject: [issue1] Testing... [assignedto=mary; nosy=+john]
986 ''')
987         l = self.db.issue.get('1', 'nosy')
988         l.sort()
989         self.assertEqual(l, [self.chef_id, self.richard_id, self.mary_id,
990             self.john_id])
992         # should be no file created (ie. no message)
993         assert not os.path.exists(SENDMAILDEBUG)
995     def testFollowupEmptyMessageNoSubject(self):
996         self.doNewIssue()
998         self._handle_mail('''Content-Type: text/plain;
999   charset="iso-8859-1"
1000 From: richard <richard@test.test>
1001 To: issue_tracker@your.tracker.email.domain.example
1002 Message-Id: <followup_dummy_id>
1003 In-Reply-To: <dummy_test_message_id>
1004 Subject: [issue1] [assignedto=mary; nosy=+john]
1006 ''')
1007         l = self.db.issue.get('1', 'nosy')
1008         l.sort()
1009         self.assertEqual(l, [self.chef_id, self.richard_id, self.mary_id,
1010             self.john_id])
1012         # should be no file created (ie. no message)
1013         assert not os.path.exists(SENDMAILDEBUG)
1015     def testNosyRemove(self):
1016         self.doNewIssue()
1018         self._handle_mail('''Content-Type: text/plain;
1019   charset="iso-8859-1"
1020 From: richard <richard@test.test>
1021 To: issue_tracker@your.tracker.email.domain.example
1022 Message-Id: <followup_dummy_id>
1023 In-Reply-To: <dummy_test_message_id>
1024 Subject: [issue1] Testing... [nosy=-richard]
1026 ''')
1027         l = self.db.issue.get('1', 'nosy')
1028         l.sort()
1029         self.assertEqual(l, [self.chef_id])
1031         # NO NOSY MESSAGE SHOULD BE SENT!
1032         assert not os.path.exists(SENDMAILDEBUG)
1034     def testNewUserAuthor(self):
1035         l = self.db.user.list()
1036         l.sort()
1037         message = '''Content-Type: text/plain;
1038   charset="iso-8859-1"
1039 From: fubar <fubar@bork.bork.bork>
1040 To: issue_tracker@your.tracker.email.domain.example
1041 Message-Id: <dummy_test_message_id>
1042 Subject: [issue] Testing...
1044 This is a test submission of a new issue.
1045 '''
1046         self.db.security.role['anonymous'].permissions=[]
1047         anonid = self.db.user.lookup('anonymous')
1048         self.db.user.set(anonid, roles='Anonymous')
1049         try:
1050             self._handle_mail(message)
1051         except Unauthorized, value:
1052             body_diff = self.compareMessages(str(value), """
1053 You are not a registered user.
1055 Unknown address: fubar@bork.bork.bork
1056 """)
1057             assert not body_diff, body_diff
1058         else:
1059             raise AssertionError, "Unathorized not raised when handling mail"
1061         # Add Web Access role to anonymous, and try again to make sure
1062         # we get a "please register at:" message this time.
1063         p = [
1064             self.db.security.getPermission('Register', 'user'),
1065             self.db.security.getPermission('Web Access', None),
1066         ]
1067         self.db.security.role['anonymous'].permissions=p
1068         try:
1069             self._handle_mail(message)
1070         except Unauthorized, value:
1071             body_diff = self.compareMessages(str(value), """
1072 You are not a registered user. Please register at:
1074 http://tracker.example/cgi-bin/roundup.cgi/bugs/user?template=register
1076 ...before sending mail to the tracker.
1078 Unknown address: fubar@bork.bork.bork
1079 """)
1080             assert not body_diff, body_diff
1081         else:
1082             raise AssertionError, "Unathorized not raised when handling mail"
1084         # Make sure list of users is the same as before.
1085         m = self.db.user.list()
1086         m.sort()
1087         self.assertEqual(l, m)
1089         # now with the permission
1090         p = [
1091             self.db.security.getPermission('Register', 'user'),
1092             self.db.security.getPermission('Email Access', None),
1093         ]
1094         self.db.security.role['anonymous'].permissions=p
1095         self._handle_mail(message)
1096         m = self.db.user.list()
1097         m.sort()
1098         self.assertNotEqual(l, m)
1100     def testNewUserAuthorEncodedName(self):
1101         l = set(self.db.user.list())
1102         # From: name has Euro symbol in it
1103         message = '''Content-Type: text/plain;
1104   charset="iso-8859-1"
1105 From: =?utf8?b?SOKCrGxsbw==?= <fubar@bork.bork.bork>
1106 To: issue_tracker@your.tracker.email.domain.example
1107 Message-Id: <dummy_test_message_id>
1108 Subject: [issue] Testing...
1110 This is a test submission of a new issue.
1111 '''
1112         p = [
1113             self.db.security.getPermission('Register', 'user'),
1114             self.db.security.getPermission('Email Access', None),
1115             self.db.security.getPermission('Create', 'issue'),
1116             self.db.security.getPermission('Create', 'msg'),
1117         ]
1118         self.db.security.role['anonymous'].permissions = p
1119         self._handle_mail(message)
1120         m = set(self.db.user.list())
1121         new = list(m - l)[0]
1122         name = self.db.user.get(new, 'realname')
1123         self.assertEquals(name, 'H€llo')
1125     def testUnknownUser(self):
1126         l = set(self.db.user.list())
1127         message = '''Content-Type: text/plain;
1128   charset="iso-8859-1"
1129 From: Nonexisting User <nonexisting@bork.bork.bork>
1130 To: issue_tracker@your.tracker.email.domain.example
1131 Message-Id: <dummy_test_message_id>
1132 Subject: [issue] Testing nonexisting user...
1134 This is a test submission of a new issue.
1135 '''
1136         self.db.close()
1137         handler = self.instance.MailGW(self.instance)
1138         # we want a bounce message:
1139         handler.trapExceptions = 1
1140         ret = handler.main(StringIO(message))
1141         self.compareMessages(self._get_mail(),
1142 '''FROM: Roundup issue tracker <roundup-admin@your.tracker.email.domain.example>
1143 TO: nonexisting@bork.bork.bork
1144 From nobody Tue Jul 14 12:04:11 2009
1145 Content-Type: multipart/mixed; boundary="===============0639262320=="
1146 MIME-Version: 1.0
1147 Subject: Failed issue tracker submission
1148 To: nonexisting@bork.bork.bork
1149 From: Roundup issue tracker <roundup-admin@your.tracker.email.domain.example>
1150 Date: Tue, 14 Jul 2009 12:04:11 +0000
1151 Precedence: bulk
1152 X-Roundup-Name: Roundup issue tracker
1153 X-Roundup-Loop: hello
1154 X-Roundup-Version: 1.4.8
1155 MIME-Version: 1.0
1157 --===============0639262320==
1158 Content-Type: text/plain; charset="us-ascii"
1159 MIME-Version: 1.0
1160 Content-Transfer-Encoding: 7bit
1164 You are not a registered user. Please register at:
1166 http://tracker.example/cgi-bin/roundup.cgi/bugs/user?template=register
1168 ...before sending mail to the tracker.
1170 Unknown address: nonexisting@bork.bork.bork
1172 --===============0639262320==
1173 Content-Type: text/plain; charset="us-ascii"
1174 MIME-Version: 1.0
1175 Content-Transfer-Encoding: 7bit
1177 Content-Type: text/plain;
1178   charset="iso-8859-1"
1179 From: Nonexisting User <nonexisting@bork.bork.bork>
1180 To: issue_tracker@your.tracker.email.domain.example
1181 Message-Id: <dummy_test_message_id>
1182 Subject: [issue] Testing nonexisting user...
1184 This is a test submission of a new issue.
1186 --===============0639262320==--
1187 ''')
1189     def testEnc01(self):
1190         self.db.user.set(self.mary_id,
1191             realname='\xe4\xf6\xfc\xc4\xd6\xdc\xdf, Mary'.decode
1192             ('latin-1').encode('utf-8'))
1193         self.doNewIssue()
1194         self._handle_mail('''Content-Type: text/plain;
1195   charset="iso-8859-1"
1196 From: mary <mary@test.test>
1197 To: issue_tracker@your.tracker.email.domain.example
1198 Message-Id: <followup_dummy_id>
1199 In-Reply-To: <dummy_test_message_id>
1200 Subject: [issue1] Testing...
1201 Content-Type: text/plain;
1202         charset="iso-8859-1"
1203 Content-Transfer-Encoding: quoted-printable
1205 A message with encoding (encoded oe =F6)
1207 ''')
1208         self.compareMessages(self._get_mail(),
1209 '''FROM: roundup-admin@your.tracker.email.domain.example
1210 TO: chef@bork.bork.bork, richard@test.test
1211 Content-Type: text/plain; charset="utf-8"
1212 Subject: [issue1] Testing...
1213 To: chef@bork.bork.bork, richard@test.test
1214 From: =?utf-8?b?w6TDtsO8w4TDlsOcw58sIE1hcnk=?=
1215  <issue_tracker@your.tracker.email.domain.example>
1216 Reply-To: Roundup issue tracker
1217  <issue_tracker@your.tracker.email.domain.example>
1218 MIME-Version: 1.0
1219 Message-Id: <followup_dummy_id>
1220 In-Reply-To: <dummy_test_message_id>
1221 X-Roundup-Name: Roundup issue tracker
1222 X-Roundup-Loop: hello
1223 X-Roundup-Issue-Status: chatting
1224 Content-Transfer-Encoding: quoted-printable
1227 =C3=A4=C3=B6=C3=BC=C3=84=C3=96=C3=9C=C3=9F, Mary <mary@test.test> added the=
1228  comment:
1230 A message with encoding (encoded oe =C3=B6)
1232 ----------
1233 status: unread -> chatting
1235 _______________________________________________________________________
1236 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1237 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1238 _______________________________________________________________________
1239 ''')
1241     def testEncNonUTF8(self):
1242         self.doNewIssue()
1243         self.instance.config.EMAIL_CHARSET = 'iso-8859-1'
1244         self._handle_mail('''Content-Type: text/plain;
1245   charset="iso-8859-1"
1246 From: mary <mary@test.test>
1247 To: issue_tracker@your.tracker.email.domain.example
1248 Message-Id: <followup_dummy_id>
1249 In-Reply-To: <dummy_test_message_id>
1250 Subject: [issue1] Testing...
1251 Content-Type: text/plain;
1252         charset="iso-8859-1"
1253 Content-Transfer-Encoding: quoted-printable
1255 A message with encoding (encoded oe =F6)
1257 ''')
1258         self.compareMessages(self._get_mail(),
1259 '''FROM: roundup-admin@your.tracker.email.domain.example
1260 TO: chef@bork.bork.bork, richard@test.test
1261 Content-Type: text/plain; charset="iso-8859-1"
1262 Subject: [issue1] Testing...
1263 To: chef@bork.bork.bork, richard@test.test
1264 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
1265 Reply-To: Roundup issue tracker
1266  <issue_tracker@your.tracker.email.domain.example>
1267 MIME-Version: 1.0
1268 Message-Id: <followup_dummy_id>
1269 In-Reply-To: <dummy_test_message_id>
1270 X-Roundup-Name: Roundup issue tracker
1271 X-Roundup-Loop: hello
1272 X-Roundup-Issue-Status: chatting
1273 Content-Transfer-Encoding: quoted-printable
1276 Contrary, Mary <mary@test.test> added the comment:
1278 A message with encoding (encoded oe =F6)
1280 ----------
1281 status: unread -> chatting
1283 _______________________________________________________________________
1284 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1285 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1286 _______________________________________________________________________
1287 ''')
1290     def testMultipartEnc01(self):
1291         self.doNewIssue()
1292         self._handle_mail('''Content-Type: text/plain;
1293   charset="iso-8859-1"
1294 From: mary <mary@test.test>
1295 To: issue_tracker@your.tracker.email.domain.example
1296 Message-Id: <followup_dummy_id>
1297 In-Reply-To: <dummy_test_message_id>
1298 Subject: [issue1] Testing...
1299 Content-Type: multipart/mixed;
1300         boundary="----_=_NextPart_000_01"
1302 This message is in MIME format. Since your mail reader does not understand
1303 this format, some or all of this message may not be legible.
1305 ------_=_NextPart_000_01
1306 Content-Type: text/plain;
1307         charset="iso-8859-1"
1308 Content-Transfer-Encoding: quoted-printable
1310 A message with first part encoded (encoded oe =F6)
1312 ''')
1313         self.compareMessages(self._get_mail(),
1314 '''FROM: roundup-admin@your.tracker.email.domain.example
1315 TO: chef@bork.bork.bork, richard@test.test
1316 Content-Type: text/plain; charset="utf-8"
1317 Subject: [issue1] Testing...
1318 To: chef@bork.bork.bork, richard@test.test
1319 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
1320 Reply-To: Roundup issue tracker
1321  <issue_tracker@your.tracker.email.domain.example>
1322 MIME-Version: 1.0
1323 Message-Id: <followup_dummy_id>
1324 In-Reply-To: <dummy_test_message_id>
1325 X-Roundup-Name: Roundup issue tracker
1326 X-Roundup-Loop: hello
1327 X-Roundup-Issue-Status: chatting
1328 Content-Transfer-Encoding: quoted-printable
1331 Contrary, Mary <mary@test.test> added the comment:
1333 A message with first part encoded (encoded oe =C3=B6)
1335 ----------
1336 status: unread -> chatting
1338 _______________________________________________________________________
1339 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1340 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1341 _______________________________________________________________________
1342 ''')
1344     def testContentDisposition(self):
1345         self.doNewIssue()
1346         self._handle_mail('''Content-Type: text/plain;
1347   charset="iso-8859-1"
1348 From: mary <mary@test.test>
1349 To: issue_tracker@your.tracker.email.domain.example
1350 Message-Id: <followup_dummy_id>
1351 In-Reply-To: <dummy_test_message_id>
1352 Subject: [issue1] Testing...
1353 Content-Type: multipart/mixed; boundary="bCsyhTFzCvuiizWE"
1354 Content-Disposition: inline
1357 --bCsyhTFzCvuiizWE
1358 Content-Type: text/plain; charset=us-ascii
1359 Content-Disposition: inline
1361 test attachment binary
1363 --bCsyhTFzCvuiizWE
1364 Content-Type: application/octet-stream
1365 Content-Disposition: attachment; filename="main.dvi"
1366 Content-Transfer-Encoding: base64
1368 SnVzdCBhIHRlc3QgAQo=
1370 --bCsyhTFzCvuiizWE--
1371 ''')
1372         messages = self.db.issue.get('1', 'messages')
1373         messages.sort()
1374         file = self.db.file.getnode (self.db.msg.get(messages[-1], 'files')[0])
1375         self.assertEqual(file.name, 'main.dvi')
1376         self.assertEqual(file.content, 'Just a test \001\n')
1378     def testFollowupStupidQuoting(self):
1379         self.doNewIssue()
1381         self._handle_mail('''Content-Type: text/plain;
1382   charset="iso-8859-1"
1383 From: richard <richard@test.test>
1384 To: issue_tracker@your.tracker.email.domain.example
1385 Message-Id: <followup_dummy_id>
1386 In-Reply-To: <dummy_test_message_id>
1387 Subject: Re: "[issue1] Testing... "
1389 This is a followup
1390 ''')
1391         self.compareMessages(self._get_mail(),
1392 '''FROM: roundup-admin@your.tracker.email.domain.example
1393 TO: chef@bork.bork.bork
1394 Content-Type: text/plain; charset="utf-8"
1395 Subject: [issue1] Testing...
1396 To: chef@bork.bork.bork
1397 From: richard <issue_tracker@your.tracker.email.domain.example>
1398 Reply-To: Roundup issue tracker
1399  <issue_tracker@your.tracker.email.domain.example>
1400 MIME-Version: 1.0
1401 Message-Id: <followup_dummy_id>
1402 In-Reply-To: <dummy_test_message_id>
1403 X-Roundup-Name: Roundup issue tracker
1404 X-Roundup-Loop: hello
1405 X-Roundup-Issue-Status: chatting
1406 Content-Transfer-Encoding: quoted-printable
1409 richard <richard@test.test> added the comment:
1411 This is a followup
1413 ----------
1414 status: unread -> chatting
1416 _______________________________________________________________________
1417 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1418 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1419 _______________________________________________________________________
1420 ''')
1422     def testEmailQuoting(self):
1423         self.instance.config.EMAIL_KEEP_QUOTED_TEXT = 'no'
1424         self.innerTestQuoting('''This is a followup
1425 ''')
1427     def testEmailQuotingRemove(self):
1428         self.instance.config.EMAIL_KEEP_QUOTED_TEXT = 'yes'
1429         self.innerTestQuoting('''Blah blah wrote:
1430 > Blah bklaskdfj sdf asdf jlaskdf skj sdkfjl asdf
1431 >  skdjlkjsdfalsdkfjasdlfkj dlfksdfalksd fj
1434 This is a followup
1435 ''')
1437     def innerTestQuoting(self, expect):
1438         nodeid = self.doNewIssue()
1440         messages = self.db.issue.get(nodeid, 'messages')
1442         self._handle_mail('''Content-Type: text/plain;
1443   charset="iso-8859-1"
1444 From: richard <richard@test.test>
1445 To: issue_tracker@your.tracker.email.domain.example
1446 Message-Id: <followup_dummy_id>
1447 In-Reply-To: <dummy_test_message_id>
1448 Subject: Re: [issue1] Testing...
1450 Blah blah wrote:
1451 > Blah bklaskdfj sdf asdf jlaskdf skj sdkfjl asdf
1452 >  skdjlkjsdfalsdkfjasdlfkj dlfksdfalksd fj
1455 This is a followup
1456 ''')
1457         # figure the new message id
1458         newmessages = self.db.issue.get(nodeid, 'messages')
1459         for msg in messages:
1460             newmessages.remove(msg)
1461         messageid = newmessages[0]
1463         self.compareMessages(self.db.msg.get(messageid, 'content'), expect)
1465     def testUserLookup(self):
1466         i = self.db.user.create(username='user1', address='user1@foo.com')
1467         self.assertEqual(uidFromAddress(self.db, ('', 'user1@foo.com'), 0), i)
1468         self.assertEqual(uidFromAddress(self.db, ('', 'USER1@foo.com'), 0), i)
1469         i = self.db.user.create(username='user2', address='USER2@foo.com')
1470         self.assertEqual(uidFromAddress(self.db, ('', 'USER2@foo.com'), 0), i)
1471         self.assertEqual(uidFromAddress(self.db, ('', 'user2@foo.com'), 0), i)
1473     def testUserAlternateLookup(self):
1474         i = self.db.user.create(username='user1', address='user1@foo.com',
1475                                 alternate_addresses='user1@bar.com')
1476         self.assertEqual(uidFromAddress(self.db, ('', 'user1@bar.com'), 0), i)
1477         self.assertEqual(uidFromAddress(self.db, ('', 'USER1@bar.com'), 0), i)
1479     def testUserCreate(self):
1480         i = uidFromAddress(self.db, ('', 'user@foo.com'), 1)
1481         self.assertNotEqual(uidFromAddress(self.db, ('', 'user@bar.com'), 1), i)
1483     def testRFC2822(self):
1484         ascii_header = "[issue243] This is a \"test\" - with 'quotation' marks"
1485         unicode_header = '[issue244] \xd0\xb0\xd0\xbd\xd0\xb4\xd1\x80\xd0\xb5\xd0\xb9'
1486         unicode_encoded = '=?utf-8?q?[issue244]_=D0=B0=D0=BD=D0=B4=D1=80=D0=B5=D0=B9?='
1487         self.assertEqual(rfc2822.encode_header(ascii_header), ascii_header)
1488         self.assertEqual(rfc2822.encode_header(unicode_header), unicode_encoded)
1490     def testRegistrationConfirmation(self):
1491         otk = "Aj4euk4LZSAdwePohj90SME5SpopLETL"
1492         self.db.getOTKManager().set(otk, username='johannes')
1493         self._handle_mail('''Content-Type: text/plain;
1494   charset="iso-8859-1"
1495 From: Chef <chef@bork.bork.bork>
1496 To: issue_tracker@your.tracker.email.domain.example
1497 Cc: richard@test.test
1498 Message-Id: <dummy_test_message_id>
1499 Subject: Re: Complete your registration to Roundup issue tracker
1500  -- key %s
1502 This is a test confirmation of registration.
1503 ''' % otk)
1504         self.db.user.lookup('johannes')
1506     def testFollowupOnNonIssue(self):
1507         self.db.keyword.create(name='Foo')
1508         self._handle_mail('''Content-Type: text/plain;
1509   charset="iso-8859-1"
1510 From: richard <richard@test.test>
1511 To: issue_tracker@your.tracker.email.domain.example
1512 Message-Id: <followup_dummy_id>
1513 In-Reply-To: <dummy_test_message_id>
1514 Subject: [keyword1] Testing... [name=Bar]
1516 ''')
1517         self.assertEqual(self.db.keyword.get('1', 'name'), 'Bar')
1519     def testResentFrom(self):
1520         nodeid = self._handle_mail('''Content-Type: text/plain;
1521   charset="iso-8859-1"
1522 From: Chef <chef@bork.bork.bork>
1523 Resent-From: mary <mary@test.test>
1524 To: issue_tracker@your.tracker.email.domain.example
1525 Cc: richard@test.test
1526 Message-Id: <dummy_test_message_id>
1527 Subject: [issue] Testing...
1529 This is a test submission of a new issue.
1530 ''')
1531         assert not os.path.exists(SENDMAILDEBUG)
1532         l = self.db.issue.get(nodeid, 'nosy')
1533         l.sort()
1534         self.assertEqual(l, [self.richard_id, self.mary_id])
1535         return nodeid
1537     def testDejaVu(self):
1538         self.assertRaises(IgnoreLoop, self._handle_mail,
1539             '''Content-Type: text/plain;
1540   charset="iso-8859-1"
1541 From: Chef <chef@bork.bork.bork>
1542 X-Roundup-Loop: hello
1543 To: issue_tracker@your.tracker.email.domain.example
1544 Cc: richard@test.test
1545 Message-Id: <dummy_test_message_id>
1546 Subject: Re: [issue] Testing...
1548 Hi, I've been mis-configured to loop messages back to myself.
1549 ''')
1551     def testItsBulkStupid(self):
1552         self.assertRaises(IgnoreBulk, self._handle_mail,
1553             '''Content-Type: text/plain;
1554   charset="iso-8859-1"
1555 From: Chef <chef@bork.bork.bork>
1556 Precedence: bulk
1557 To: issue_tracker@your.tracker.email.domain.example
1558 Cc: richard@test.test
1559 Message-Id: <dummy_test_message_id>
1560 Subject: Re: [issue] Testing...
1562 Hi, I'm on holidays, and this is a dumb auto-responder.
1563 ''')
1565     def testAutoReplyEmailsAreIgnored(self):
1566         self.assertRaises(IgnoreBulk, self._handle_mail,
1567             '''Content-Type: text/plain;
1568   charset="iso-8859-1"
1569 From: Chef <chef@bork.bork.bork>
1570 To: issue_tracker@your.tracker.email.domain.example
1571 Cc: richard@test.test
1572 Message-Id: <dummy_test_message_id>
1573 Subject: Re: [issue] Out of office AutoReply: Back next week
1575 Hi, I am back in the office next week
1576 ''')
1578     def testNoSubject(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 Cc: richard@test.test
1585 Reply-To: chef@bork.bork.bork
1586 Message-Id: <dummy_test_message_id>
1588 ''')
1590     #
1591     # TEST FOR INVALID DESIGNATOR HANDLING
1592     #
1593     def testInvalidDesignator(self):
1594         self.assertRaises(MailUsageError, self._handle_mail,
1595             '''Content-Type: text/plain;
1596   charset="iso-8859-1"
1597 From: Chef <chef@bork.bork.bork>
1598 To: issue_tracker@your.tracker.email.domain.example
1599 Subject: [frobulated] testing
1600 Cc: richard@test.test
1601 Reply-To: chef@bork.bork.bork
1602 Message-Id: <dummy_test_message_id>
1604 ''')
1605         self.assertRaises(MailUsageError, self._handle_mail,
1606             '''Content-Type: text/plain;
1607   charset="iso-8859-1"
1608 From: Chef <chef@bork.bork.bork>
1609 To: issue_tracker@your.tracker.email.domain.example
1610 Subject: [issue12345] testing
1611 Cc: richard@test.test
1612 Reply-To: chef@bork.bork.bork
1613 Message-Id: <dummy_test_message_id>
1615 ''')
1617     def testInvalidClassLoose(self):
1618         self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'loose'
1619         nodeid = self._handle_mail('''Content-Type: text/plain;
1620   charset="iso-8859-1"
1621 From: Chef <chef@bork.bork.bork>
1622 To: issue_tracker@your.tracker.email.domain.example
1623 Subject: [frobulated] testing
1624 Cc: richard@test.test
1625 Reply-To: chef@bork.bork.bork
1626 Message-Id: <dummy_test_message_id>
1628 ''')
1629         assert not os.path.exists(SENDMAILDEBUG)
1630         self.assertEqual(self.db.issue.get(nodeid, 'title'),
1631             '[frobulated] testing')
1633     def testInvalidClassLooseReply(self):
1634         self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'loose'
1635         nodeid = self._handle_mail('''Content-Type: text/plain;
1636   charset="iso-8859-1"
1637 From: Chef <chef@bork.bork.bork>
1638 To: issue_tracker@your.tracker.email.domain.example
1639 Subject: Re: [frobulated] testing
1640 Cc: richard@test.test
1641 Reply-To: chef@bork.bork.bork
1642 Message-Id: <dummy_test_message_id>
1644 ''')
1645         assert not os.path.exists(SENDMAILDEBUG)
1646         self.assertEqual(self.db.issue.get(nodeid, 'title'),
1647             '[frobulated] testing')
1649     def testInvalidClassLoose(self):
1650         self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'loose'
1651         nodeid = self._handle_mail('''Content-Type: text/plain;
1652   charset="iso-8859-1"
1653 From: Chef <chef@bork.bork.bork>
1654 To: issue_tracker@your.tracker.email.domain.example
1655 Subject: [issue1234] testing
1656 Cc: richard@test.test
1657 Reply-To: chef@bork.bork.bork
1658 Message-Id: <dummy_test_message_id>
1660 ''')
1661         assert not os.path.exists(SENDMAILDEBUG)
1662         self.assertEqual(self.db.issue.get(nodeid, 'title'),
1663             '[issue1234] testing')
1665     def testClassLooseOK(self):
1666         self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'loose'
1667         self.db.keyword.create(name='Foo')
1668         nodeid = self._handle_mail('''Content-Type: text/plain;
1669   charset="iso-8859-1"
1670 From: Chef <chef@bork.bork.bork>
1671 To: issue_tracker@your.tracker.email.domain.example
1672 Subject: [keyword1] Testing... [name=Bar]
1673 Cc: richard@test.test
1674 Reply-To: chef@bork.bork.bork
1675 Message-Id: <dummy_test_message_id>
1677 ''')
1678         assert not os.path.exists(SENDMAILDEBUG)
1679         self.assertEqual(self.db.keyword.get('1', 'name'), 'Bar')
1681     def testClassStrictInvalid(self):
1682         self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'strict'
1683         self.instance.config.MAILGW_DEFAULT_CLASS = ''
1685         message = '''Content-Type: text/plain;
1686   charset="iso-8859-1"
1687 From: Chef <chef@bork.bork.bork>
1688 To: issue_tracker@your.tracker.email.domain.example
1689 Subject: Testing...
1690 Cc: richard@test.test
1691 Reply-To: chef@bork.bork.bork
1692 Message-Id: <dummy_test_message_id>
1694 '''
1695         self.assertRaises(MailUsageError, self._handle_mail, message)
1697     def testClassStrictValid(self):
1698         self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'strict'
1699         self.instance.config.MAILGW_DEFAULT_CLASS = ''
1701         nodeid = self._handle_mail('''Content-Type: text/plain;
1702   charset="iso-8859-1"
1703 From: Chef <chef@bork.bork.bork>
1704 To: issue_tracker@your.tracker.email.domain.example
1705 Subject: [issue] Testing...
1706 Cc: richard@test.test
1707 Reply-To: chef@bork.bork.bork
1708 Message-Id: <dummy_test_message_id>
1710 ''')
1712         assert not os.path.exists(SENDMAILDEBUG)
1713         self.assertEqual(self.db.issue.get(nodeid, 'title'), 'Testing...')
1715     #
1716     # TEST FOR INVALID COMMANDS HANDLING
1717     #
1718     def testInvalidCommands(self):
1719         self.assertRaises(MailUsageError, self._handle_mail,
1720             '''Content-Type: text/plain;
1721   charset="iso-8859-1"
1722 From: Chef <chef@bork.bork.bork>
1723 To: issue_tracker@your.tracker.email.domain.example
1724 Subject: testing [frobulated]
1725 Cc: richard@test.test
1726 Reply-To: chef@bork.bork.bork
1727 Message-Id: <dummy_test_message_id>
1729 ''')
1731     def testInvalidCommandPassthrough(self):
1732         self.instance.config.MAILGW_SUBJECT_SUFFIX_PARSING = 'none'
1733         nodeid = self._handle_mail('''Content-Type: text/plain;
1734   charset="iso-8859-1"
1735 From: Chef <chef@bork.bork.bork>
1736 To: issue_tracker@your.tracker.email.domain.example
1737 Subject: testing [frobulated]
1738 Cc: richard@test.test
1739 Reply-To: chef@bork.bork.bork
1740 Message-Id: <dummy_test_message_id>
1742 ''')
1743         assert not os.path.exists(SENDMAILDEBUG)
1744         self.assertEqual(self.db.issue.get(nodeid, 'title'),
1745             'testing [frobulated]')
1747     def testInvalidCommandPassthroughLoose(self):
1748         self.instance.config.MAILGW_SUBJECT_SUFFIX_PARSING = 'loose'
1749         nodeid = self._handle_mail('''Content-Type: text/plain;
1750   charset="iso-8859-1"
1751 From: Chef <chef@bork.bork.bork>
1752 To: issue_tracker@your.tracker.email.domain.example
1753 Subject: testing [frobulated]
1754 Cc: richard@test.test
1755 Reply-To: chef@bork.bork.bork
1756 Message-Id: <dummy_test_message_id>
1758 ''')
1759         assert not os.path.exists(SENDMAILDEBUG)
1760         self.assertEqual(self.db.issue.get(nodeid, 'title'),
1761             'testing [frobulated]')
1763     def testInvalidCommandPassthroughLooseOK(self):
1764         self.instance.config.MAILGW_SUBJECT_SUFFIX_PARSING = 'loose'
1765         nodeid = self._handle_mail('''Content-Type: text/plain;
1766   charset="iso-8859-1"
1767 From: Chef <chef@bork.bork.bork>
1768 To: issue_tracker@your.tracker.email.domain.example
1769 Subject: testing [assignedto=mary]
1770 Cc: richard@test.test
1771 Reply-To: chef@bork.bork.bork
1772 Message-Id: <dummy_test_message_id>
1774 ''')
1775         assert not os.path.exists(SENDMAILDEBUG)
1776         self.assertEqual(self.db.issue.get(nodeid, 'title'), 'testing')
1777         self.assertEqual(self.db.issue.get(nodeid, 'assignedto'), self.mary_id)
1779     def testCommandDelimiters(self):
1780         self.instance.config.MAILGW_SUBJECT_SUFFIX_DELIMITERS = '{}'
1781         nodeid = self._handle_mail('''Content-Type: text/plain;
1782   charset="iso-8859-1"
1783 From: Chef <chef@bork.bork.bork>
1784 To: issue_tracker@your.tracker.email.domain.example
1785 Subject: testing {assignedto=mary}
1786 Cc: richard@test.test
1787 Reply-To: chef@bork.bork.bork
1788 Message-Id: <dummy_test_message_id>
1790 ''')
1791         assert not os.path.exists(SENDMAILDEBUG)
1792         self.assertEqual(self.db.issue.get(nodeid, 'title'), 'testing')
1793         self.assertEqual(self.db.issue.get(nodeid, 'assignedto'), self.mary_id)
1795     def testPrefixDelimiters(self):
1796         self.instance.config.MAILGW_SUBJECT_SUFFIX_DELIMITERS = '{}'
1797         self.db.keyword.create(name='Foo')
1798         self._handle_mail('''Content-Type: text/plain;
1799   charset="iso-8859-1"
1800 From: richard <richard@test.test>
1801 To: issue_tracker@your.tracker.email.domain.example
1802 Message-Id: <followup_dummy_id>
1803 In-Reply-To: <dummy_test_message_id>
1804 Subject: {keyword1} Testing... {name=Bar}
1806 ''')
1807         assert not os.path.exists(SENDMAILDEBUG)
1808         self.assertEqual(self.db.keyword.get('1', 'name'), 'Bar')
1810     def testCommandDelimitersIgnore(self):
1811         self.instance.config.MAILGW_SUBJECT_SUFFIX_DELIMITERS = '{}'
1812         nodeid = self._handle_mail('''Content-Type: text/plain;
1813   charset="iso-8859-1"
1814 From: Chef <chef@bork.bork.bork>
1815 To: issue_tracker@your.tracker.email.domain.example
1816 Subject: testing [assignedto=mary]
1817 Cc: richard@test.test
1818 Reply-To: chef@bork.bork.bork
1819 Message-Id: <dummy_test_message_id>
1821 ''')
1822         assert not os.path.exists(SENDMAILDEBUG)
1823         self.assertEqual(self.db.issue.get(nodeid, 'title'),
1824             'testing [assignedto=mary]')
1825         self.assertEqual(self.db.issue.get(nodeid, 'assignedto'), None)
1827     def testReplytoMatch(self):
1828         self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'loose'
1829         nodeid = self.doNewIssue()
1830         nodeid2 = self._handle_mail('''Content-Type: text/plain;
1831   charset="iso-8859-1"
1832 From: Chef <chef@bork.bork.bork>
1833 To: issue_tracker@your.tracker.email.domain.example
1834 Message-Id: <dummy_test_message_id2>
1835 In-Reply-To: <dummy_test_message_id>
1836 Subject: Testing...
1838 Followup message.
1839 ''')
1841         nodeid3 = self._handle_mail('''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_id3>
1846 In-Reply-To: <dummy_test_message_id2>
1847 Subject: Testing...
1849 Yet another message in the same thread/issue.
1850 ''')
1852         self.assertEqual(nodeid, nodeid2)
1853         self.assertEqual(nodeid, nodeid3)
1855     def testHelpSubject(self):
1856         message = '''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 Message-Id: <dummy_test_message_id2>
1861 In-Reply-To: <dummy_test_message_id>
1862 Subject: hElp
1865 '''
1866         self.assertRaises(MailUsageHelp, self._handle_mail, message)
1868     def testMaillistSubject(self):
1869         self.instance.config.MAILGW_SUBJECT_SUFFIX_DELIMITERS = '[]'
1870         self.db.keyword.create(name='Foo')
1871         self._handle_mail('''Content-Type: text/plain;
1872   charset="iso-8859-1"
1873 From: Chef <chef@bork.bork.bork>
1874 To: issue_tracker@your.tracker.email.domain.example
1875 Subject: [mailinglist-name] [keyword1] Testing.. [name=Bar]
1876 Cc: richard@test.test
1877 Reply-To: chef@bork.bork.bork
1878 Message-Id: <dummy_test_message_id>
1880 ''')
1882         assert not os.path.exists(SENDMAILDEBUG)
1883         self.assertEqual(self.db.keyword.get('1', 'name'), 'Bar')
1885     def testUnknownPrefixSubject(self):
1886         self.db.keyword.create(name='Foo')
1887         self._handle_mail('''Content-Type: text/plain;
1888   charset="iso-8859-1"
1889 From: Chef <chef@bork.bork.bork>
1890 To: issue_tracker@your.tracker.email.domain.example
1891 Subject: VeryStrangeRe: [keyword1] Testing.. [name=Bar]
1892 Cc: richard@test.test
1893 Reply-To: chef@bork.bork.bork
1894 Message-Id: <dummy_test_message_id>
1896 ''')
1898         assert not os.path.exists(SENDMAILDEBUG)
1899         self.assertEqual(self.db.keyword.get('1', 'name'), 'Bar')
1901     def testIssueidLast(self):
1902         nodeid1 = self.doNewIssue()
1903         nodeid2 = self._handle_mail('''Content-Type: text/plain;
1904   charset="iso-8859-1"
1905 From: mary <mary@test.test>
1906 To: issue_tracker@your.tracker.email.domain.example
1907 Message-Id: <followup_dummy_id>
1908 In-Reply-To: <dummy_test_message_id>
1909 Subject: New title [issue1]
1911 This is a second followup
1912 ''')
1914         assert nodeid1 == nodeid2
1915         self.assertEqual(self.db.issue.get(nodeid2, 'title'), "Testing...")
1917     def testSecurityMessagePermissionContent(self):
1918         id = self.doNewIssue()
1919         issue = self.db.issue.getnode (id)
1920         self.db.security.addRole(name='Nomsg')
1921         self.db.security.addPermissionToRole('Nomsg', 'Email Access')
1922         for cl in 'issue', 'file', 'keyword':
1923             for p in 'View', 'Edit', 'Create':
1924                 self.db.security.addPermissionToRole('Nomsg', p, cl)
1925         self.db.user.set(self.mary_id, roles='Nomsg')
1926         nodeid = self._handle_mail('''Content-Type: text/plain;
1927   charset="iso-8859-1"
1928 From: Chef <chef@bork.bork.bork>
1929 To: issue_tracker@your.tracker.email.domain.example
1930 Message-Id: <dummy_test_message_id>
1931 Subject: [issue%(id)s] Testing... [nosy=+mary]
1933 Just a test reply
1934 '''%locals())
1935         assert os.path.exists(SENDMAILDEBUG)
1936         self.compareMessages(self._get_mail(),
1937 '''FROM: roundup-admin@your.tracker.email.domain.example
1938 TO: chef@bork.bork.bork, richard@test.test
1939 Content-Type: text/plain; charset="utf-8"
1940 Subject: [issue1] Testing...
1941 To: richard@test.test
1942 From: "Bork, Chef" <issue_tracker@your.tracker.email.domain.example>
1943 Reply-To: Roundup issue tracker
1944  <issue_tracker@your.tracker.email.domain.example>
1945 MIME-Version: 1.0
1946 Message-Id: <dummy_test_message_id>
1947 X-Roundup-Name: Roundup issue tracker
1948 X-Roundup-Loop: hello
1949 X-Roundup-Issue-Status: chatting
1950 Content-Transfer-Encoding: quoted-printable
1953 Bork, Chef <chef@bork.bork.bork> added the comment:
1955 Just a test reply
1957 ----------
1958 nosy: +mary
1959 status: unread -> chatting
1961 _______________________________________________________________________
1962 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1963 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1964 _______________________________________________________________________
1965 ''')
1968 def test_suite():
1969     suite = unittest.TestSuite()
1970     suite.addTest(unittest.makeSuite(MailgwTestCase))
1971     return suite
1973 if __name__ == '__main__':
1974     runner = unittest.TextTestRunner()
1975     unittest.main(testRunner=runner)
1977 # vim: set filetype=python sts=4 sw=4 et si :