Code

295d06a1e3a64d8b8fc76a1c777ebca06ea48d3a
[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')
140         self.rgg_id = self.db.user.create(username='rgg',
141             address='rgg@test.test', roles='User')
143     def tearDown(self):
144         if os.path.exists(SENDMAILDEBUG):
145             os.remove(SENDMAILDEBUG)
146         self.db.close()
148     def _create_mailgw(self, message):
149         class MailGW(self.instance.MailGW):
150             def handle_message(self, message):
151                 return self._handle_message(message)
152         handler = MailGW(self.instance)
153         handler.db = self.db
154         return handler
156     def _handle_mail(self, message):
157         handler = self._create_mailgw(message)
158         handler.trapExceptions = 0
159         return handler.main(StringIO(message))
161     def _get_mail(self):
162         f = open(SENDMAILDEBUG)
163         try:
164             return f.read()
165         finally:
166             f.close()
168     def testEmptyMessage(self):
169         nodeid = self._handle_mail('''Content-Type: text/plain;
170   charset="iso-8859-1"
171 From: Chef <chef@bork.bork.bork>
172 To: issue_tracker@your.tracker.email.domain.example
173 Cc: richard@test.test
174 Reply-To: chef@bork.bork.bork
175 Message-Id: <dummy_test_message_id>
176 Subject: [issue] Testing...
178 ''')
179         assert not os.path.exists(SENDMAILDEBUG)
180         self.assertEqual(self.db.issue.get(nodeid, 'title'), 'Testing...')
182     def testMessageWithFromInIt(self):
183         nodeid = self._handle_mail('''Content-Type: text/plain;
184   charset="iso-8859-1"
185 From: Chef <chef@bork.bork.bork>
186 To: issue_tracker@your.tracker.email.domain.example
187 Cc: richard@test.test
188 Reply-To: chef@bork.bork.bork
189 Message-Id: <dummy_test_message_id>
190 Subject: [issue] Testing...
192 From here to there!
193 ''')
194         assert not os.path.exists(SENDMAILDEBUG)
195         msgid = self.db.issue.get(nodeid, 'messages')[0]
196         self.assertEqual(self.db.msg.get(msgid, 'content'), 'From here to there!')
198     def doNewIssue(self):
199         nodeid = self._handle_mail('''Content-Type: text/plain;
200   charset="iso-8859-1"
201 From: Chef <chef@bork.bork.bork>
202 To: issue_tracker@your.tracker.email.domain.example
203 Cc: richard@test.test
204 Message-Id: <dummy_test_message_id>
205 Subject: [issue] Testing...
207 This is a test submission of a new issue.
208 ''')
209         assert not os.path.exists(SENDMAILDEBUG)
210         l = self.db.issue.get(nodeid, 'nosy')
211         l.sort()
212         self.assertEqual(l, [self.chef_id, self.richard_id])
213         return nodeid
215     def testNewIssue(self):
216         self.doNewIssue()
218     def testNewIssueNosy(self):
219         self.instance.config.ADD_AUTHOR_TO_NOSY = 'yes'
220         nodeid = self._handle_mail('''Content-Type: text/plain;
221   charset="iso-8859-1"
222 From: Chef <chef@bork.bork.bork>
223 To: issue_tracker@your.tracker.email.domain.example
224 Cc: richard@test.test
225 Message-Id: <dummy_test_message_id>
226 Subject: [issue] Testing...
228 This is a test submission of a new issue.
229 ''')
230         assert not os.path.exists(SENDMAILDEBUG)
231         l = self.db.issue.get(nodeid, 'nosy')
232         l.sort()
233         self.assertEqual(l, [self.chef_id, self.richard_id])
235     def testAlternateAddress(self):
236         self._handle_mail('''Content-Type: text/plain;
237   charset="iso-8859-1"
238 From: John Doe <john.doe@test.test>
239 To: issue_tracker@your.tracker.email.domain.example
240 Message-Id: <dummy_test_message_id>
241 Subject: [issue] Testing...
243 This is a test submission of a new issue.
244 ''')
245         userlist = self.db.user.list()
246         assert not os.path.exists(SENDMAILDEBUG)
247         self.assertEqual(userlist, self.db.user.list(),
248             "user created when it shouldn't have been")
250     def testNewIssueNoClass(self):
251         self._handle_mail('''Content-Type: text/plain;
252   charset="iso-8859-1"
253 From: Chef <chef@bork.bork.bork>
254 To: issue_tracker@your.tracker.email.domain.example
255 Cc: richard@test.test
256 Message-Id: <dummy_test_message_id>
257 Subject: Testing...
259 This is a test submission of a new issue.
260 ''')
261         assert not os.path.exists(SENDMAILDEBUG)
263     def testNewIssueAuthMsg(self):
264         # TODO: fix the damn config - this is apalling
265         self.db.config.MESSAGES_TO_AUTHOR = 'yes'
266         self._handle_mail('''Content-Type: text/plain;
267   charset="iso-8859-1"
268 From: Chef <chef@bork.bork.bork>
269 To: issue_tracker@your.tracker.email.domain.example
270 Message-Id: <dummy_test_message_id>
271 Subject: [issue] Testing... [nosy=mary; assignedto=richard]
273 This is a test submission of a new issue.
274 ''')
275         self.compareMessages(self._get_mail(),
276 '''FROM: roundup-admin@your.tracker.email.domain.example
277 TO: chef@bork.bork.bork, mary@test.test, richard@test.test
278 Content-Type: text/plain; charset="utf-8"
279 Subject: [issue1] Testing...
280 To: chef@bork.bork.bork, mary@test.test, richard@test.test
281 From: "Bork, Chef" <issue_tracker@your.tracker.email.domain.example>
282 Reply-To: Roundup issue tracker
283  <issue_tracker@your.tracker.email.domain.example>
284 MIME-Version: 1.0
285 Message-Id: <dummy_test_message_id>
286 X-Roundup-Name: Roundup issue tracker
287 X-Roundup-Loop: hello
288 X-Roundup-Issue-Status: unread
289 Content-Transfer-Encoding: quoted-printable
292 New submission from Bork, Chef <chef@bork.bork.bork>:
294 This is a test submission of a new issue.
296 ----------
297 assignedto: richard
298 messages: 1
299 nosy: Chef, mary, richard
300 status: unread
301 title: Testing...
303 _______________________________________________________________________
304 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
305 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
306 _______________________________________________________________________
307 ''')
309     def testNewIssueNoAuthorInfo(self):
310         self.db.config.MAIL_ADD_AUTHORINFO = 'no'
311         self._handle_mail('''Content-Type: text/plain;
312   charset="iso-8859-1"
313 From: Chef <chef@bork.bork.bork>
314 To: issue_tracker@your.tracker.email.domain.example
315 Message-Id: <dummy_test_message_id>
316 Subject: [issue] Testing... [nosy=mary; assignedto=richard]
318 This is a test submission of a new issue.
319 ''')
320         self.compareMessages(self._get_mail(),
321 '''FROM: roundup-admin@your.tracker.email.domain.example
322 TO: chef@bork.bork.bork, mary@test.test, richard@test.test
323 Content-Type: text/plain; charset="utf-8"
324 Subject: [issue1] Testing...
325 To: mary@test.test, richard@test.test
326 From: "Bork, Chef" <issue_tracker@your.tracker.email.domain.example>
327 Reply-To: Roundup issue tracker
328  <issue_tracker@your.tracker.email.domain.example>
329 MIME-Version: 1.0
330 Message-Id: <dummy_test_message_id>
331 X-Roundup-Name: Roundup issue tracker
332 X-Roundup-Loop: hello
333 X-Roundup-Issue-Status: unread
334 Content-Transfer-Encoding: quoted-printable
336 This is a test submission of a new issue.
338 ----------
339 assignedto: richard
340 messages: 1
341 nosy: Chef, mary, richard
342 status: unread
343 title: Testing...
345 _______________________________________________________________________
346 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
347 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
348 _______________________________________________________________________
349 ''')
351     def testNewIssueNoAuthorEmail(self):
352         self.db.config.MAIL_ADD_AUTHOREMAIL = 'no'
353         self._handle_mail('''Content-Type: text/plain;
354   charset="iso-8859-1"
355 From: Chef <chef@bork.bork.bork>
356 To: issue_tracker@your.tracker.email.domain.example
357 Message-Id: <dummy_test_message_id>
358 Subject: [issue] Testing... [nosy=mary; assignedto=richard]
360 This is a test submission of a new issue.
361 ''')
362         self.compareMessages(self._get_mail(),
363 '''FROM: roundup-admin@your.tracker.email.domain.example
364 TO: chef@bork.bork.bork, mary@test.test, richard@test.test
365 Content-Type: text/plain; charset="utf-8"
366 Subject: [issue1] Testing...
367 To: mary@test.test, richard@test.test
368 From: "Bork, Chef" <issue_tracker@your.tracker.email.domain.example>
369 Reply-To: Roundup issue tracker
370  <issue_tracker@your.tracker.email.domain.example>
371 MIME-Version: 1.0
372 Message-Id: <dummy_test_message_id>
373 X-Roundup-Name: Roundup issue tracker
374 X-Roundup-Loop: hello
375 X-Roundup-Issue-Status: unread
376 Content-Transfer-Encoding: quoted-printable
378 New submission from Bork, Chef:
380 This is a test submission of a new issue.
382 ----------
383 assignedto: richard
384 messages: 1
385 nosy: Chef, mary, richard
386 status: unread
387 title: Testing...
389 _______________________________________________________________________
390 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
391 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
392 _______________________________________________________________________
393 ''')
395     multipart_msg = '''From: mary <mary@test.test>
396 To: issue_tracker@your.tracker.email.domain.example
397 Message-Id: <followup_dummy_id>
398 In-Reply-To: <dummy_test_message_id>
399 Subject: [issue1] Testing...
400 Content-Type: multipart/mixed; boundary="bxyzzy"
401 Content-Disposition: inline
404 --bxyzzy
405 Content-Type: multipart/alternative; boundary="bCsyhTFzCvuiizWE"
406 Content-Disposition: inline
408 --bCsyhTFzCvuiizWE
409 Content-Type: text/plain; charset=us-ascii
410 Content-Disposition: inline
412 test attachment first text/plain
414 --bCsyhTFzCvuiizWE
415 Content-Type: application/octet-stream
416 Content-Disposition: attachment; filename="first.dvi"
417 Content-Transfer-Encoding: base64
419 SnVzdCBhIHRlc3QgAQo=
421 --bCsyhTFzCvuiizWE
422 Content-Type: text/plain; charset=us-ascii
423 Content-Disposition: inline
425 test attachment second text/plain
427 --bCsyhTFzCvuiizWE
428 Content-Type: text/html
429 Content-Disposition: inline
431 <html>
432 to be ignored.
433 </html>
435 --bCsyhTFzCvuiizWE--
437 --bxyzzy
438 Content-Type: multipart/alternative; boundary="bCsyhTFzCvuiizWF"
439 Content-Disposition: inline
441 --bCsyhTFzCvuiizWF
442 Content-Type: text/plain; charset=us-ascii
443 Content-Disposition: inline
445 test attachment third text/plain
447 --bCsyhTFzCvuiizWF
448 Content-Type: application/octet-stream
449 Content-Disposition: attachment; filename="second.dvi"
450 Content-Transfer-Encoding: base64
452 SnVzdCBhIHRlc3QK
454 --bCsyhTFzCvuiizWF--
456 --bxyzzy--
457 '''
459     def testMultipartKeepAlternatives(self):
460         self.doNewIssue()
461         self._handle_mail(self.multipart_msg)
462         messages = self.db.issue.get('1', 'messages')
463         messages.sort()
464         msg = self.db.msg.getnode (messages[-1])
465         assert(len(msg.files) == 5)
466         names = {0 : 'first.dvi', 4 : 'second.dvi'}
467         content = {3 : 'test attachment third text/plain\n',
468                    4 : 'Just a test\n'}
469         for n, id in enumerate (msg.files):
470             f = self.db.file.getnode (id)
471             self.assertEqual(f.name, names.get (n, 'unnamed'))
472             if n in content :
473                 self.assertEqual(f.content, content [n])
474         self.assertEqual(msg.content, 'test attachment second text/plain')
476     def testMultipartDropAlternatives(self):
477         self.doNewIssue()
478         self.db.config.MAILGW_IGNORE_ALTERNATIVES = True
479         self._handle_mail(self.multipart_msg)
480         messages = self.db.issue.get('1', 'messages')
481         messages.sort()
482         msg = self.db.msg.getnode (messages[-1])
483         assert(len(msg.files) == 2)
484         names = {1 : 'second.dvi'}
485         content = {0 : 'test attachment third text/plain\n',
486                    1 : 'Just a test\n'}
487         for n, id in enumerate (msg.files):
488             f = self.db.file.getnode (id)
489             self.assertEqual(f.name, names.get (n, 'unnamed'))
490             if n in content :
491                 self.assertEqual(f.content, content [n])
492         self.assertEqual(msg.content, 'test attachment second text/plain')
494     def testSimpleFollowup(self):
495         self.doNewIssue()
496         self._handle_mail('''Content-Type: text/plain;
497   charset="iso-8859-1"
498 From: mary <mary@test.test>
499 To: issue_tracker@your.tracker.email.domain.example
500 Message-Id: <followup_dummy_id>
501 In-Reply-To: <dummy_test_message_id>
502 Subject: [issue1] Testing...
504 This is a second followup
505 ''')
506         self.compareMessages(self._get_mail(),
507 '''FROM: roundup-admin@your.tracker.email.domain.example
508 TO: chef@bork.bork.bork, richard@test.test
509 Content-Type: text/plain; charset="utf-8"
510 Subject: [issue1] Testing...
511 To: chef@bork.bork.bork, richard@test.test
512 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
513 Reply-To: Roundup issue tracker
514  <issue_tracker@your.tracker.email.domain.example>
515 MIME-Version: 1.0
516 Message-Id: <followup_dummy_id>
517 In-Reply-To: <dummy_test_message_id>
518 X-Roundup-Name: Roundup issue tracker
519 X-Roundup-Loop: hello
520 X-Roundup-Issue-Status: chatting
521 Content-Transfer-Encoding: quoted-printable
524 Contrary, Mary <mary@test.test> added the comment:
526 This is a second followup
528 ----------
529 status: unread -> chatting
531 _______________________________________________________________________
532 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
533 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
534 _______________________________________________________________________
535 ''')
537     def testFollowup(self):
538         self.doNewIssue()
540         self._handle_mail('''Content-Type: text/plain;
541   charset="iso-8859-1"
542 From: richard <richard@test.test>
543 To: issue_tracker@your.tracker.email.domain.example
544 Message-Id: <followup_dummy_id>
545 In-Reply-To: <dummy_test_message_id>
546 Subject: [issue1] Testing... [assignedto=mary; nosy=+john]
548 This is a followup
549 ''')
550         l = self.db.issue.get('1', 'nosy')
551         l.sort()
552         self.assertEqual(l, [self.chef_id, self.richard_id, self.mary_id,
553             self.john_id])
555         self.compareMessages(self._get_mail(),
556 '''FROM: roundup-admin@your.tracker.email.domain.example
557 TO: chef@bork.bork.bork, john@test.test, mary@test.test
558 Content-Type: text/plain; charset="utf-8"
559 Subject: [issue1] Testing...
560 To: chef@bork.bork.bork, john@test.test, mary@test.test
561 From: richard <issue_tracker@your.tracker.email.domain.example>
562 Reply-To: Roundup issue tracker
563  <issue_tracker@your.tracker.email.domain.example>
564 MIME-Version: 1.0
565 Message-Id: <followup_dummy_id>
566 In-Reply-To: <dummy_test_message_id>
567 X-Roundup-Name: Roundup issue tracker
568 X-Roundup-Loop: hello
569 X-Roundup-Issue-Status: chatting
570 Content-Transfer-Encoding: quoted-printable
573 richard <richard@test.test> added the comment:
575 This is a followup
577 ----------
578 assignedto:  -> mary
579 nosy: +john, mary
580 status: unread -> chatting
582 _______________________________________________________________________
583 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
584 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
585 _______________________________________________________________________
586 ''')
588     def testNosyGeneration(self):
589         self.db.issue.create(title='test')
591         # create a nosy message
592         msg = self.db.msg.create(content='This is a test',
593             author=self.richard_id, messageid='<dummy_test_message_id>')
594         self.db.journaltag = 'richard'
595         l = self.db.issue.create(title='test', messages=[msg],
596             nosy=[self.chef_id, self.mary_id, self.john_id])
598         self.compareMessages(self._get_mail(),
599 '''FROM: roundup-admin@your.tracker.email.domain.example
600 TO: chef@bork.bork.bork, john@test.test, mary@test.test
601 Content-Type: text/plain; charset="utf-8"
602 Subject: [issue2] test
603 To: chef@bork.bork.bork, john@test.test, mary@test.test
604 From: richard <issue_tracker@your.tracker.email.domain.example>
605 Reply-To: Roundup issue tracker
606  <issue_tracker@your.tracker.email.domain.example>
607 MIME-Version: 1.0
608 Message-Id: <dummy_test_message_id>
609 X-Roundup-Name: Roundup issue tracker
610 X-Roundup-Loop: hello
611 X-Roundup-Issue-Status: unread
612 Content-Transfer-Encoding: quoted-printable
615 New submission from richard <richard@test.test>:
617 This is a test
619 ----------
620 messages: 1
621 nosy: Chef, john, mary, richard
622 status: unread
623 title: test
625 _______________________________________________________________________
626 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
627 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue2>
628 _______________________________________________________________________
629 ''')
631     def testPropertyChangeOnly(self):
632         self.doNewIssue()
633         oldvalues = self.db.getnode('issue', '1').copy()
634         oldvalues['assignedto'] = None
635         # reconstruct old behaviour: This would reuse the
636         # database-handle from the doNewIssue above which has committed
637         # as user "Chef". So we close and reopen the db as that user.
638         #self.db.close() actually don't close 'cos this empties memorydb
639         self.db = self.instance.open('Chef')
640         self.db.issue.set('1', assignedto=self.chef_id)
641         self.db.commit()
642         self.db.issue.nosymessage('1', None, oldvalues)
644         new_mail = ""
645         for line in self._get_mail().split("\n"):
646             if "Message-Id: " in line:
647                 continue
648             if "Date: " in line:
649                 continue
650             new_mail += line+"\n"
652         self.compareMessages(new_mail, """
653 FROM: roundup-admin@your.tracker.email.domain.example
654 TO: chef@bork.bork.bork, richard@test.test
655 Content-Type: text/plain; charset="utf-8"
656 Subject: [issue1] Testing...
657 To: chef@bork.bork.bork, richard@test.test
658 From: "Bork, Chef" <issue_tracker@your.tracker.email.domain.example>
659 X-Roundup-Name: Roundup issue tracker
660 X-Roundup-Loop: hello
661 X-Roundup-Issue-Status: unread
662 X-Roundup-Version: 1.3.3
663 In-Reply-To: <dummy_test_message_id>
664 MIME-Version: 1.0
665 Reply-To: Roundup issue tracker
666  <issue_tracker@your.tracker.email.domain.example>
667 Content-Transfer-Encoding: quoted-printable
670 Change by Bork, Chef <chef@bork.bork.bork>:
673 ----------
674 assignedto:  -> Chef
676 _______________________________________________________________________
677 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
678 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
679 _______________________________________________________________________
680 """)
683     #
684     # FOLLOWUP TITLE MATCH
685     #
686     def testFollowupTitleMatch(self):
687         self.doNewIssue()
688         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: <followup_dummy_id>
693 Subject: Re: Testing... [assignedto=mary; nosy=+john]
695 This is a followup
696 ''')
697         self.compareMessages(self._get_mail(),
698 '''FROM: roundup-admin@your.tracker.email.domain.example
699 TO: chef@bork.bork.bork, john@test.test, mary@test.test
700 Content-Type: text/plain; charset="utf-8"
701 Subject: [issue1] Testing...
702 To: chef@bork.bork.bork, john@test.test, mary@test.test
703 From: richard <issue_tracker@your.tracker.email.domain.example>
704 Reply-To: Roundup issue tracker
705  <issue_tracker@your.tracker.email.domain.example>
706 MIME-Version: 1.0
707 Message-Id: <followup_dummy_id>
708 In-Reply-To: <dummy_test_message_id>
709 X-Roundup-Name: Roundup issue tracker
710 X-Roundup-Loop: hello
711 X-Roundup-Issue-Status: chatting
712 Content-Transfer-Encoding: quoted-printable
715 richard <richard@test.test> added the comment:
717 This is a followup
719 ----------
720 assignedto:  -> mary
721 nosy: +john, mary
722 status: unread -> chatting
724 _______________________________________________________________________
725 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
726 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
727 _______________________________________________________________________
728 ''')
730     def testFollowupTitleMatchMultiRe(self):
731         nodeid1 = self.doNewIssue()
732         nodeid2 = 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... [assignedto=mary; nosy=+john]
739 This is a followup
740 ''')
742         nodeid3 = self._handle_mail('''Content-Type: text/plain;
743   charset="iso-8859-1"
744 From: richard <richard@test.test>
745 To: issue_tracker@your.tracker.email.domain.example
746 Message-Id: <followup2_dummy_id>
747 Subject: Ang: Re: Testing...
749 This is a followup
750 ''')
751         self.assertEqual(nodeid1, nodeid2)
752         self.assertEqual(nodeid1, nodeid3)
754     def testFollowupTitleMatchNever(self):
755         nodeid = self.doNewIssue()
756         self.db.config.MAILGW_SUBJECT_CONTENT_MATCH = 'never'
757         self.assertNotEqual(self._handle_mail('''Content-Type: text/plain;
758   charset="iso-8859-1"
759 From: richard <richard@test.test>
760 To: issue_tracker@your.tracker.email.domain.example
761 Message-Id: <followup_dummy_id>
762 Subject: Re: Testing...
764 This is a followup
765 '''), nodeid)
767     def testFollowupTitleMatchNeverInterval(self):
768         nodeid = self.doNewIssue()
769         # force failure of the interval
770         time.sleep(2)
771         self.db.config.MAILGW_SUBJECT_CONTENT_MATCH = 'creation 00:00:01'
772         self.assertNotEqual(self._handle_mail('''Content-Type: text/plain;
773   charset="iso-8859-1"
774 From: richard <richard@test.test>
775 To: issue_tracker@your.tracker.email.domain.example
776 Message-Id: <followup_dummy_id>
777 Subject: Re: Testing...
779 This is a followup
780 '''), nodeid)
783     def testFollowupTitleMatchInterval(self):
784         nodeid = self.doNewIssue()
785         self.db.config.MAILGW_SUBJECT_CONTENT_MATCH = 'creation +1d'
786         self.assertEqual(self._handle_mail('''Content-Type: text/plain;
787   charset="iso-8859-1"
788 From: richard <richard@test.test>
789 To: issue_tracker@your.tracker.email.domain.example
790 Message-Id: <followup_dummy_id>
791 Subject: Re: Testing...
793 This is a followup
794 '''), nodeid)
797     def testFollowupNosyAuthor(self):
798         self.doNewIssue()
799         self.db.config.ADD_AUTHOR_TO_NOSY = 'yes'
800         self._handle_mail('''Content-Type: text/plain;
801   charset="iso-8859-1"
802 From: john@test.test
803 To: issue_tracker@your.tracker.email.domain.example
804 Message-Id: <followup_dummy_id>
805 In-Reply-To: <dummy_test_message_id>
806 Subject: [issue1] Testing...
808 This is a followup
809 ''')
811         self.compareMessages(self._get_mail(),
812 '''FROM: roundup-admin@your.tracker.email.domain.example
813 TO: chef@bork.bork.bork, richard@test.test
814 Content-Type: text/plain; charset="utf-8"
815 Subject: [issue1] Testing...
816 To: chef@bork.bork.bork, richard@test.test
817 From: John Doe <issue_tracker@your.tracker.email.domain.example>
818 Reply-To: Roundup issue tracker
819  <issue_tracker@your.tracker.email.domain.example>
820 MIME-Version: 1.0
821 Message-Id: <followup_dummy_id>
822 In-Reply-To: <dummy_test_message_id>
823 X-Roundup-Name: Roundup issue tracker
824 X-Roundup-Loop: hello
825 X-Roundup-Issue-Status: chatting
826 Content-Transfer-Encoding: quoted-printable
829 John Doe <john@test.test> added the comment:
831 This is a followup
833 ----------
834 nosy: +john
835 status: unread -> chatting
837 _______________________________________________________________________
838 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
839 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
840 _______________________________________________________________________
842 ''')
844     def testFollowupNosyRecipients(self):
845         self.doNewIssue()
846         self.db.config.ADD_RECIPIENTS_TO_NOSY = 'yes'
847         self._handle_mail('''Content-Type: text/plain;
848   charset="iso-8859-1"
849 From: richard@test.test
850 To: issue_tracker@your.tracker.email.domain.example
851 Cc: john@test.test
852 Message-Id: <followup_dummy_id>
853 In-Reply-To: <dummy_test_message_id>
854 Subject: [issue1] Testing...
856 This is a followup
857 ''')
858         self.compareMessages(self._get_mail(),
859 '''FROM: roundup-admin@your.tracker.email.domain.example
860 TO: chef@bork.bork.bork
861 Content-Type: text/plain; charset="utf-8"
862 Subject: [issue1] Testing...
863 To: chef@bork.bork.bork
864 From: richard <issue_tracker@your.tracker.email.domain.example>
865 Reply-To: Roundup issue tracker
866  <issue_tracker@your.tracker.email.domain.example>
867 MIME-Version: 1.0
868 Message-Id: <followup_dummy_id>
869 In-Reply-To: <dummy_test_message_id>
870 X-Roundup-Name: Roundup issue tracker
871 X-Roundup-Loop: hello
872 X-Roundup-Issue-Status: chatting
873 Content-Transfer-Encoding: quoted-printable
876 richard <richard@test.test> added the comment:
878 This is a followup
880 ----------
881 nosy: +john
882 status: unread -> chatting
884 _______________________________________________________________________
885 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
886 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
887 _______________________________________________________________________
889 ''')
891     def testFollowupNosyAuthorAndCopy(self):
892         self.doNewIssue()
893         self.db.config.ADD_AUTHOR_TO_NOSY = 'yes'
894         self.db.config.MESSAGES_TO_AUTHOR = 'yes'
895         self._handle_mail('''Content-Type: text/plain;
896   charset="iso-8859-1"
897 From: john@test.test
898 To: issue_tracker@your.tracker.email.domain.example
899 Message-Id: <followup_dummy_id>
900 In-Reply-To: <dummy_test_message_id>
901 Subject: [issue1] Testing...
903 This is a followup
904 ''')
905         self.compareMessages(self._get_mail(),
906 '''FROM: roundup-admin@your.tracker.email.domain.example
907 TO: chef@bork.bork.bork, john@test.test, richard@test.test
908 Content-Type: text/plain; charset="utf-8"
909 Subject: [issue1] Testing...
910 To: chef@bork.bork.bork, john@test.test, richard@test.test
911 From: John Doe <issue_tracker@your.tracker.email.domain.example>
912 Reply-To: Roundup issue tracker
913  <issue_tracker@your.tracker.email.domain.example>
914 MIME-Version: 1.0
915 Message-Id: <followup_dummy_id>
916 In-Reply-To: <dummy_test_message_id>
917 X-Roundup-Name: Roundup issue tracker
918 X-Roundup-Loop: hello
919 X-Roundup-Issue-Status: chatting
920 Content-Transfer-Encoding: quoted-printable
923 John Doe <john@test.test> added the comment:
925 This is a followup
927 ----------
928 nosy: +john
929 status: unread -> chatting
931 _______________________________________________________________________
932 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
933 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
934 _______________________________________________________________________
936 ''')
938     def testFollowupNoNosyAuthor(self):
939         self.doNewIssue()
940         self.instance.config.ADD_AUTHOR_TO_NOSY = 'no'
941         self._handle_mail('''Content-Type: text/plain;
942   charset="iso-8859-1"
943 From: john@test.test
944 To: issue_tracker@your.tracker.email.domain.example
945 Message-Id: <followup_dummy_id>
946 In-Reply-To: <dummy_test_message_id>
947 Subject: [issue1] Testing...
949 This is a followup
950 ''')
951         self.compareMessages(self._get_mail(),
952 '''FROM: roundup-admin@your.tracker.email.domain.example
953 TO: chef@bork.bork.bork, richard@test.test
954 Content-Type: text/plain; charset="utf-8"
955 Subject: [issue1] Testing...
956 To: chef@bork.bork.bork, richard@test.test
957 From: John Doe <issue_tracker@your.tracker.email.domain.example>
958 Reply-To: Roundup issue tracker
959  <issue_tracker@your.tracker.email.domain.example>
960 MIME-Version: 1.0
961 Message-Id: <followup_dummy_id>
962 In-Reply-To: <dummy_test_message_id>
963 X-Roundup-Name: Roundup issue tracker
964 X-Roundup-Loop: hello
965 X-Roundup-Issue-Status: chatting
966 Content-Transfer-Encoding: quoted-printable
969 John Doe <john@test.test> added the comment:
971 This is a followup
973 ----------
974 status: unread -> chatting
976 _______________________________________________________________________
977 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
978 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
979 _______________________________________________________________________
981 ''')
983     def testFollowupNoNosyRecipients(self):
984         self.doNewIssue()
985         self.instance.config.ADD_RECIPIENTS_TO_NOSY = 'no'
986         self._handle_mail('''Content-Type: text/plain;
987   charset="iso-8859-1"
988 From: richard@test.test
989 To: issue_tracker@your.tracker.email.domain.example
990 Cc: john@test.test
991 Message-Id: <followup_dummy_id>
992 In-Reply-To: <dummy_test_message_id>
993 Subject: [issue1] Testing...
995 This is a followup
996 ''')
997         self.compareMessages(self._get_mail(),
998 '''FROM: roundup-admin@your.tracker.email.domain.example
999 TO: chef@bork.bork.bork
1000 Content-Type: text/plain; charset="utf-8"
1001 Subject: [issue1] Testing...
1002 To: chef@bork.bork.bork
1003 From: richard <issue_tracker@your.tracker.email.domain.example>
1004 Reply-To: Roundup issue tracker
1005  <issue_tracker@your.tracker.email.domain.example>
1006 MIME-Version: 1.0
1007 Message-Id: <followup_dummy_id>
1008 In-Reply-To: <dummy_test_message_id>
1009 X-Roundup-Name: Roundup issue tracker
1010 X-Roundup-Loop: hello
1011 X-Roundup-Issue-Status: chatting
1012 Content-Transfer-Encoding: quoted-printable
1015 richard <richard@test.test> added the comment:
1017 This is a followup
1019 ----------
1020 status: unread -> chatting
1022 _______________________________________________________________________
1023 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1024 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1025 _______________________________________________________________________
1027 ''')
1029     def testFollowupEmptyMessage(self):
1030         self.doNewIssue()
1032         self._handle_mail('''Content-Type: text/plain;
1033   charset="iso-8859-1"
1034 From: richard <richard@test.test>
1035 To: issue_tracker@your.tracker.email.domain.example
1036 Message-Id: <followup_dummy_id>
1037 In-Reply-To: <dummy_test_message_id>
1038 Subject: [issue1] Testing... [assignedto=mary; nosy=+john]
1040 ''')
1041         l = self.db.issue.get('1', 'nosy')
1042         l.sort()
1043         self.assertEqual(l, [self.chef_id, self.richard_id, self.mary_id,
1044             self.john_id])
1046         # should be no file created (ie. no message)
1047         assert not os.path.exists(SENDMAILDEBUG)
1049     def testFollowupEmptyMessageNoSubject(self):
1050         self.doNewIssue()
1052         self._handle_mail('''Content-Type: text/plain;
1053   charset="iso-8859-1"
1054 From: richard <richard@test.test>
1055 To: issue_tracker@your.tracker.email.domain.example
1056 Message-Id: <followup_dummy_id>
1057 In-Reply-To: <dummy_test_message_id>
1058 Subject: [issue1] [assignedto=mary; nosy=+john]
1060 ''')
1061         l = self.db.issue.get('1', 'nosy')
1062         l.sort()
1063         self.assertEqual(l, [self.chef_id, self.richard_id, self.mary_id,
1064             self.john_id])
1066         # should be no file created (ie. no message)
1067         assert not os.path.exists(SENDMAILDEBUG)
1069     def testNosyRemove(self):
1070         self.doNewIssue()
1072         self._handle_mail('''Content-Type: text/plain;
1073   charset="iso-8859-1"
1074 From: richard <richard@test.test>
1075 To: issue_tracker@your.tracker.email.domain.example
1076 Message-Id: <followup_dummy_id>
1077 In-Reply-To: <dummy_test_message_id>
1078 Subject: [issue1] Testing... [nosy=-richard]
1080 ''')
1081         l = self.db.issue.get('1', 'nosy')
1082         l.sort()
1083         self.assertEqual(l, [self.chef_id])
1085         # NO NOSY MESSAGE SHOULD BE SENT!
1086         assert not os.path.exists(SENDMAILDEBUG)
1088     def testNewUserAuthor(self):
1089         self.db.commit()
1090         l = self.db.user.list()
1091         l.sort()
1092         message = '''Content-Type: text/plain;
1093   charset="iso-8859-1"
1094 From: fubar <fubar@bork.bork.bork>
1095 To: issue_tracker@your.tracker.email.domain.example
1096 Message-Id: <dummy_test_message_id>
1097 Subject: [issue] Testing...
1099 This is a test submission of a new issue.
1100 '''
1101         self.db.security.role['anonymous'].permissions=[]
1102         anonid = self.db.user.lookup('anonymous')
1103         self.db.user.set(anonid, roles='Anonymous')
1104         try:
1105             self._handle_mail(message)
1106         except Unauthorized, value:
1107             body_diff = self.compareMessages(str(value), """
1108 You are not a registered user.
1110 Unknown address: fubar@bork.bork.bork
1111 """)
1112             assert not body_diff, body_diff
1113         else:
1114             raise AssertionError, "Unathorized not raised when handling mail"
1116         # Add Web Access role to anonymous, and try again to make sure
1117         # we get a "please register at:" message this time.
1118         p = [
1119             self.db.security.getPermission('Register', 'user'),
1120             self.db.security.getPermission('Web Access', None),
1121         ]
1122         self.db.security.role['anonymous'].permissions=p
1123         try:
1124             self._handle_mail(message)
1125         except Unauthorized, value:
1126             body_diff = self.compareMessages(str(value), """
1127 You are not a registered user. Please register at:
1129 http://tracker.example/cgi-bin/roundup.cgi/bugs/user?template=register
1131 ...before sending mail to the tracker.
1133 Unknown address: fubar@bork.bork.bork
1134 """)
1135             assert not body_diff, body_diff
1136         else:
1137             raise AssertionError, "Unathorized not raised when handling mail"
1139         # Make sure list of users is the same as before.
1140         m = self.db.user.list()
1141         m.sort()
1142         self.assertEqual(l, m)
1144         # now with the permission
1145         p = [
1146             self.db.security.getPermission('Register', 'user'),
1147             self.db.security.getPermission('Email Access', None),
1148         ]
1149         self.db.security.role['anonymous'].permissions=p
1150         self._handle_mail(message)
1151         m = self.db.user.list()
1152         m.sort()
1153         self.assertNotEqual(l, m)
1155     def testNewUserAuthorEncodedName(self):
1156         l = set(self.db.user.list())
1157         # From: name has Euro symbol in it
1158         message = '''Content-Type: text/plain;
1159   charset="iso-8859-1"
1160 From: =?utf8?b?SOKCrGxsbw==?= <fubar@bork.bork.bork>
1161 To: issue_tracker@your.tracker.email.domain.example
1162 Message-Id: <dummy_test_message_id>
1163 Subject: [issue] Testing...
1165 This is a test submission of a new issue.
1166 '''
1167         p = [
1168             self.db.security.getPermission('Register', 'user'),
1169             self.db.security.getPermission('Email Access', None),
1170             self.db.security.getPermission('Create', 'issue'),
1171             self.db.security.getPermission('Create', 'msg'),
1172         ]
1173         self.db.security.role['anonymous'].permissions = p
1174         self._handle_mail(message)
1175         m = set(self.db.user.list())
1176         new = list(m - l)[0]
1177         name = self.db.user.get(new, 'realname')
1178         self.assertEquals(name, 'H€llo')
1180     def testUnknownUser(self):
1181         l = set(self.db.user.list())
1182         message = '''Content-Type: text/plain;
1183   charset="iso-8859-1"
1184 From: Nonexisting User <nonexisting@bork.bork.bork>
1185 To: issue_tracker@your.tracker.email.domain.example
1186 Message-Id: <dummy_test_message_id>
1187 Subject: [issue] Testing nonexisting user...
1189 This is a test submission of a new issue.
1190 '''
1191         handler = self._create_mailgw(message)
1192         # we want a bounce message:
1193         handler.trapExceptions = 1
1194         ret = handler.main(StringIO(message))
1195         self.compareMessages(self._get_mail(),
1196 '''FROM: Roundup issue tracker <roundup-admin@your.tracker.email.domain.example>
1197 TO: nonexisting@bork.bork.bork
1198 From nobody Tue Jul 14 12:04:11 2009
1199 Content-Type: multipart/mixed; boundary="===============0639262320=="
1200 MIME-Version: 1.0
1201 Subject: Failed issue tracker submission
1202 To: nonexisting@bork.bork.bork
1203 From: Roundup issue tracker <roundup-admin@your.tracker.email.domain.example>
1204 Date: Tue, 14 Jul 2009 12:04:11 +0000
1205 Precedence: bulk
1206 X-Roundup-Name: Roundup issue tracker
1207 X-Roundup-Loop: hello
1208 X-Roundup-Version: 1.4.8
1209 MIME-Version: 1.0
1211 --===============0639262320==
1212 Content-Type: text/plain; charset="us-ascii"
1213 MIME-Version: 1.0
1214 Content-Transfer-Encoding: 7bit
1218 You are not a registered user. Please register at:
1220 http://tracker.example/cgi-bin/roundup.cgi/bugs/user?template=register
1222 ...before sending mail to the tracker.
1224 Unknown address: nonexisting@bork.bork.bork
1226 --===============0639262320==
1227 Content-Type: text/plain; charset="us-ascii"
1228 MIME-Version: 1.0
1229 Content-Transfer-Encoding: 7bit
1231 Content-Type: text/plain;
1232   charset="iso-8859-1"
1233 From: Nonexisting User <nonexisting@bork.bork.bork>
1234 To: issue_tracker@your.tracker.email.domain.example
1235 Message-Id: <dummy_test_message_id>
1236 Subject: [issue] Testing nonexisting user...
1238 This is a test submission of a new issue.
1240 --===============0639262320==--
1241 ''')
1243     def testEnc01(self):
1244         self.db.user.set(self.mary_id,
1245             realname='\xe4\xf6\xfc\xc4\xd6\xdc\xdf, Mary'.decode
1246             ('latin-1').encode('utf-8'))
1247         self.doNewIssue()
1248         self._handle_mail('''Content-Type: text/plain;
1249   charset="iso-8859-1"
1250 From: mary <mary@test.test>
1251 To: issue_tracker@your.tracker.email.domain.example
1252 Message-Id: <followup_dummy_id>
1253 In-Reply-To: <dummy_test_message_id>
1254 Subject: [issue1] Testing...
1255 Content-Type: text/plain;
1256         charset="iso-8859-1"
1257 Content-Transfer-Encoding: quoted-printable
1259 A message with encoding (encoded oe =F6)
1261 ''')
1262         self.compareMessages(self._get_mail(),
1263 '''FROM: roundup-admin@your.tracker.email.domain.example
1264 TO: chef@bork.bork.bork, richard@test.test
1265 Content-Type: text/plain; charset="utf-8"
1266 Subject: [issue1] Testing...
1267 To: chef@bork.bork.bork, richard@test.test
1268 From: =?utf-8?b?w6TDtsO8w4TDlsOcw58sIE1hcnk=?=
1269  <issue_tracker@your.tracker.email.domain.example>
1270 Reply-To: Roundup issue tracker
1271  <issue_tracker@your.tracker.email.domain.example>
1272 MIME-Version: 1.0
1273 Message-Id: <followup_dummy_id>
1274 In-Reply-To: <dummy_test_message_id>
1275 X-Roundup-Name: Roundup issue tracker
1276 X-Roundup-Loop: hello
1277 X-Roundup-Issue-Status: chatting
1278 Content-Transfer-Encoding: quoted-printable
1281 =C3=A4=C3=B6=C3=BC=C3=84=C3=96=C3=9C=C3=9F, Mary <mary@test.test> added the=
1282  comment:
1284 A message with encoding (encoded oe =C3=B6)
1286 ----------
1287 status: unread -> chatting
1289 _______________________________________________________________________
1290 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1291 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1292 _______________________________________________________________________
1293 ''')
1295     def testEncNonUTF8(self):
1296         self.doNewIssue()
1297         self.instance.config.EMAIL_CHARSET = 'iso-8859-1'
1298         self._handle_mail('''Content-Type: text/plain;
1299   charset="iso-8859-1"
1300 From: mary <mary@test.test>
1301 To: issue_tracker@your.tracker.email.domain.example
1302 Message-Id: <followup_dummy_id>
1303 In-Reply-To: <dummy_test_message_id>
1304 Subject: [issue1] Testing...
1305 Content-Type: text/plain;
1306         charset="iso-8859-1"
1307 Content-Transfer-Encoding: quoted-printable
1309 A message with encoding (encoded oe =F6)
1311 ''')
1312         self.compareMessages(self._get_mail(),
1313 '''FROM: roundup-admin@your.tracker.email.domain.example
1314 TO: chef@bork.bork.bork, richard@test.test
1315 Content-Type: text/plain; charset="iso-8859-1"
1316 Subject: [issue1] Testing...
1317 To: chef@bork.bork.bork, richard@test.test
1318 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
1319 Reply-To: Roundup issue tracker
1320  <issue_tracker@your.tracker.email.domain.example>
1321 MIME-Version: 1.0
1322 Message-Id: <followup_dummy_id>
1323 In-Reply-To: <dummy_test_message_id>
1324 X-Roundup-Name: Roundup issue tracker
1325 X-Roundup-Loop: hello
1326 X-Roundup-Issue-Status: chatting
1327 Content-Transfer-Encoding: quoted-printable
1330 Contrary, Mary <mary@test.test> added the comment:
1332 A message with encoding (encoded oe =F6)
1334 ----------
1335 status: unread -> chatting
1337 _______________________________________________________________________
1338 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1339 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1340 _______________________________________________________________________
1341 ''')
1344     def testMultipartEnc01(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;
1354         boundary="----_=_NextPart_000_01"
1356 This message is in MIME format. Since your mail reader does not understand
1357 this format, some or all of this message may not be legible.
1359 ------_=_NextPart_000_01
1360 Content-Type: text/plain;
1361         charset="iso-8859-1"
1362 Content-Transfer-Encoding: quoted-printable
1364 A message with first part encoded (encoded oe =F6)
1366 ''')
1367         self.compareMessages(self._get_mail(),
1368 '''FROM: roundup-admin@your.tracker.email.domain.example
1369 TO: chef@bork.bork.bork, richard@test.test
1370 Content-Type: text/plain; charset="utf-8"
1371 Subject: [issue1] Testing...
1372 To: chef@bork.bork.bork, richard@test.test
1373 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
1374 Reply-To: Roundup issue tracker
1375  <issue_tracker@your.tracker.email.domain.example>
1376 MIME-Version: 1.0
1377 Message-Id: <followup_dummy_id>
1378 In-Reply-To: <dummy_test_message_id>
1379 X-Roundup-Name: Roundup issue tracker
1380 X-Roundup-Loop: hello
1381 X-Roundup-Issue-Status: chatting
1382 Content-Transfer-Encoding: quoted-printable
1385 Contrary, Mary <mary@test.test> added the comment:
1387 A message with first part encoded (encoded oe =C3=B6)
1389 ----------
1390 status: unread -> chatting
1392 _______________________________________________________________________
1393 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1394 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1395 _______________________________________________________________________
1396 ''')
1398     def testContentDisposition(self):
1399         self.doNewIssue()
1400         self._handle_mail('''Content-Type: text/plain;
1401   charset="iso-8859-1"
1402 From: mary <mary@test.test>
1403 To: issue_tracker@your.tracker.email.domain.example
1404 Message-Id: <followup_dummy_id>
1405 In-Reply-To: <dummy_test_message_id>
1406 Subject: [issue1] Testing...
1407 Content-Type: multipart/mixed; boundary="bCsyhTFzCvuiizWE"
1408 Content-Disposition: inline
1411 --bCsyhTFzCvuiizWE
1412 Content-Type: text/plain; charset=us-ascii
1413 Content-Disposition: inline
1415 test attachment binary
1417 --bCsyhTFzCvuiizWE
1418 Content-Type: application/octet-stream
1419 Content-Disposition: attachment; filename="main.dvi"
1420 Content-Transfer-Encoding: base64
1422 SnVzdCBhIHRlc3QgAQo=
1424 --bCsyhTFzCvuiizWE--
1425 ''')
1426         messages = self.db.issue.get('1', 'messages')
1427         messages.sort()
1428         file = self.db.file.getnode (self.db.msg.get(messages[-1], 'files')[0])
1429         self.assertEqual(file.name, 'main.dvi')
1430         self.assertEqual(file.content, 'Just a test \001\n')
1432     def testFollowupStupidQuoting(self):
1433         self.doNewIssue()
1435         self._handle_mail('''Content-Type: text/plain;
1436   charset="iso-8859-1"
1437 From: richard <richard@test.test>
1438 To: issue_tracker@your.tracker.email.domain.example
1439 Message-Id: <followup_dummy_id>
1440 In-Reply-To: <dummy_test_message_id>
1441 Subject: Re: "[issue1] Testing... "
1443 This is a followup
1444 ''')
1445         self.compareMessages(self._get_mail(),
1446 '''FROM: roundup-admin@your.tracker.email.domain.example
1447 TO: chef@bork.bork.bork
1448 Content-Type: text/plain; charset="utf-8"
1449 Subject: [issue1] Testing...
1450 To: chef@bork.bork.bork
1451 From: richard <issue_tracker@your.tracker.email.domain.example>
1452 Reply-To: Roundup issue tracker
1453  <issue_tracker@your.tracker.email.domain.example>
1454 MIME-Version: 1.0
1455 Message-Id: <followup_dummy_id>
1456 In-Reply-To: <dummy_test_message_id>
1457 X-Roundup-Name: Roundup issue tracker
1458 X-Roundup-Loop: hello
1459 X-Roundup-Issue-Status: chatting
1460 Content-Transfer-Encoding: quoted-printable
1463 richard <richard@test.test> added the comment:
1465 This is a followup
1467 ----------
1468 status: unread -> chatting
1470 _______________________________________________________________________
1471 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1472 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1473 _______________________________________________________________________
1474 ''')
1476     def testEmailQuoting(self):
1477         self.instance.config.EMAIL_KEEP_QUOTED_TEXT = 'no'
1478         self.innerTestQuoting('''This is a followup
1479 ''')
1481     def testEmailQuotingRemove(self):
1482         self.instance.config.EMAIL_KEEP_QUOTED_TEXT = 'yes'
1483         self.innerTestQuoting('''Blah blah wrote:
1484 > Blah bklaskdfj sdf asdf jlaskdf skj sdkfjl asdf
1485 >  skdjlkjsdfalsdkfjasdlfkj dlfksdfalksd fj
1488 This is a followup
1489 ''')
1491     def innerTestQuoting(self, expect):
1492         nodeid = self.doNewIssue()
1494         messages = self.db.issue.get(nodeid, 'messages')
1496         self._handle_mail('''Content-Type: text/plain;
1497   charset="iso-8859-1"
1498 From: richard <richard@test.test>
1499 To: issue_tracker@your.tracker.email.domain.example
1500 Message-Id: <followup_dummy_id>
1501 In-Reply-To: <dummy_test_message_id>
1502 Subject: Re: [issue1] Testing...
1504 Blah blah wrote:
1505 > Blah bklaskdfj sdf asdf jlaskdf skj sdkfjl asdf
1506 >  skdjlkjsdfalsdkfjasdlfkj dlfksdfalksd fj
1509 This is a followup
1510 ''')
1511         # figure the new message id
1512         newmessages = self.db.issue.get(nodeid, 'messages')
1513         for msg in messages:
1514             newmessages.remove(msg)
1515         messageid = newmessages[0]
1517         self.compareMessages(self.db.msg.get(messageid, 'content'), expect)
1519     def testUserLookup(self):
1520         i = self.db.user.create(username='user1', address='user1@foo.com')
1521         self.assertEqual(uidFromAddress(self.db, ('', 'user1@foo.com'), 0), i)
1522         self.assertEqual(uidFromAddress(self.db, ('', 'USER1@foo.com'), 0), i)
1523         i = self.db.user.create(username='user2', address='USER2@foo.com')
1524         self.assertEqual(uidFromAddress(self.db, ('', 'USER2@foo.com'), 0), i)
1525         self.assertEqual(uidFromAddress(self.db, ('', 'user2@foo.com'), 0), i)
1527     def testUserAlternateLookup(self):
1528         i = self.db.user.create(username='user1', address='user1@foo.com',
1529                                 alternate_addresses='user1@bar.com')
1530         self.assertEqual(uidFromAddress(self.db, ('', 'user1@bar.com'), 0), i)
1531         self.assertEqual(uidFromAddress(self.db, ('', 'USER1@bar.com'), 0), i)
1533     def testUserCreate(self):
1534         i = uidFromAddress(self.db, ('', 'user@foo.com'), 1)
1535         self.assertNotEqual(uidFromAddress(self.db, ('', 'user@bar.com'), 1), i)
1537     def testRFC2822(self):
1538         ascii_header = "[issue243] This is a \"test\" - with 'quotation' marks"
1539         unicode_header = '[issue244] \xd0\xb0\xd0\xbd\xd0\xb4\xd1\x80\xd0\xb5\xd0\xb9'
1540         unicode_encoded = '=?utf-8?q?[issue244]_=D0=B0=D0=BD=D0=B4=D1=80=D0=B5=D0=B9?='
1541         self.assertEqual(rfc2822.encode_header(ascii_header), ascii_header)
1542         self.assertEqual(rfc2822.encode_header(unicode_header), unicode_encoded)
1544     def testRegistrationConfirmation(self):
1545         otk = "Aj4euk4LZSAdwePohj90SME5SpopLETL"
1546         self.db.getOTKManager().set(otk, username='johannes')
1547         self._handle_mail('''Content-Type: text/plain;
1548   charset="iso-8859-1"
1549 From: Chef <chef@bork.bork.bork>
1550 To: issue_tracker@your.tracker.email.domain.example
1551 Cc: richard@test.test
1552 Message-Id: <dummy_test_message_id>
1553 Subject: Re: Complete your registration to Roundup issue tracker
1554  -- key %s
1556 This is a test confirmation of registration.
1557 ''' % otk)
1558         self.db.user.lookup('johannes')
1560     def testFollowupOnNonIssue(self):
1561         self.db.keyword.create(name='Foo')
1562         self._handle_mail('''Content-Type: text/plain;
1563   charset="iso-8859-1"
1564 From: richard <richard@test.test>
1565 To: issue_tracker@your.tracker.email.domain.example
1566 Message-Id: <followup_dummy_id>
1567 In-Reply-To: <dummy_test_message_id>
1568 Subject: [keyword1] Testing... [name=Bar]
1570 ''')
1571         self.assertEqual(self.db.keyword.get('1', 'name'), 'Bar')
1573     def testResentFrom(self):
1574         nodeid = self._handle_mail('''Content-Type: text/plain;
1575   charset="iso-8859-1"
1576 From: Chef <chef@bork.bork.bork>
1577 Resent-From: mary <mary@test.test>
1578 To: issue_tracker@your.tracker.email.domain.example
1579 Cc: richard@test.test
1580 Message-Id: <dummy_test_message_id>
1581 Subject: [issue] Testing...
1583 This is a test submission of a new issue.
1584 ''')
1585         assert not os.path.exists(SENDMAILDEBUG)
1586         l = self.db.issue.get(nodeid, 'nosy')
1587         l.sort()
1588         self.assertEqual(l, [self.richard_id, self.mary_id])
1589         return nodeid
1591     def testDejaVu(self):
1592         self.assertRaises(IgnoreLoop, self._handle_mail,
1593             '''Content-Type: text/plain;
1594   charset="iso-8859-1"
1595 From: Chef <chef@bork.bork.bork>
1596 X-Roundup-Loop: hello
1597 To: issue_tracker@your.tracker.email.domain.example
1598 Cc: richard@test.test
1599 Message-Id: <dummy_test_message_id>
1600 Subject: Re: [issue] Testing...
1602 Hi, I've been mis-configured to loop messages back to myself.
1603 ''')
1605     def testItsBulkStupid(self):
1606         self.assertRaises(IgnoreBulk, self._handle_mail,
1607             '''Content-Type: text/plain;
1608   charset="iso-8859-1"
1609 From: Chef <chef@bork.bork.bork>
1610 Precedence: bulk
1611 To: issue_tracker@your.tracker.email.domain.example
1612 Cc: richard@test.test
1613 Message-Id: <dummy_test_message_id>
1614 Subject: Re: [issue] Testing...
1616 Hi, I'm on holidays, and this is a dumb auto-responder.
1617 ''')
1619     def testAutoReplyEmailsAreIgnored(self):
1620         self.assertRaises(IgnoreBulk, self._handle_mail,
1621             '''Content-Type: text/plain;
1622   charset="iso-8859-1"
1623 From: Chef <chef@bork.bork.bork>
1624 To: issue_tracker@your.tracker.email.domain.example
1625 Cc: richard@test.test
1626 Message-Id: <dummy_test_message_id>
1627 Subject: Re: [issue] Out of office AutoReply: Back next week
1629 Hi, I am back in the office next week
1630 ''')
1632     def testNoSubject(self):
1633         self.assertRaises(MailUsageError, self._handle_mail,
1634             '''Content-Type: text/plain;
1635   charset="iso-8859-1"
1636 From: Chef <chef@bork.bork.bork>
1637 To: issue_tracker@your.tracker.email.domain.example
1638 Cc: richard@test.test
1639 Reply-To: chef@bork.bork.bork
1640 Message-Id: <dummy_test_message_id>
1642 ''')
1644     #
1645     # TEST FOR INVALID DESIGNATOR HANDLING
1646     #
1647     def testInvalidDesignator(self):
1648         self.assertRaises(MailUsageError, self._handle_mail,
1649             '''Content-Type: text/plain;
1650   charset="iso-8859-1"
1651 From: Chef <chef@bork.bork.bork>
1652 To: issue_tracker@your.tracker.email.domain.example
1653 Subject: [frobulated] testing
1654 Cc: richard@test.test
1655 Reply-To: chef@bork.bork.bork
1656 Message-Id: <dummy_test_message_id>
1658 ''')
1659         self.assertRaises(MailUsageError, self._handle_mail,
1660             '''Content-Type: text/plain;
1661   charset="iso-8859-1"
1662 From: Chef <chef@bork.bork.bork>
1663 To: issue_tracker@your.tracker.email.domain.example
1664 Subject: [issue12345] testing
1665 Cc: richard@test.test
1666 Reply-To: chef@bork.bork.bork
1667 Message-Id: <dummy_test_message_id>
1669 ''')
1671     def testInvalidClassLoose(self):
1672         self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'loose'
1673         nodeid = self._handle_mail('''Content-Type: text/plain;
1674   charset="iso-8859-1"
1675 From: Chef <chef@bork.bork.bork>
1676 To: issue_tracker@your.tracker.email.domain.example
1677 Subject: [frobulated] testing
1678 Cc: richard@test.test
1679 Reply-To: chef@bork.bork.bork
1680 Message-Id: <dummy_test_message_id>
1682 ''')
1683         assert not os.path.exists(SENDMAILDEBUG)
1684         self.assertEqual(self.db.issue.get(nodeid, 'title'),
1685             '[frobulated] testing')
1687     def testInvalidClassLooseReply(self):
1688         self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'loose'
1689         nodeid = self._handle_mail('''Content-Type: text/plain;
1690   charset="iso-8859-1"
1691 From: Chef <chef@bork.bork.bork>
1692 To: issue_tracker@your.tracker.email.domain.example
1693 Subject: Re: [frobulated] testing
1694 Cc: richard@test.test
1695 Reply-To: chef@bork.bork.bork
1696 Message-Id: <dummy_test_message_id>
1698 ''')
1699         assert not os.path.exists(SENDMAILDEBUG)
1700         self.assertEqual(self.db.issue.get(nodeid, 'title'),
1701             '[frobulated] testing')
1703     def testInvalidClassLoose(self):
1704         self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'loose'
1705         nodeid = self._handle_mail('''Content-Type: text/plain;
1706   charset="iso-8859-1"
1707 From: Chef <chef@bork.bork.bork>
1708 To: issue_tracker@your.tracker.email.domain.example
1709 Subject: [issue1234] testing
1710 Cc: richard@test.test
1711 Reply-To: chef@bork.bork.bork
1712 Message-Id: <dummy_test_message_id>
1714 ''')
1715         assert not os.path.exists(SENDMAILDEBUG)
1716         self.assertEqual(self.db.issue.get(nodeid, 'title'),
1717             '[issue1234] testing')
1719     def testClassLooseOK(self):
1720         self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'loose'
1721         self.db.keyword.create(name='Foo')
1722         nodeid = self._handle_mail('''Content-Type: text/plain;
1723   charset="iso-8859-1"
1724 From: Chef <chef@bork.bork.bork>
1725 To: issue_tracker@your.tracker.email.domain.example
1726 Subject: [keyword1] Testing... [name=Bar]
1727 Cc: richard@test.test
1728 Reply-To: chef@bork.bork.bork
1729 Message-Id: <dummy_test_message_id>
1731 ''')
1732         assert not os.path.exists(SENDMAILDEBUG)
1733         self.assertEqual(self.db.keyword.get('1', 'name'), 'Bar')
1735     def testClassStrictInvalid(self):
1736         self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'strict'
1737         self.instance.config.MAILGW_DEFAULT_CLASS = ''
1739         message = '''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...
1744 Cc: richard@test.test
1745 Reply-To: chef@bork.bork.bork
1746 Message-Id: <dummy_test_message_id>
1748 '''
1749         self.assertRaises(MailUsageError, self._handle_mail, message)
1751     def testClassStrictValid(self):
1752         self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'strict'
1753         self.instance.config.MAILGW_DEFAULT_CLASS = ''
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: [issue] Testing...
1760 Cc: richard@test.test
1761 Reply-To: chef@bork.bork.bork
1762 Message-Id: <dummy_test_message_id>
1764 ''')
1766         assert not os.path.exists(SENDMAILDEBUG)
1767         self.assertEqual(self.db.issue.get(nodeid, 'title'), 'Testing...')
1769     #
1770     # TEST FOR INVALID COMMANDS HANDLING
1771     #
1772     def testInvalidCommands(self):
1773         self.assertRaises(MailUsageError, self._handle_mail,
1774             '''Content-Type: text/plain;
1775   charset="iso-8859-1"
1776 From: Chef <chef@bork.bork.bork>
1777 To: issue_tracker@your.tracker.email.domain.example
1778 Subject: testing [frobulated]
1779 Cc: richard@test.test
1780 Reply-To: chef@bork.bork.bork
1781 Message-Id: <dummy_test_message_id>
1783 ''')
1785     def testInvalidCommandPassthrough(self):
1786         self.instance.config.MAILGW_SUBJECT_SUFFIX_PARSING = 'none'
1787         nodeid = self._handle_mail('''Content-Type: text/plain;
1788   charset="iso-8859-1"
1789 From: Chef <chef@bork.bork.bork>
1790 To: issue_tracker@your.tracker.email.domain.example
1791 Subject: testing [frobulated]
1792 Cc: richard@test.test
1793 Reply-To: chef@bork.bork.bork
1794 Message-Id: <dummy_test_message_id>
1796 ''')
1797         assert not os.path.exists(SENDMAILDEBUG)
1798         self.assertEqual(self.db.issue.get(nodeid, 'title'),
1799             'testing [frobulated]')
1801     def testInvalidCommandPassthroughLoose(self):
1802         self.instance.config.MAILGW_SUBJECT_SUFFIX_PARSING = 'loose'
1803         nodeid = self._handle_mail('''Content-Type: text/plain;
1804   charset="iso-8859-1"
1805 From: Chef <chef@bork.bork.bork>
1806 To: issue_tracker@your.tracker.email.domain.example
1807 Subject: testing [frobulated]
1808 Cc: richard@test.test
1809 Reply-To: chef@bork.bork.bork
1810 Message-Id: <dummy_test_message_id>
1812 ''')
1813         assert not os.path.exists(SENDMAILDEBUG)
1814         self.assertEqual(self.db.issue.get(nodeid, 'title'),
1815             'testing [frobulated]')
1817     def testInvalidCommandPassthroughLooseOK(self):
1818         self.instance.config.MAILGW_SUBJECT_SUFFIX_PARSING = 'loose'
1819         nodeid = self._handle_mail('''Content-Type: text/plain;
1820   charset="iso-8859-1"
1821 From: Chef <chef@bork.bork.bork>
1822 To: issue_tracker@your.tracker.email.domain.example
1823 Subject: testing [assignedto=mary]
1824 Cc: richard@test.test
1825 Reply-To: chef@bork.bork.bork
1826 Message-Id: <dummy_test_message_id>
1828 ''')
1829         assert not os.path.exists(SENDMAILDEBUG)
1830         self.assertEqual(self.db.issue.get(nodeid, 'title'), 'testing')
1831         self.assertEqual(self.db.issue.get(nodeid, 'assignedto'), self.mary_id)
1833     def testCommandDelimiters(self):
1834         self.instance.config.MAILGW_SUBJECT_SUFFIX_DELIMITERS = '{}'
1835         nodeid = self._handle_mail('''Content-Type: text/plain;
1836   charset="iso-8859-1"
1837 From: Chef <chef@bork.bork.bork>
1838 To: issue_tracker@your.tracker.email.domain.example
1839 Subject: testing {assignedto=mary}
1840 Cc: richard@test.test
1841 Reply-To: chef@bork.bork.bork
1842 Message-Id: <dummy_test_message_id>
1844 ''')
1845         assert not os.path.exists(SENDMAILDEBUG)
1846         self.assertEqual(self.db.issue.get(nodeid, 'title'), 'testing')
1847         self.assertEqual(self.db.issue.get(nodeid, 'assignedto'), self.mary_id)
1849     def testPrefixDelimiters(self):
1850         self.instance.config.MAILGW_SUBJECT_SUFFIX_DELIMITERS = '{}'
1851         self.db.keyword.create(name='Foo')
1852         self._handle_mail('''Content-Type: text/plain;
1853   charset="iso-8859-1"
1854 From: richard <richard@test.test>
1855 To: issue_tracker@your.tracker.email.domain.example
1856 Message-Id: <followup_dummy_id>
1857 In-Reply-To: <dummy_test_message_id>
1858 Subject: {keyword1} Testing... {name=Bar}
1860 ''')
1861         assert not os.path.exists(SENDMAILDEBUG)
1862         self.assertEqual(self.db.keyword.get('1', 'name'), 'Bar')
1864     def testCommandDelimitersIgnore(self):
1865         self.instance.config.MAILGW_SUBJECT_SUFFIX_DELIMITERS = '{}'
1866         nodeid = self._handle_mail('''Content-Type: text/plain;
1867   charset="iso-8859-1"
1868 From: Chef <chef@bork.bork.bork>
1869 To: issue_tracker@your.tracker.email.domain.example
1870 Subject: testing [assignedto=mary]
1871 Cc: richard@test.test
1872 Reply-To: chef@bork.bork.bork
1873 Message-Id: <dummy_test_message_id>
1875 ''')
1876         assert not os.path.exists(SENDMAILDEBUG)
1877         self.assertEqual(self.db.issue.get(nodeid, 'title'),
1878             'testing [assignedto=mary]')
1879         self.assertEqual(self.db.issue.get(nodeid, 'assignedto'), None)
1881     def testReplytoMatch(self):
1882         self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'loose'
1883         nodeid = self.doNewIssue()
1884         nodeid2 = self._handle_mail('''Content-Type: text/plain;
1885   charset="iso-8859-1"
1886 From: Chef <chef@bork.bork.bork>
1887 To: issue_tracker@your.tracker.email.domain.example
1888 Message-Id: <dummy_test_message_id2>
1889 In-Reply-To: <dummy_test_message_id>
1890 Subject: Testing...
1892 Followup message.
1893 ''')
1895         nodeid3 = self._handle_mail('''Content-Type: text/plain;
1896   charset="iso-8859-1"
1897 From: Chef <chef@bork.bork.bork>
1898 To: issue_tracker@your.tracker.email.domain.example
1899 Message-Id: <dummy_test_message_id3>
1900 In-Reply-To: <dummy_test_message_id2>
1901 Subject: Testing...
1903 Yet another message in the same thread/issue.
1904 ''')
1906         self.assertEqual(nodeid, nodeid2)
1907         self.assertEqual(nodeid, nodeid3)
1909     def testHelpSubject(self):
1910         message = '''Content-Type: text/plain;
1911   charset="iso-8859-1"
1912 From: Chef <chef@bork.bork.bork>
1913 To: issue_tracker@your.tracker.email.domain.example
1914 Message-Id: <dummy_test_message_id2>
1915 In-Reply-To: <dummy_test_message_id>
1916 Subject: hElp
1919 '''
1920         self.assertRaises(MailUsageHelp, self._handle_mail, message)
1922     def testMaillistSubject(self):
1923         self.instance.config.MAILGW_SUBJECT_SUFFIX_DELIMITERS = '[]'
1924         self.db.keyword.create(name='Foo')
1925         self._handle_mail('''Content-Type: text/plain;
1926   charset="iso-8859-1"
1927 From: Chef <chef@bork.bork.bork>
1928 To: issue_tracker@your.tracker.email.domain.example
1929 Subject: [mailinglist-name] [keyword1] Testing.. [name=Bar]
1930 Cc: richard@test.test
1931 Reply-To: chef@bork.bork.bork
1932 Message-Id: <dummy_test_message_id>
1934 ''')
1936         assert not os.path.exists(SENDMAILDEBUG)
1937         self.assertEqual(self.db.keyword.get('1', 'name'), 'Bar')
1939     def testUnknownPrefixSubject(self):
1940         self.db.keyword.create(name='Foo')
1941         self._handle_mail('''Content-Type: text/plain;
1942   charset="iso-8859-1"
1943 From: Chef <chef@bork.bork.bork>
1944 To: issue_tracker@your.tracker.email.domain.example
1945 Subject: VeryStrangeRe: [keyword1] Testing.. [name=Bar]
1946 Cc: richard@test.test
1947 Reply-To: chef@bork.bork.bork
1948 Message-Id: <dummy_test_message_id>
1950 ''')
1952         assert not os.path.exists(SENDMAILDEBUG)
1953         self.assertEqual(self.db.keyword.get('1', 'name'), 'Bar')
1955     def testOneCharSubject(self):
1956         message = '''Content-Type: text/plain;
1957   charset="iso-8859-1"
1958 From: Chef <chef@bork.bork.bork>
1959 To: issue_tracker@your.tracker.email.domain.example
1960 Subject: b
1961 Cc: richard@test.test
1962 Reply-To: chef@bork.bork.bork
1963 Message-Id: <dummy_test_message_id>
1965 '''
1966         try:
1967             self._handle_mail(message)
1968         except MailUsageError:
1969             self.fail('MailUsageError raised')
1971     def testIssueidLast(self):
1972         nodeid1 = self.doNewIssue()
1973         nodeid2 = self._handle_mail('''Content-Type: text/plain;
1974   charset="iso-8859-1"
1975 From: mary <mary@test.test>
1976 To: issue_tracker@your.tracker.email.domain.example
1977 Message-Id: <followup_dummy_id>
1978 In-Reply-To: <dummy_test_message_id>
1979 Subject: New title [issue1]
1981 This is a second followup
1982 ''')
1984         assert nodeid1 == nodeid2
1985         self.assertEqual(self.db.issue.get(nodeid2, 'title'), "Testing...")
1987     def testSecurityMessagePermissionContent(self):
1988         id = self.doNewIssue()
1989         issue = self.db.issue.getnode (id)
1990         self.db.security.addRole(name='Nomsg')
1991         self.db.security.addPermissionToRole('Nomsg', 'Email Access')
1992         for cl in 'issue', 'file', 'keyword':
1993             for p in 'View', 'Edit', 'Create':
1994                 self.db.security.addPermissionToRole('Nomsg', p, cl)
1995         self.db.user.set(self.mary_id, roles='Nomsg')
1996         nodeid = self._handle_mail('''Content-Type: text/plain;
1997   charset="iso-8859-1"
1998 From: Chef <chef@bork.bork.bork>
1999 To: issue_tracker@your.tracker.email.domain.example
2000 Message-Id: <dummy_test_message_id_2>
2001 Subject: [issue%(id)s] Testing... [nosy=+mary]
2003 Just a test reply
2004 '''%locals())
2005         assert os.path.exists(SENDMAILDEBUG)
2006         self.compareMessages(self._get_mail(),
2007 '''FROM: roundup-admin@your.tracker.email.domain.example
2008 TO: chef@bork.bork.bork, richard@test.test
2009 Content-Type: text/plain; charset="utf-8"
2010 Subject: [issue1] Testing...
2011 To: richard@test.test
2012 From: "Bork, Chef" <issue_tracker@your.tracker.email.domain.example>
2013 Reply-To: Roundup issue tracker
2014  <issue_tracker@your.tracker.email.domain.example>
2015 MIME-Version: 1.0
2016 Message-Id: <dummy_test_message_id_2>
2017 In-Reply-To: <dummy_test_message_id>
2018 X-Roundup-Name: Roundup issue tracker
2019 X-Roundup-Loop: hello
2020 X-Roundup-Issue-Status: chatting
2021 Content-Transfer-Encoding: quoted-printable
2024 Bork, Chef <chef@bork.bork.bork> added the comment:
2026 Just a test reply
2028 ----------
2029 nosy: +mary
2030 status: unread -> chatting
2032 _______________________________________________________________________
2033 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
2034 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
2035 _______________________________________________________________________
2036 ''')
2038     def testOutlookAttachment(self):
2039         message = '''X-MimeOLE: Produced By Microsoft Exchange V6.5
2040 Content-class: urn:content-classes:message
2041 MIME-Version: 1.0
2042 Content-Type: multipart/mixed;
2043         boundary="----_=_NextPart_001_01CACA65.40A51CBC"
2044 Subject: Example of a failed outlook attachment e-mail
2045 Date: Tue, 23 Mar 2010 01:43:44 -0700
2046 Message-ID: <CA37F17219784343816CA6613D2E339205E7D0F9@nrcwstexb1.nrc.ca>
2047 X-MS-Has-Attach: yes
2048 X-MS-TNEF-Correlator: 
2049 Thread-Topic: Example of a failed outlook attachment e-mail
2050 Thread-Index: AcrKJo/t3pUBBwTpSwWNE3LE67UBDQ==
2051 From: "Hugh" <richard@test.test>
2052 To: <richard@test.test>
2053 X-OriginalArrivalTime: 23 Mar 2010 08:45:57.0350 (UTC) FILETIME=[41893860:01CACA65]
2055 This is a multi-part message in MIME format.
2057 ------_=_NextPart_001_01CACA65.40A51CBC
2058 Content-Type: multipart/alternative;
2059         boundary="----_=_NextPart_002_01CACA65.40A51CBC"
2062 ------_=_NextPart_002_01CACA65.40A51CBC
2063 Content-Type: text/plain;
2064         charset="us-ascii"
2065 Content-Transfer-Encoding: quoted-printable
2068 Hi Richard,
2070 I suppose this isn't the exact message that was sent but is a resend of
2071 one of my trial messages that failed.  For your benefit I changed the
2072 subject line and am adding these words to the message body.  Should
2073 still be as problematic, but if you like I can resend an exact copy of a
2074 failed message changing nothing except putting your address instead of
2075 our tracker.
2077 Thanks very much for taking time to look into this.  Much appreciated.
2079  <<battery backup>>=20
2081 ------_=_NextPart_002_01CACA65.40A51CBC
2082 Content-Type: text/html;
2083         charset="us-ascii"
2084 Content-Transfer-Encoding: quoted-printable
2086 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
2087 <HTML>
2088 <HEAD>
2089 <META HTTP-EQUIV=3D"Content-Type" CONTENT=3D"text/html; =
2090 charset=3Dus-ascii">
2091 <META NAME=3D"Generator" CONTENT=3D"MS Exchange Server version =
2092 6.5.7654.12">
2093 <TITLE>Example of a failed outlook attachment e-mail</TITLE>
2094 </HEAD>
2095 <BODY>
2096 <!-- Converted from text/rtf format -->
2097 <BR>
2099 <P><FONT SIZE=3D2 FACE=3D"Arial">Hi Richard,</FONT>
2100 </P>
2102 <P><FONT SIZE=3D2 FACE=3D"Arial">I suppose this isn't the exact message =
2103 that was sent but is a resend of one of my trial messages that =
2104 failed.&nbsp; For your benefit I changed the subject line and am adding =
2105 these words to the message body.&nbsp; Should still be as problematic, =
2106 but if you like I can resend an exact copy of a failed message changing =
2107 nothing except putting your address instead of our tracker.</FONT></P>
2109 <P><FONT SIZE=3D2 FACE=3D"Arial">Thanks very much for taking time to =
2110 look into this.&nbsp; Much appreciated.</FONT>
2111 </P>
2112 <BR>
2114 <P><FONT FACE=3D"Arial" SIZE=3D2 COLOR=3D"#000000"> &lt;&lt;battery =
2115 backup&gt;&gt; </FONT>
2116 </P>
2118 </BODY>
2119 </HTML>
2120 ------_=_NextPart_002_01CACA65.40A51CBC--
2122 ------_=_NextPart_001_01CACA65.40A51CBC
2123 Content-Type: message/rfc822
2124 Content-Transfer-Encoding: 7bit
2126 X-MimeOLE: Produced By Microsoft Exchange V6.5
2127 MIME-Version: 1.0
2128 Content-Type: multipart/alternative;
2129         boundary="----_=_NextPart_003_01CAC15A.29717800"
2130 X-OriginalArrivalTime: 11 Mar 2010 20:33:51.0249 (UTC) FILETIME=[28FEE010:01CAC15A]
2131 Content-class: urn:content-classes:message
2132 Subject: battery backup
2133 Date: Thu, 11 Mar 2010 13:33:43 -0700
2134 Message-ID: <p06240809c7bf02f9624c@[128.114.22.203]>
2135 X-MS-Has-Attach: 
2136 X-MS-TNEF-Correlator: 
2137 Thread-Topic: battery backup
2138 Thread-Index: AcrBWimtulTrSvBdQ2CcfZ8lyQdxmQ==
2139 From: "Jerry" <jerry@test.test>
2140 To: "Hugh" <hugh@test.test>
2142 This is a multi-part message in MIME format.
2144 ------_=_NextPart_003_01CAC15A.29717800
2145 Content-Type: text/plain;
2146         charset="iso-8859-1"
2147 Content-Transfer-Encoding: quoted-printable
2149 Dear Hugh,
2150         A car batter has an energy capacity of ~ 500Wh.  A UPS=20
2151 battery is worse than this.
2153 if we need to provied 100kW for 30 minutes that will take 100 car=20
2154 batteries.  This seems like an awful lot of batteries.
2156 Of course I like your idea of making the time 1 minute, so we get to=20
2157 a more modest number of batteries
2159 Jerry
2162 ------_=_NextPart_003_01CAC15A.29717800
2163 Content-Type: text/html;
2164         charset="iso-8859-1"
2165 Content-Transfer-Encoding: quoted-printable
2167 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
2168 <HTML>
2169 <HEAD>
2170 <META HTTP-EQUIV=3D"Content-Type" CONTENT=3D"text/html; =
2171 charset=3Diso-8859-1">
2172 <META NAME=3D"Generator" CONTENT=3D"MS Exchange Server version =
2173 6.5.7654.12">
2174 <TITLE>battery backup</TITLE>
2175 </HEAD>
2176 <BODY>
2177 <!-- Converted from text/plain format -->
2179 <P><FONT SIZE=3D2>Dear Hugh,</FONT>
2181 <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <FONT SIZE=3D2>A car =
2182 batter has an energy capacity of ~ 500Wh.&nbsp; A UPS </FONT>
2184 <BR><FONT SIZE=3D2>battery is worse than this.</FONT>
2185 </P>
2187 <P><FONT SIZE=3D2>if we need to provied 100kW for 30 minutes that will =
2188 take 100 car </FONT>
2190 <BR><FONT SIZE=3D2>batteries.&nbsp; This seems like an awful lot of =
2191 batteries.</FONT>
2192 </P>
2194 <P><FONT SIZE=3D2>Of course I like your idea of making the time 1 =
2195 minute, so we get to </FONT>
2197 <BR><FONT SIZE=3D2>a more modest number of batteries</FONT>
2198 </P>
2200 <P><FONT SIZE=3D2>Jerry</FONT>
2201 </P>
2203 </BODY>
2204 </HTML>
2205 ------_=_NextPart_003_01CAC15A.29717800--
2207 ------_=_NextPart_001_01CACA65.40A51CBC--
2208 '''
2209         nodeid = self._handle_mail(message)
2210         assert not os.path.exists(SENDMAILDEBUG)
2211         msgid = self.db.issue.get(nodeid, 'messages')[0]
2212         self.assert_(self.db.msg.get(msgid, 'content').startswith('Hi Richard'))
2213         self.assertEqual(self.db.msg.get(msgid, 'files'), ['1', '2'])
2214         fileid = self.db.msg.get(msgid, 'files')[0]
2215         self.assertEqual(self.db.file.get(fileid, 'type'), 'text/html')
2216         fileid = self.db.msg.get(msgid, 'files')[1]
2217         self.assertEqual(self.db.file.get(fileid, 'type'), 'message/rfc822')
2219     def testForwardedMessageAttachment(self):
2220         message = '''Return-Path: <rgg@test.test>
2221 Received: from localhost(127.0.0.1), claiming to be "[115.130.26.69]"
2222 via SMTP by localhost, id smtpdAAApLaWrq; Tue Apr 13 23:10:05 2010
2223 Message-ID: <4BC4F9C7.50409@test.test>
2224 Date: Wed, 14 Apr 2010 09:09:59 +1000
2225 From: Rupert Goldie <rgg@test.test>
2226 User-Agent: Thunderbird 2.0.0.24 (Windows/20100228)
2227 MIME-Version: 1.0
2228 To: ekit issues <issues@test.test>
2229 Subject: [Fwd: PHP ERROR (fb)] post limit reached
2230 Content-Type: multipart/mixed; boundary="------------000807090608060304010403"
2232 This is a multi-part message in MIME format.
2233 --------------000807090608060304010403
2234 Content-Type: text/plain; charset=ISO-8859-1; format=flowed
2235 Content-Transfer-Encoding: 7bit
2237 Catch this exception and log it without emailing.
2239 --------------000807090608060304010403
2240 Content-Type: message/rfc822; name="PHP ERROR (fb).eml"
2241 Content-Transfer-Encoding: 7bit
2242 Content-Disposition: inline; filename="PHP ERROR (fb).eml"
2244 Return-Path: <ektravj@test.test>
2245 X-Sieve: CMU Sieve 2.2
2246 via SMTP by crown.off.ekorp.com, id smtpdAAA1JaW1o; Tue Apr 13 23:01:04 2010
2247 X-Virus-Scanned: by amavisd-new at ekit.com
2248 To: facebook-errors@test.test
2249 From: ektravj@test.test
2250 Subject: PHP ERROR (fb)
2251 Message-Id: <20100413230100.D601D27E84@mail2.elax3.ekorp.com>
2252 Date: Tue, 13 Apr 2010 23:01:00 +0000 (UTC)
2254 [13-Apr-2010 22:49:02] PHP Fatal error:  Uncaught exception 'Exception' with message 'Facebook Error Message: Feed action request limit reached' in /app/01/www/virtual/fb.ekit.com/htdocs/includes/functions.php:280
2255 Stack trace:
2256 #0 /app/01/www/virtual/fb.ekit.com/htdocs/gateway/ekit/feed/index.php(178): fb_exceptions(Object(FacebookRestClientException))
2257 #1 {main}
2258  thrown in /app/01/www/virtual/fb.ekit.com/htdocs/includes/functions.php on line 280
2261 --------------000807090608060304010403--
2262 '''
2263         nodeid = self._handle_mail(message)
2264         assert not os.path.exists(SENDMAILDEBUG)
2265         msgid = self.db.issue.get(nodeid, 'messages')[0]
2266         self.assertEqual(self.db.msg.get(msgid, 'content'),
2267             'Catch this exception and log it without emailing.')
2268         self.assertEqual(self.db.msg.get(msgid, 'files'), ['1'])
2269         fileid = self.db.msg.get(msgid, 'files')[0]
2270         self.assertEqual(self.db.file.get(fileid, 'type'), 'message/rfc822')
2272 def test_suite():
2273     suite = unittest.TestSuite()
2274     suite.addTest(unittest.makeSuite(MailgwTestCase))
2275     return suite
2277 if __name__ == '__main__':
2278     runner = unittest.TextTestRunner()
2279     unittest.main(testRunner=runner)
2281 # vim: set filetype=python sts=4 sw=4 et si :