Code

- Add regression test for -c option to mailgw -- bug in issue2550697
[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 import mailgw, i18n, roundupdb
25 from roundup.mailgw import MailGW, Unauthorized, uidFromAddress, \
26     parseContent, IgnoreLoop, IgnoreBulk, MailUsageError, MailUsageHelp
27 from roundup import init, instance, password, rfc2822, __version__
28 from roundup.anypy.sets_ import set
30 #import db_test_base
31 import memorydb
33 class Message(rfc822.Message):
34     """String-based Message class with equivalence test."""
35     def __init__(self, s):
36         rfc822.Message.__init__(self, StringIO(s.strip()))
38     def __eq__(self, other):
39         return (self.dict == other.dict and
40                 self.fp.read() == other.fp.read())
42 class Tracker(object):
43     def open(self, journaltag):
44         return self.db
46 class DiffHelper:
47     def compareMessages(self, new, old):
48         """Compare messages for semantic equivalence."""
49         new, old = Message(new), Message(old)
51         # all Roundup-generated messages have "Precedence: bulk"
52         old['Precedence'] = 'bulk'
54         # don't try to compare the date
55         del new['date'], old['date']
57         if not new == old:
58             res = []
60             replace = {}
61             for key in new.keys():
62                 if key.startswith('from '):
63                     # skip the unix from line
64                     continue
65                 if key.lower() == 'x-roundup-version':
66                     # version changes constantly, so handle it specially
67                     if new[key] != __version__:
68                         res.append('  %s: %r != %r' % (key, __version__,
69                             new[key]))
70                 elif key.lower() == 'content-type' and 'boundary=' in new[key]:
71                     # handle mime messages
72                     newmime = new[key].split('=',1)[-1].strip('"')
73                     oldmime = old.get(key, '').split('=',1)[-1].strip('"')
74                     replace ['--' + newmime] = '--' + oldmime
75                     replace ['--' + newmime + '--'] = '--' + oldmime + '--'
76                 elif new.get(key, '') != old.get(key, ''):
77                     res.append('  %s: %r != %r' % (key, old.get(key, ''),
78                         new.get(key, '')))
80             body_diff = self.compareStrings(new.fp.read(), old.fp.read(),
81                 replace=replace)
82             if body_diff:
83                 res.append('')
84                 res.extend(body_diff)
86             if res:
87                 res.insert(0, 'Generated message not correct (diff follows, expected vs. actual):')
88                 raise AssertionError, '\n'.join(res)
90     def compareStrings(self, s2, s1, replace={}):
91         '''Note the reversal of s2 and s1 - difflib.SequenceMatcher wants
92            the first to be the "original" but in the calls in this file,
93            the second arg is the original. Ho hum.
94            Do replacements over the replace dict -- used for mime boundary
95         '''
96         l1 = s1.strip().split('\n')
97         l2 = [replace.get(i,i) for i in s2.strip().split('\n')]
98         if l1 == l2:
99             return
100         s = difflib.SequenceMatcher(None, l1, l2)
101         res = []
102         for value, s1s, s1e, s2s, s2e in s.get_opcodes():
103             if value == 'equal':
104                 for i in range(s1s, s1e):
105                     res.append('  %s'%l1[i])
106             elif value == 'delete':
107                 for i in range(s1s, s1e):
108                     res.append('- %s'%l1[i])
109             elif value == 'insert':
110                 for i in range(s2s, s2e):
111                     res.append('+ %s'%l2[i])
112             elif value == 'replace':
113                 for i, j in zip(range(s1s, s1e), range(s2s, s2e)):
114                     res.append('- %s'%l1[i])
115                     res.append('+ %s'%l2[j])
117         return res
119 class MailgwTestCase(unittest.TestCase, DiffHelper):
120     count = 0
121     schema = 'classic'
122     def setUp(self):
123         self.old_translate_ = mailgw._
124         roundupdb._ = mailgw._ = i18n.get_translation(language='C').gettext
125         MailgwTestCase.count = MailgwTestCase.count + 1
127         # and open the database / "instance"
128         self.db = memorydb.create('admin')
129         self.instance = Tracker()
130         self.instance.db = self.db
131         self.instance.config = self.db.config
132         self.instance.MailGW = MailGW
134         self.chef_id = self.db.user.create(username='Chef',
135             address='chef@bork.bork.bork', realname='Bork, Chef', roles='User')
136         self.richard_id = self.db.user.create(username='richard',
137             address='richard@test.test', roles='User')
138         self.mary_id = self.db.user.create(username='mary',
139             address='mary@test.test', roles='User', realname='Contrary, Mary')
140         self.john_id = self.db.user.create(username='john',
141             address='john@test.test', roles='User', realname='John Doe',
142             alternate_addresses='jondoe@test.test\njohn.doe@test.test')
143         self.rgg_id = self.db.user.create(username='rgg',
144             address='rgg@test.test', roles='User')
146     def tearDown(self):
147         roundupdb._ = mailgw._ = self.old_translate_
148         if os.path.exists(SENDMAILDEBUG):
149             os.remove(SENDMAILDEBUG)
150         self.db.close()
152     def _create_mailgw(self, message, args=()):
153         class MailGW(self.instance.MailGW):
154             def handle_message(self, message):
155                 return self._handle_message(message)
156         handler = MailGW(self.instance, args)
157         handler.db = self.db
158         return handler
160     def _handle_mail(self, message, args=()):
161         handler = self._create_mailgw(message, args)
162         handler.trapExceptions = 0
163         return handler.main(StringIO(message))
165     def _get_mail(self):
166         f = open(SENDMAILDEBUG)
167         try:
168             return f.read()
169         finally:
170             f.close()
172     def testEmptyMessage(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 ''')
183         assert not os.path.exists(SENDMAILDEBUG)
184         self.assertEqual(self.db.issue.get(nodeid, 'title'), 'Testing...')
186     def testMessageWithFromInIt(self):
187         nodeid = self._handle_mail('''Content-Type: text/plain;
188   charset="iso-8859-1"
189 From: Chef <chef@bork.bork.bork>
190 To: issue_tracker@your.tracker.email.domain.example
191 Cc: richard@test.test
192 Reply-To: chef@bork.bork.bork
193 Message-Id: <dummy_test_message_id>
194 Subject: [issue] Testing...
196 From here to there!
197 ''')
198         assert not os.path.exists(SENDMAILDEBUG)
199         msgid = self.db.issue.get(nodeid, 'messages')[0]
200         self.assertEqual(self.db.msg.get(msgid, 'content'), 'From here to there!')
202     def testNoMessageId(self):
203         self.instance.config['MAIL_DOMAIN'] = 'example.com'
204         nodeid = self._handle_mail('''Content-Type: text/plain;
205   charset="iso-8859-1"
206 From: Chef <chef@bork.bork.bork>
207 To: issue_tracker@your.tracker.email.domain.example
208 Cc: richard@test.test
209 Reply-To: chef@bork.bork.bork
210 Subject: [issue] Testing...
212 Hi there!
213 ''')
214         assert not os.path.exists(SENDMAILDEBUG)
215         msgid = self.db.issue.get(nodeid, 'messages')[0]
216         messageid = self.db.msg.get(msgid, 'messageid')
217         x1, x2 = messageid.split('@')
218         self.assertEqual(x2, 'example.com>')
219         x = x1.split('.')[-1]
220         self.assertEqual(x, 'issueNone')
221         nodeid = self._handle_mail('''Content-Type: text/plain;
222   charset="iso-8859-1"
223 From: Chef <chef@bork.bork.bork>
224 To: issue_tracker@your.tracker.email.domain.example
225 Subject: [issue%(nodeid)s] Testing...
227 Just a test reply
228 '''%locals())
229         msgid = self.db.issue.get(nodeid, 'messages')[-1]
230         messageid = self.db.msg.get(msgid, 'messageid')
231         x1, x2 = messageid.split('@')
232         self.assertEqual(x2, 'example.com>')
233         x = x1.split('.')[-1]
234         self.assertEqual(x, "issue%s"%nodeid)
236     def testOptions(self):
237         nodeid = self._handle_mail('''Content-Type: text/plain;
238   charset="iso-8859-1"
239 From: Chef <chef@bork.bork.bork>
240 To: issue_tracker@your.tracker.email.domain.example
241 Message-Id: <dummy_test_message_id>
242 Reply-To: chef@bork.bork.bork
243 Subject: [issue] Testing...
245 Hi there!
246 ''', (('-C', 'issue'), ('-S', 'status=chatting;priority=critical')))
247         self.assertEqual(self.db.issue.get(nodeid, 'status'), '3')
248         self.assertEqual(self.db.issue.get(nodeid, 'priority'), '1')
250     def testOptionsMulti(self):
251         nodeid = 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 Message-Id: <dummy_test_message_id>
256 Reply-To: chef@bork.bork.bork
257 Subject: [issue] Testing...
259 Hi there!
260 ''', (('-C', 'issue'), ('-S', 'status=chatting'), ('-S', 'priority=critical')))
261         self.assertEqual(self.db.issue.get(nodeid, 'status'), '3')
262         self.assertEqual(self.db.issue.get(nodeid, 'priority'), '1')
264     def testOptionClass(self):
265         nodeid = self._handle_mail('''Content-Type: text/plain;
266   charset="iso-8859-1"
267 From: Chef <chef@bork.bork.bork>
268 To: issue_tracker@your.tracker.email.domain.example
269 Message-Id: <dummy_test_message_id>
270 Reply-To: chef@bork.bork.bork
271 Subject: [issue] Testing...
273 Hi there!
274 ''', (('-c', 'issue'),))
275         self.assertEqual(self.db.issue.get(nodeid, 'status'), '3')
276         self.assertEqual(self.db.issue.get(nodeid, 'priority'), '1')
278     def doNewIssue(self):
279         nodeid = self._handle_mail('''Content-Type: text/plain;
280   charset="iso-8859-1"
281 From: Chef <chef@bork.bork.bork>
282 To: issue_tracker@your.tracker.email.domain.example
283 Cc: richard@test.test
284 Message-Id: <dummy_test_message_id>
285 Subject: [issue] Testing...
287 This is a test submission of a new issue.
288 ''')
289         assert not os.path.exists(SENDMAILDEBUG)
290         l = self.db.issue.get(nodeid, 'nosy')
291         l.sort()
292         self.assertEqual(l, [self.chef_id, self.richard_id])
293         return nodeid
295     def testNewIssue(self):
296         self.doNewIssue()
298     def testNewIssueNosy(self):
299         self.instance.config.ADD_AUTHOR_TO_NOSY = 'yes'
300         nodeid = self._handle_mail('''Content-Type: text/plain;
301   charset="iso-8859-1"
302 From: Chef <chef@bork.bork.bork>
303 To: issue_tracker@your.tracker.email.domain.example
304 Cc: richard@test.test
305 Message-Id: <dummy_test_message_id>
306 Subject: [issue] Testing...
308 This is a test submission of a new issue.
309 ''')
310         assert not os.path.exists(SENDMAILDEBUG)
311         l = self.db.issue.get(nodeid, 'nosy')
312         l.sort()
313         self.assertEqual(l, [self.chef_id, self.richard_id])
315     def testAlternateAddress(self):
316         self._handle_mail('''Content-Type: text/plain;
317   charset="iso-8859-1"
318 From: John Doe <john.doe@test.test>
319 To: issue_tracker@your.tracker.email.domain.example
320 Message-Id: <dummy_test_message_id>
321 Subject: [issue] Testing...
323 This is a test submission of a new issue.
324 ''')
325         userlist = self.db.user.list()
326         assert not os.path.exists(SENDMAILDEBUG)
327         self.assertEqual(userlist, self.db.user.list(),
328             "user created when it shouldn't have been")
330     def testNewIssueNoClass(self):
331         self._handle_mail('''Content-Type: text/plain;
332   charset="iso-8859-1"
333 From: Chef <chef@bork.bork.bork>
334 To: issue_tracker@your.tracker.email.domain.example
335 Cc: richard@test.test
336 Message-Id: <dummy_test_message_id>
337 Subject: Testing...
339 This is a test submission of a new issue.
340 ''')
341         assert not os.path.exists(SENDMAILDEBUG)
343     def testNewIssueAuthMsg(self):
344         # TODO: fix the damn config - this is apalling
345         self.db.config.MESSAGES_TO_AUTHOR = 'yes'
346         self._handle_mail('''Content-Type: text/plain;
347   charset="iso-8859-1"
348 From: Chef <chef@bork.bork.bork>
349 To: issue_tracker@your.tracker.email.domain.example
350 Message-Id: <dummy_test_message_id>
351 Subject: [issue] Testing... [nosy=mary; assignedto=richard]
353 This is a test submission of a new issue.
354 ''')
355         self.compareMessages(self._get_mail(),
356 '''FROM: roundup-admin@your.tracker.email.domain.example
357 TO: chef@bork.bork.bork, mary@test.test, richard@test.test
358 Content-Type: text/plain; charset="utf-8"
359 Subject: [issue1] Testing...
360 To: chef@bork.bork.bork, mary@test.test, richard@test.test
361 From: "Bork, Chef" <issue_tracker@your.tracker.email.domain.example>
362 Reply-To: Roundup issue tracker
363  <issue_tracker@your.tracker.email.domain.example>
364 MIME-Version: 1.0
365 Message-Id: <dummy_test_message_id>
366 X-Roundup-Name: Roundup issue tracker
367 X-Roundup-Loop: hello
368 X-Roundup-Issue-Status: unread
369 Content-Transfer-Encoding: quoted-printable
372 New submission from Bork, Chef <chef@bork.bork.bork>:
374 This is a test submission of a new issue.
376 ----------
377 assignedto: richard
378 messages: 1
379 nosy: Chef, mary, richard
380 status: unread
381 title: Testing...
383 _______________________________________________________________________
384 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
385 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
386 _______________________________________________________________________
387 ''')
389     def testNewIssueNoAuthorInfo(self):
390         self.db.config.MAIL_ADD_AUTHORINFO = 'no'
391         self._handle_mail('''Content-Type: text/plain;
392   charset="iso-8859-1"
393 From: Chef <chef@bork.bork.bork>
394 To: issue_tracker@your.tracker.email.domain.example
395 Message-Id: <dummy_test_message_id>
396 Subject: [issue] Testing... [nosy=mary; assignedto=richard]
398 This is a test submission of a new issue.
399 ''')
400         self.compareMessages(self._get_mail(),
401 '''FROM: roundup-admin@your.tracker.email.domain.example
402 TO: chef@bork.bork.bork, mary@test.test, richard@test.test
403 Content-Type: text/plain; charset="utf-8"
404 Subject: [issue1] Testing...
405 To: mary@test.test, richard@test.test
406 From: "Bork, Chef" <issue_tracker@your.tracker.email.domain.example>
407 Reply-To: Roundup issue tracker
408  <issue_tracker@your.tracker.email.domain.example>
409 MIME-Version: 1.0
410 Message-Id: <dummy_test_message_id>
411 X-Roundup-Name: Roundup issue tracker
412 X-Roundup-Loop: hello
413 X-Roundup-Issue-Status: unread
414 Content-Transfer-Encoding: quoted-printable
416 This is a test submission of a new issue.
418 ----------
419 assignedto: richard
420 messages: 1
421 nosy: Chef, mary, richard
422 status: unread
423 title: Testing...
425 _______________________________________________________________________
426 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
427 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
428 _______________________________________________________________________
429 ''')
431     def testNewIssueNoAuthorEmail(self):
432         self.db.config.MAIL_ADD_AUTHOREMAIL = 'no'
433         self._handle_mail('''Content-Type: text/plain;
434   charset="iso-8859-1"
435 From: Chef <chef@bork.bork.bork>
436 To: issue_tracker@your.tracker.email.domain.example
437 Message-Id: <dummy_test_message_id>
438 Subject: [issue] Testing... [nosy=mary; assignedto=richard]
440 This is a test submission of a new issue.
441 ''')
442         self.compareMessages(self._get_mail(),
443 '''FROM: roundup-admin@your.tracker.email.domain.example
444 TO: chef@bork.bork.bork, mary@test.test, richard@test.test
445 Content-Type: text/plain; charset="utf-8"
446 Subject: [issue1] Testing...
447 To: mary@test.test, richard@test.test
448 From: "Bork, Chef" <issue_tracker@your.tracker.email.domain.example>
449 Reply-To: Roundup issue tracker
450  <issue_tracker@your.tracker.email.domain.example>
451 MIME-Version: 1.0
452 Message-Id: <dummy_test_message_id>
453 X-Roundup-Name: Roundup issue tracker
454 X-Roundup-Loop: hello
455 X-Roundup-Issue-Status: unread
456 Content-Transfer-Encoding: quoted-printable
458 New submission from Bork, Chef:
460 This is a test submission of a new issue.
462 ----------
463 assignedto: richard
464 messages: 1
465 nosy: Chef, mary, richard
466 status: unread
467 title: Testing...
469 _______________________________________________________________________
470 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
471 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
472 _______________________________________________________________________
473 ''')
475     multipart_msg = '''From: mary <mary@test.test>
476 To: issue_tracker@your.tracker.email.domain.example
477 Message-Id: <followup_dummy_id>
478 In-Reply-To: <dummy_test_message_id>
479 Subject: [issue1] Testing...
480 Content-Type: multipart/mixed; boundary="bxyzzy"
481 Content-Disposition: inline
484 --bxyzzy
485 Content-Type: multipart/alternative; boundary="bCsyhTFzCvuiizWE"
486 Content-Disposition: inline
488 --bCsyhTFzCvuiizWE
489 Content-Type: text/plain; charset=us-ascii
490 Content-Disposition: inline
492 test attachment first text/plain
494 --bCsyhTFzCvuiizWE
495 Content-Type: application/octet-stream
496 Content-Disposition: attachment; filename="first.dvi"
497 Content-Transfer-Encoding: base64
499 SnVzdCBhIHRlc3QgAQo=
501 --bCsyhTFzCvuiizWE
502 Content-Type: text/plain; charset=us-ascii
503 Content-Disposition: inline
505 test attachment second text/plain
507 --bCsyhTFzCvuiizWE
508 Content-Type: text/html
509 Content-Disposition: inline
511 <html>
512 to be ignored.
513 </html>
515 --bCsyhTFzCvuiizWE--
517 --bxyzzy
518 Content-Type: multipart/alternative; boundary="bCsyhTFzCvuiizWF"
519 Content-Disposition: inline
521 --bCsyhTFzCvuiizWF
522 Content-Type: text/plain; charset=us-ascii
523 Content-Disposition: inline
525 test attachment third text/plain
527 --bCsyhTFzCvuiizWF
528 Content-Type: application/octet-stream
529 Content-Disposition: attachment; filename="second.dvi"
530 Content-Transfer-Encoding: base64
532 SnVzdCBhIHRlc3QK
534 --bCsyhTFzCvuiizWF--
536 --bxyzzy--
537 '''
539     multipart_msg_latin1 = '''From: mary <mary@test.test>
540 To: issue_tracker@your.tracker.email.domain.example
541 Message-Id: <followup_dummy_id>
542 In-Reply-To: <dummy_test_message_id>
543 Subject: [issue1] Testing...
544 Content-Type: multipart/alternative; boundary=001485f339f8f361fb049188dbba
547 --001485f339f8f361fb049188dbba
548 Content-Type: text/plain; charset=ISO-8859-1
549 Content-Transfer-Encoding: quoted-printable
551 umlaut =E4=F6=FC=C4=D6=DC=DF
553 --001485f339f8f361fb049188dbba
554 Content-Type: text/html; charset=ISO-8859-1
555 Content-Transfer-Encoding: quoted-printable
557 <html>umlaut =E4=F6=FC=C4=D6=DC=DF</html>
559 --001485f339f8f361fb049188dbba--
560 '''
562     multipart_msg_rfc822 = '''From: mary <mary@test.test>
563 To: issue_tracker@your.tracker.email.domain.example
564 Message-Id: <followup_dummy_id>
565 In-Reply-To: <dummy_test_message_id>
566 Subject: [issue1] Testing...
567 Content-Type: multipart/mixed; boundary=001485f339f8f361fb049188dbba
569 This is a multi-part message in MIME format.
570 --001485f339f8f361fb049188dbba
571 Content-Type: text/plain; charset=ISO-8859-15
572 Content-Transfer-Encoding: 7bit
574 First part: Text
576 --001485f339f8f361fb049188dbba
577 Content-Type: message/rfc822; name="Fwd: Original email subject.eml"
578 Content-Transfer-Encoding: 7bit
579 Content-Disposition: attachment; filename="Fwd: Original email subject.eml"
581 Message-Id: <followup_dummy_id_2>
582 In-Reply-To: <dummy_test_message_id_2>
583 MIME-Version: 1.0
584 Subject: Fwd: Original email subject
585 Date: Mon, 23 Aug 2010 08:23:33 +0200
586 Content-Type: multipart/alternative; boundary="090500050101020406060002"
588 This is a multi-part message in MIME format.
589 --090500050101020406060002
590 Content-Type: text/plain; charset=ISO-8859-15; format=flowed
591 Content-Transfer-Encoding: 7bit
593 some text in inner email
594 ========================
596 --090500050101020406060002
597 Content-Type: text/html; charset=ISO-8859-15
598 Content-Transfer-Encoding: 7bit
600 <html>
601 some text in inner email
602 ========================
603 </html>
605 --090500050101020406060002--
607 --001485f339f8f361fb049188dbba--
608 '''
610     def testMultipartKeepAlternatives(self):
611         self.doNewIssue()
612         self._handle_mail(self.multipart_msg)
613         messages = self.db.issue.get('1', 'messages')
614         messages.sort()
615         msg = self.db.msg.getnode (messages[-1])
616         assert(len(msg.files) == 5)
617         names = {0 : 'first.dvi', 4 : 'second.dvi'}
618         content = {3 : 'test attachment third text/plain\n',
619                    4 : 'Just a test\n'}
620         for n, id in enumerate (msg.files):
621             f = self.db.file.getnode (id)
622             self.assertEqual(f.name, names.get (n, 'unnamed'))
623             if n in content :
624                 self.assertEqual(f.content, content [n])
625         self.assertEqual(msg.content, 'test attachment second text/plain')
627     def testMultipartDropAlternatives(self):
628         self.doNewIssue()
629         self.db.config.MAILGW_IGNORE_ALTERNATIVES = True
630         self._handle_mail(self.multipart_msg)
631         messages = self.db.issue.get('1', 'messages')
632         messages.sort()
633         msg = self.db.msg.getnode (messages[-1])
634         assert(len(msg.files) == 2)
635         names = {1 : 'second.dvi'}
636         content = {0 : 'test attachment third text/plain\n',
637                    1 : 'Just a test\n'}
638         for n, id in enumerate (msg.files):
639             f = self.db.file.getnode (id)
640             self.assertEqual(f.name, names.get (n, 'unnamed'))
641             if n in content :
642                 self.assertEqual(f.content, content [n])
643         self.assertEqual(msg.content, 'test attachment second text/plain')
645     def testMultipartCharsetUTF8NoAttach(self):
646         c = 'umlaut \xc3\xa4\xc3\xb6\xc3\xbc\xc3\x84\xc3\x96\xc3\x9c\xc3\x9f'
647         self.doNewIssue()
648         self.db.config.NOSY_MAX_ATTACHMENT_SIZE = 0
649         self._handle_mail(self.multipart_msg_latin1)
650         messages = self.db.issue.get('1', 'messages')
651         messages.sort()
652         msg = self.db.msg.getnode (messages[-1])
653         assert(len(msg.files) == 1)
654         name = 'unnamed'
655         content = '<html>' + c + '</html>\n'
656         for n, id in enumerate (msg.files):
657             f = self.db.file.getnode (id)
658             self.assertEqual(f.name, name)
659             self.assertEqual(f.content, content)
660         self.assertEqual(msg.content, c)
661         self.compareMessages(self._get_mail(),
662 '''FROM: roundup-admin@your.tracker.email.domain.example
663 TO: chef@bork.bork.bork, richard@test.test
664 Content-Type: text/plain; charset="utf-8"
665 Subject: [issue1] Testing...
666 To: chef@bork.bork.bork, richard@test.test
667 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
668 Reply-To: Roundup issue tracker
669  <issue_tracker@your.tracker.email.domain.example>
670 MIME-Version: 1.0
671 Message-Id: <followup_dummy_id>
672 In-Reply-To: <dummy_test_message_id>
673 X-Roundup-Name: Roundup issue tracker
674 X-Roundup-Loop: hello
675 X-Roundup-Issue-Status: chatting
676 X-Roundup-Issue-Files: unnamed
677 Content-Transfer-Encoding: quoted-printable
680 Contrary, Mary <mary@test.test> added the comment:
682 umlaut =C3=A4=C3=B6=C3=BC=C3=84=C3=96=C3=9C=C3=9F
683 File 'unnamed' not attached - you can download it from http://tracker.examp=
684 le/cgi-bin/roundup.cgi/bugs/file1.
686 ----------
687 status: unread -> chatting
689 _______________________________________________________________________
690 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
691 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
692 _______________________________________________________________________
693 ''')
695     def testMultipartCharsetLatin1NoAttach(self):
696         c = 'umlaut \xc3\xa4\xc3\xb6\xc3\xbc\xc3\x84\xc3\x96\xc3\x9c\xc3\x9f'
697         self.doNewIssue()
698         self.db.config.NOSY_MAX_ATTACHMENT_SIZE = 0
699         self.db.config.MAIL_CHARSET = 'iso-8859-1'
700         self._handle_mail(self.multipart_msg_latin1)
701         messages = self.db.issue.get('1', 'messages')
702         messages.sort()
703         msg = self.db.msg.getnode (messages[-1])
704         assert(len(msg.files) == 1)
705         name = 'unnamed'
706         content = '<html>' + c + '</html>\n'
707         for n, id in enumerate (msg.files):
708             f = self.db.file.getnode (id)
709             self.assertEqual(f.name, name)
710             self.assertEqual(f.content, content)
711         self.assertEqual(msg.content, c)
712         self.compareMessages(self._get_mail(),
713 '''FROM: roundup-admin@your.tracker.email.domain.example
714 TO: chef@bork.bork.bork, richard@test.test
715 Content-Type: text/plain; charset="iso-8859-1"
716 Subject: [issue1] Testing...
717 To: chef@bork.bork.bork, richard@test.test
718 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
719 Reply-To: Roundup issue tracker
720  <issue_tracker@your.tracker.email.domain.example>
721 MIME-Version: 1.0
722 Message-Id: <followup_dummy_id>
723 In-Reply-To: <dummy_test_message_id>
724 X-Roundup-Name: Roundup issue tracker
725 X-Roundup-Loop: hello
726 X-Roundup-Issue-Status: chatting
727 X-Roundup-Issue-Files: unnamed
728 Content-Transfer-Encoding: quoted-printable
731 Contrary, Mary <mary@test.test> added the comment:
733 umlaut =E4=F6=FC=C4=D6=DC=DF
734 File 'unnamed' not attached - you can download it from http://tracker.examp=
735 le/cgi-bin/roundup.cgi/bugs/file1.
737 ----------
738 status: unread -> chatting
740 _______________________________________________________________________
741 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
742 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
743 _______________________________________________________________________
744 ''')
746     def testMultipartCharsetUTF8AttachFile(self):
747         c = 'umlaut \xc3\xa4\xc3\xb6\xc3\xbc\xc3\x84\xc3\x96\xc3\x9c\xc3\x9f'
748         self.doNewIssue()
749         self._handle_mail(self.multipart_msg_latin1)
750         messages = self.db.issue.get('1', 'messages')
751         messages.sort()
752         msg = self.db.msg.getnode (messages[-1])
753         assert(len(msg.files) == 1)
754         name = 'unnamed'
755         content = '<html>' + c + '</html>\n'
756         for n, id in enumerate (msg.files):
757             f = self.db.file.getnode (id)
758             self.assertEqual(f.name, name)
759             self.assertEqual(f.content, content)
760         self.assertEqual(msg.content, c)
761         self.compareMessages(self._get_mail(),
762 '''FROM: roundup-admin@your.tracker.email.domain.example
763 TO: chef@bork.bork.bork, richard@test.test
764 Content-Type: multipart/mixed; boundary="utf-8"
765 Subject: [issue1] Testing...
766 To: chef@bork.bork.bork, richard@test.test
767 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
768 Reply-To: Roundup issue tracker
769  <issue_tracker@your.tracker.email.domain.example>
770 MIME-Version: 1.0
771 Message-Id: <followup_dummy_id>
772 In-Reply-To: <dummy_test_message_id>
773 X-Roundup-Name: Roundup issue tracker
774 X-Roundup-Loop: hello
775 X-Roundup-Issue-Status: chatting
776 X-Roundup-Issue-Files: unnamed
777 Content-Transfer-Encoding: quoted-printable
780 --utf-8
781 MIME-Version: 1.0
782 Content-Type: text/plain; charset="utf-8"
783 Content-Transfer-Encoding: quoted-printable
786 Contrary, Mary <mary@test.test> added the comment:
788 umlaut =C3=A4=C3=B6=C3=BC=C3=84=C3=96=C3=9C=C3=9F
790 ----------
791 status: unread -> chatting
793 _______________________________________________________________________
794 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
795 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
796 _______________________________________________________________________
797 --utf-8
798 Content-Type: text/html
799 MIME-Version: 1.0
800 Content-Transfer-Encoding: base64
801 Content-Disposition: attachment;
802  filename="unnamed"
804 PGh0bWw+dW1sYXV0IMOkw7bDvMOEw5bDnMOfPC9odG1sPgo=
806 --utf-8--
807 ''')
809     def testMultipartCharsetLatin1AttachFile(self):
810         c = 'umlaut \xc3\xa4\xc3\xb6\xc3\xbc\xc3\x84\xc3\x96\xc3\x9c\xc3\x9f'
811         self.doNewIssue()
812         self.db.config.MAIL_CHARSET = 'iso-8859-1'
813         self._handle_mail(self.multipart_msg_latin1)
814         messages = self.db.issue.get('1', 'messages')
815         messages.sort()
816         msg = self.db.msg.getnode (messages[-1])
817         assert(len(msg.files) == 1)
818         name = 'unnamed'
819         content = '<html>' + c + '</html>\n'
820         for n, id in enumerate (msg.files):
821             f = self.db.file.getnode (id)
822             self.assertEqual(f.name, name)
823             self.assertEqual(f.content, content)
824         self.assertEqual(msg.content, c)
825         self.compareMessages(self._get_mail(),
826 '''FROM: roundup-admin@your.tracker.email.domain.example
827 TO: chef@bork.bork.bork, richard@test.test
828 Content-Type: multipart/mixed; boundary="utf-8"
829 Subject: [issue1] Testing...
830 To: chef@bork.bork.bork, richard@test.test
831 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
832 Reply-To: Roundup issue tracker
833  <issue_tracker@your.tracker.email.domain.example>
834 MIME-Version: 1.0
835 Message-Id: <followup_dummy_id>
836 In-Reply-To: <dummy_test_message_id>
837 X-Roundup-Name: Roundup issue tracker
838 X-Roundup-Loop: hello
839 X-Roundup-Issue-Status: chatting
840 X-Roundup-Issue-Files: unnamed
841 Content-Transfer-Encoding: quoted-printable
844 --utf-8
845 MIME-Version: 1.0
846 Content-Type: text/plain; charset="iso-8859-1"
847 Content-Transfer-Encoding: quoted-printable
850 Contrary, Mary <mary@test.test> added the comment:
852 umlaut =E4=F6=FC=C4=D6=DC=DF
854 ----------
855 status: unread -> chatting
857 _______________________________________________________________________
858 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
859 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
860 _______________________________________________________________________
861 --utf-8
862 Content-Type: text/html
863 MIME-Version: 1.0
864 Content-Transfer-Encoding: base64
865 Content-Disposition: attachment;
866  filename="unnamed"
868 PGh0bWw+dW1sYXV0IMOkw7bDvMOEw5bDnMOfPC9odG1sPgo=
870 --utf-8--
871 ''')
873     def testMultipartRFC822(self):
874         self.doNewIssue()
875         self._handle_mail(self.multipart_msg_rfc822)
876         messages = self.db.issue.get('1', 'messages')
877         messages.sort()
878         msg = self.db.msg.getnode (messages[-1])
879         assert(len(msg.files) == 1)
880         name = "Fwd: Original email subject.eml"
881         for n, id in enumerate (msg.files):
882             f = self.db.file.getnode (id)
883             self.assertEqual(f.name, name)
884         self.assertEqual(msg.content, 'First part: Text')
885         self.compareMessages(self._get_mail(),
886 '''TO: chef@bork.bork.bork, richard@test.test
887 Content-Type: text/plain; charset="utf-8"
888 Subject: [issue1] Testing...
889 To: chef@bork.bork.bork, richard@test.test
890 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
891 Reply-To: Roundup issue tracker
892  <issue_tracker@your.tracker.email.domain.example>
893 MIME-Version: 1.0
894 Message-Id: <followup_dummy_id>
895 In-Reply-To: <dummy_test_message_id>
896 X-Roundup-Name: Roundup issue tracker
897 X-Roundup-Loop: hello
898 X-Roundup-Issue-Status: chatting
899 X-Roundup-Issue-Files: Fwd: Original email subject.eml
900 Content-Transfer-Encoding: quoted-printable
903 --utf-8
904 MIME-Version: 1.0
905 Content-Type: text/plain; charset="utf-8"
906 Content-Transfer-Encoding: quoted-printable
909 Contrary, Mary <mary@test.test> added the comment:
911 First part: Text
913 ----------
914 status: unread -> chatting
916 _______________________________________________________________________
917 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
918 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
919 _______________________________________________________________________
920 --utf-8
921 Content-Type: message/rfc822
922 MIME-Version: 1.0
923 Content-Disposition: attachment;
924  filename="Fwd: Original email subject.eml"
926 Message-Id: <followup_dummy_id_2>
927 In-Reply-To: <dummy_test_message_id_2>
928 MIME-Version: 1.0
929 Subject: Fwd: Original email subject
930 Date: Mon, 23 Aug 2010 08:23:33 +0200
931 Content-Type: multipart/alternative; boundary="090500050101020406060002"
933 This is a multi-part message in MIME format.
934 --090500050101020406060002
935 Content-Type: text/plain; charset=ISO-8859-15; format=flowed
936 Content-Transfer-Encoding: 7bit
938 some text in inner email
939 ========================
941 --090500050101020406060002
942 Content-Type: text/html; charset=ISO-8859-15
943 Content-Transfer-Encoding: 7bit
945 <html>
946 some text in inner email
947 ========================
948 </html>
950 --090500050101020406060002--
952 --utf-8--
953 ''')
955     def testMultipartRFC822Unpack(self):
956         self.doNewIssue()
957         self.db.config.MAILGW_UNPACK_RFC822 = True
958         self._handle_mail(self.multipart_msg_rfc822)
959         messages = self.db.issue.get('1', 'messages')
960         messages.sort()
961         msg = self.db.msg.getnode (messages[-1])
962         self.assertEqual(len(msg.files), 2)
963         t = 'some text in inner email\n========================\n'
964         content = {0 : t, 1 : '<html>\n' + t + '</html>\n'}
965         for n, id in enumerate (msg.files):
966             f = self.db.file.getnode (id)
967             self.assertEqual(f.name, 'unnamed')
968             if n in content :
969                 self.assertEqual(f.content, content [n])
970         self.assertEqual(msg.content, 'First part: Text')
972     def testSimpleFollowup(self):
973         self.doNewIssue()
974         self._handle_mail('''Content-Type: text/plain;
975   charset="iso-8859-1"
976 From: mary <mary@test.test>
977 To: issue_tracker@your.tracker.email.domain.example
978 Message-Id: <followup_dummy_id>
979 In-Reply-To: <dummy_test_message_id>
980 Subject: [issue1] Testing...
982 This is a second followup
983 ''')
984         self.compareMessages(self._get_mail(),
985 '''FROM: roundup-admin@your.tracker.email.domain.example
986 TO: chef@bork.bork.bork, richard@test.test
987 Content-Type: text/plain; charset="utf-8"
988 Subject: [issue1] Testing...
989 To: chef@bork.bork.bork, richard@test.test
990 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
991 Reply-To: Roundup issue tracker
992  <issue_tracker@your.tracker.email.domain.example>
993 MIME-Version: 1.0
994 Message-Id: <followup_dummy_id>
995 In-Reply-To: <dummy_test_message_id>
996 X-Roundup-Name: Roundup issue tracker
997 X-Roundup-Loop: hello
998 X-Roundup-Issue-Status: chatting
999 Content-Transfer-Encoding: quoted-printable
1002 Contrary, Mary <mary@test.test> added the comment:
1004 This is a second followup
1006 ----------
1007 status: unread -> chatting
1009 _______________________________________________________________________
1010 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1011 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1012 _______________________________________________________________________
1013 ''')
1015     def testFollowup(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... [assignedto=mary; nosy=+john]
1026 This is a followup
1027 ''')
1028         l = self.db.issue.get('1', 'nosy')
1029         l.sort()
1030         self.assertEqual(l, [self.chef_id, self.richard_id, self.mary_id,
1031             self.john_id])
1033         self.compareMessages(self._get_mail(),
1034 '''FROM: roundup-admin@your.tracker.email.domain.example
1035 TO: chef@bork.bork.bork, john@test.test, mary@test.test
1036 Content-Type: text/plain; charset="utf-8"
1037 Subject: [issue1] Testing...
1038 To: chef@bork.bork.bork, john@test.test, mary@test.test
1039 From: richard <issue_tracker@your.tracker.email.domain.example>
1040 Reply-To: Roundup issue tracker
1041  <issue_tracker@your.tracker.email.domain.example>
1042 MIME-Version: 1.0
1043 Message-Id: <followup_dummy_id>
1044 In-Reply-To: <dummy_test_message_id>
1045 X-Roundup-Name: Roundup issue tracker
1046 X-Roundup-Loop: hello
1047 X-Roundup-Issue-Status: chatting
1048 Content-Transfer-Encoding: quoted-printable
1051 richard <richard@test.test> added the comment:
1053 This is a followup
1055 ----------
1056 assignedto:  -> mary
1057 nosy: +john, mary
1058 status: unread -> chatting
1060 _______________________________________________________________________
1061 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1062 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1063 _______________________________________________________________________
1064 ''')
1066     def testFollowupNoSubjectChange(self):
1067         self.db.config.MAILGW_SUBJECT_UPDATES_TITLE = 'no'
1068         self.doNewIssue()
1070         self._handle_mail('''Content-Type: text/plain;
1071   charset="iso-8859-1"
1072 From: richard <richard@test.test>
1073 To: issue_tracker@your.tracker.email.domain.example
1074 Message-Id: <followup_dummy_id>
1075 In-Reply-To: <dummy_test_message_id>
1076 Subject: [issue1] Wrzlbrmft... [assignedto=mary; nosy=+john]
1078 This is a followup
1079 ''')
1080         l = self.db.issue.get('1', 'nosy')
1081         l.sort()
1082         self.assertEqual(l, [self.chef_id, self.richard_id, self.mary_id,
1083             self.john_id])
1085         self.compareMessages(self._get_mail(),
1086 '''FROM: roundup-admin@your.tracker.email.domain.example
1087 TO: chef@bork.bork.bork, john@test.test, mary@test.test
1088 Content-Type: text/plain; charset="utf-8"
1089 Subject: [issue1] Testing...
1090 To: chef@bork.bork.bork, john@test.test, mary@test.test
1091 From: richard <issue_tracker@your.tracker.email.domain.example>
1092 Reply-To: Roundup issue tracker
1093  <issue_tracker@your.tracker.email.domain.example>
1094 MIME-Version: 1.0
1095 Message-Id: <followup_dummy_id>
1096 In-Reply-To: <dummy_test_message_id>
1097 X-Roundup-Name: Roundup issue tracker
1098 X-Roundup-Loop: hello
1099 X-Roundup-Issue-Status: chatting
1100 Content-Transfer-Encoding: quoted-printable
1103 richard <richard@test.test> added the comment:
1105 This is a followup
1107 ----------
1108 assignedto:  -> mary
1109 nosy: +john, mary
1110 status: unread -> chatting
1112 _______________________________________________________________________
1113 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1114 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1115 _______________________________________________________________________
1116 ''')
1117         self.assertEqual(self.db.issue.get('1','title'), 'Testing...')
1119     def testFollowupExplicitSubjectChange(self):
1120         self.doNewIssue()
1122         self._handle_mail('''Content-Type: text/plain;
1123   charset="iso-8859-1"
1124 From: richard <richard@test.test>
1125 To: issue_tracker@your.tracker.email.domain.example
1126 Message-Id: <followup_dummy_id>
1127 In-Reply-To: <dummy_test_message_id>
1128 Subject: [issue1] Wrzlbrmft... [assignedto=mary; nosy=+john; title=new title]
1130 This is a followup
1131 ''')
1132         l = self.db.issue.get('1', 'nosy')
1133         l.sort()
1134         self.assertEqual(l, [self.chef_id, self.richard_id, self.mary_id,
1135             self.john_id])
1137         self.compareMessages(self._get_mail(),
1138 '''FROM: roundup-admin@your.tracker.email.domain.example
1139 TO: chef@bork.bork.bork, john@test.test, mary@test.test
1140 Content-Type: text/plain; charset="utf-8"
1141 Subject: [issue1] new title
1142 To: chef@bork.bork.bork, john@test.test, mary@test.test
1143 From: richard <issue_tracker@your.tracker.email.domain.example>
1144 Reply-To: Roundup issue tracker
1145  <issue_tracker@your.tracker.email.domain.example>
1146 MIME-Version: 1.0
1147 Message-Id: <followup_dummy_id>
1148 In-Reply-To: <dummy_test_message_id>
1149 X-Roundup-Name: Roundup issue tracker
1150 X-Roundup-Loop: hello
1151 X-Roundup-Issue-Status: chatting
1152 Content-Transfer-Encoding: quoted-printable
1155 richard <richard@test.test> added the comment:
1157 This is a followup
1159 ----------
1160 assignedto:  -> mary
1161 nosy: +john, mary
1162 status: unread -> chatting
1163 title: Testing... -> new title
1165 _______________________________________________________________________
1166 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1167 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1168 _______________________________________________________________________
1169 ''')
1171     def testNosyGeneration(self):
1172         self.db.issue.create(title='test')
1174         # create a nosy message
1175         msg = self.db.msg.create(content='This is a test',
1176             author=self.richard_id, messageid='<dummy_test_message_id>')
1177         self.db.journaltag = 'richard'
1178         l = self.db.issue.create(title='test', messages=[msg],
1179             nosy=[self.chef_id, self.mary_id, self.john_id])
1181         self.compareMessages(self._get_mail(),
1182 '''FROM: roundup-admin@your.tracker.email.domain.example
1183 TO: chef@bork.bork.bork, john@test.test, mary@test.test
1184 Content-Type: text/plain; charset="utf-8"
1185 Subject: [issue2] test
1186 To: chef@bork.bork.bork, john@test.test, mary@test.test
1187 From: richard <issue_tracker@your.tracker.email.domain.example>
1188 Reply-To: Roundup issue tracker
1189  <issue_tracker@your.tracker.email.domain.example>
1190 MIME-Version: 1.0
1191 Message-Id: <dummy_test_message_id>
1192 X-Roundup-Name: Roundup issue tracker
1193 X-Roundup-Loop: hello
1194 X-Roundup-Issue-Status: unread
1195 Content-Transfer-Encoding: quoted-printable
1198 New submission from richard <richard@test.test>:
1200 This is a test
1202 ----------
1203 messages: 1
1204 nosy: Chef, john, mary, richard
1205 status: unread
1206 title: test
1208 _______________________________________________________________________
1209 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1210 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue2>
1211 _______________________________________________________________________
1212 ''')
1214     def testPropertyChangeOnly(self):
1215         self.doNewIssue()
1216         oldvalues = self.db.getnode('issue', '1').copy()
1217         oldvalues['assignedto'] = None
1218         # reconstruct old behaviour: This would reuse the
1219         # database-handle from the doNewIssue above which has committed
1220         # as user "Chef". So we close and reopen the db as that user.
1221         #self.db.close() actually don't close 'cos this empties memorydb
1222         self.db = self.instance.open('Chef')
1223         self.db.issue.set('1', assignedto=self.chef_id)
1224         self.db.commit()
1225         self.db.issue.nosymessage('1', None, oldvalues)
1227         new_mail = ""
1228         for line in self._get_mail().split("\n"):
1229             if "Message-Id: " in line:
1230                 continue
1231             if "Date: " in line:
1232                 continue
1233             new_mail += line+"\n"
1235         self.compareMessages(new_mail, """
1236 FROM: roundup-admin@your.tracker.email.domain.example
1237 TO: chef@bork.bork.bork, richard@test.test
1238 Content-Type: text/plain; charset="utf-8"
1239 Subject: [issue1] Testing...
1240 To: chef@bork.bork.bork, richard@test.test
1241 From: "Bork, Chef" <issue_tracker@your.tracker.email.domain.example>
1242 X-Roundup-Name: Roundup issue tracker
1243 X-Roundup-Loop: hello
1244 X-Roundup-Issue-Status: unread
1245 X-Roundup-Version: 1.3.3
1246 In-Reply-To: <dummy_test_message_id>
1247 MIME-Version: 1.0
1248 Reply-To: Roundup issue tracker
1249  <issue_tracker@your.tracker.email.domain.example>
1250 Content-Transfer-Encoding: quoted-printable
1253 Change by Bork, Chef <chef@bork.bork.bork>:
1256 ----------
1257 assignedto:  -> Chef
1259 _______________________________________________________________________
1260 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1261 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1262 _______________________________________________________________________
1263 """)
1266     #
1267     # FOLLOWUP TITLE MATCH
1268     #
1269     def testFollowupTitleMatch(self):
1270         self.doNewIssue()
1271         self._handle_mail('''Content-Type: text/plain;
1272   charset="iso-8859-1"
1273 From: richard <richard@test.test>
1274 To: issue_tracker@your.tracker.email.domain.example
1275 Message-Id: <followup_dummy_id>
1276 Subject: Re: Testing... [assignedto=mary; nosy=+john]
1278 This is a followup
1279 ''')
1280         self.compareMessages(self._get_mail(),
1281 '''FROM: roundup-admin@your.tracker.email.domain.example
1282 TO: chef@bork.bork.bork, john@test.test, mary@test.test
1283 Content-Type: text/plain; charset="utf-8"
1284 Subject: [issue1] Testing...
1285 To: chef@bork.bork.bork, john@test.test, mary@test.test
1286 From: richard <issue_tracker@your.tracker.email.domain.example>
1287 Reply-To: Roundup issue tracker
1288  <issue_tracker@your.tracker.email.domain.example>
1289 MIME-Version: 1.0
1290 Message-Id: <followup_dummy_id>
1291 In-Reply-To: <dummy_test_message_id>
1292 X-Roundup-Name: Roundup issue tracker
1293 X-Roundup-Loop: hello
1294 X-Roundup-Issue-Status: chatting
1295 Content-Transfer-Encoding: quoted-printable
1298 richard <richard@test.test> added the comment:
1300 This is a followup
1302 ----------
1303 assignedto:  -> mary
1304 nosy: +john, mary
1305 status: unread -> chatting
1307 _______________________________________________________________________
1308 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1309 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1310 _______________________________________________________________________
1311 ''')
1313     def testFollowupTitleMatchMultiRe(self):
1314         nodeid1 = self.doNewIssue()
1315         nodeid2 = self._handle_mail('''Content-Type: text/plain;
1316   charset="iso-8859-1"
1317 From: richard <richard@test.test>
1318 To: issue_tracker@your.tracker.email.domain.example
1319 Message-Id: <followup_dummy_id>
1320 Subject: Re: Testing... [assignedto=mary; nosy=+john]
1322 This is a followup
1323 ''')
1325         nodeid3 = self._handle_mail('''Content-Type: text/plain;
1326   charset="iso-8859-1"
1327 From: richard <richard@test.test>
1328 To: issue_tracker@your.tracker.email.domain.example
1329 Message-Id: <followup2_dummy_id>
1330 Subject: Ang: Re: Testing...
1332 This is a followup
1333 ''')
1334         self.assertEqual(nodeid1, nodeid2)
1335         self.assertEqual(nodeid1, nodeid3)
1337     def testFollowupTitleMatchNever(self):
1338         nodeid = self.doNewIssue()
1339         self.db.config.MAILGW_SUBJECT_CONTENT_MATCH = 'never'
1340         self.assertNotEqual(self._handle_mail('''Content-Type: text/plain;
1341   charset="iso-8859-1"
1342 From: richard <richard@test.test>
1343 To: issue_tracker@your.tracker.email.domain.example
1344 Message-Id: <followup_dummy_id>
1345 Subject: Re: Testing...
1347 This is a followup
1348 '''), nodeid)
1350     def testFollowupTitleMatchNeverInterval(self):
1351         nodeid = self.doNewIssue()
1352         # force failure of the interval
1353         time.sleep(2)
1354         self.db.config.MAILGW_SUBJECT_CONTENT_MATCH = 'creation 00:00:01'
1355         self.assertNotEqual(self._handle_mail('''Content-Type: text/plain;
1356   charset="iso-8859-1"
1357 From: richard <richard@test.test>
1358 To: issue_tracker@your.tracker.email.domain.example
1359 Message-Id: <followup_dummy_id>
1360 Subject: Re: Testing...
1362 This is a followup
1363 '''), nodeid)
1366     def testFollowupTitleMatchInterval(self):
1367         nodeid = self.doNewIssue()
1368         self.db.config.MAILGW_SUBJECT_CONTENT_MATCH = 'creation +1d'
1369         self.assertEqual(self._handle_mail('''Content-Type: text/plain;
1370   charset="iso-8859-1"
1371 From: richard <richard@test.test>
1372 To: issue_tracker@your.tracker.email.domain.example
1373 Message-Id: <followup_dummy_id>
1374 Subject: Re: Testing...
1376 This is a followup
1377 '''), nodeid)
1380     def testFollowupNosyAuthor(self):
1381         self.doNewIssue()
1382         self.db.config.ADD_AUTHOR_TO_NOSY = 'yes'
1383         self._handle_mail('''Content-Type: text/plain;
1384   charset="iso-8859-1"
1385 From: john@test.test
1386 To: issue_tracker@your.tracker.email.domain.example
1387 Message-Id: <followup_dummy_id>
1388 In-Reply-To: <dummy_test_message_id>
1389 Subject: [issue1] Testing...
1391 This is a followup
1392 ''')
1394         self.compareMessages(self._get_mail(),
1395 '''FROM: roundup-admin@your.tracker.email.domain.example
1396 TO: chef@bork.bork.bork, richard@test.test
1397 Content-Type: text/plain; charset="utf-8"
1398 Subject: [issue1] Testing...
1399 To: chef@bork.bork.bork, richard@test.test
1400 From: John Doe <issue_tracker@your.tracker.email.domain.example>
1401 Reply-To: Roundup issue tracker
1402  <issue_tracker@your.tracker.email.domain.example>
1403 MIME-Version: 1.0
1404 Message-Id: <followup_dummy_id>
1405 In-Reply-To: <dummy_test_message_id>
1406 X-Roundup-Name: Roundup issue tracker
1407 X-Roundup-Loop: hello
1408 X-Roundup-Issue-Status: chatting
1409 Content-Transfer-Encoding: quoted-printable
1412 John Doe <john@test.test> added the comment:
1414 This is a followup
1416 ----------
1417 nosy: +john
1418 status: unread -> chatting
1420 _______________________________________________________________________
1421 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1422 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1423 _______________________________________________________________________
1425 ''')
1427     def testFollowupNosyRecipients(self):
1428         self.doNewIssue()
1429         self.db.config.ADD_RECIPIENTS_TO_NOSY = 'yes'
1430         self._handle_mail('''Content-Type: text/plain;
1431   charset="iso-8859-1"
1432 From: richard@test.test
1433 To: issue_tracker@your.tracker.email.domain.example
1434 Cc: john@test.test
1435 Message-Id: <followup_dummy_id>
1436 In-Reply-To: <dummy_test_message_id>
1437 Subject: [issue1] Testing...
1439 This is a followup
1440 ''')
1441         self.compareMessages(self._get_mail(),
1442 '''FROM: roundup-admin@your.tracker.email.domain.example
1443 TO: chef@bork.bork.bork
1444 Content-Type: text/plain; charset="utf-8"
1445 Subject: [issue1] Testing...
1446 To: chef@bork.bork.bork
1447 From: richard <issue_tracker@your.tracker.email.domain.example>
1448 Reply-To: Roundup issue tracker
1449  <issue_tracker@your.tracker.email.domain.example>
1450 MIME-Version: 1.0
1451 Message-Id: <followup_dummy_id>
1452 In-Reply-To: <dummy_test_message_id>
1453 X-Roundup-Name: Roundup issue tracker
1454 X-Roundup-Loop: hello
1455 X-Roundup-Issue-Status: chatting
1456 Content-Transfer-Encoding: quoted-printable
1459 richard <richard@test.test> added the comment:
1461 This is a followup
1463 ----------
1464 nosy: +john
1465 status: unread -> chatting
1467 _______________________________________________________________________
1468 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1469 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1470 _______________________________________________________________________
1472 ''')
1474     def testFollowupNosyAuthorAndCopy(self):
1475         self.doNewIssue()
1476         self.db.config.ADD_AUTHOR_TO_NOSY = 'yes'
1477         self.db.config.MESSAGES_TO_AUTHOR = 'yes'
1478         self._handle_mail('''Content-Type: text/plain;
1479   charset="iso-8859-1"
1480 From: john@test.test
1481 To: issue_tracker@your.tracker.email.domain.example
1482 Message-Id: <followup_dummy_id>
1483 In-Reply-To: <dummy_test_message_id>
1484 Subject: [issue1] Testing...
1486 This is a followup
1487 ''')
1488         self.compareMessages(self._get_mail(),
1489 '''FROM: roundup-admin@your.tracker.email.domain.example
1490 TO: chef@bork.bork.bork, john@test.test, richard@test.test
1491 Content-Type: text/plain; charset="utf-8"
1492 Subject: [issue1] Testing...
1493 To: chef@bork.bork.bork, john@test.test, richard@test.test
1494 From: John Doe <issue_tracker@your.tracker.email.domain.example>
1495 Reply-To: Roundup issue tracker
1496  <issue_tracker@your.tracker.email.domain.example>
1497 MIME-Version: 1.0
1498 Message-Id: <followup_dummy_id>
1499 In-Reply-To: <dummy_test_message_id>
1500 X-Roundup-Name: Roundup issue tracker
1501 X-Roundup-Loop: hello
1502 X-Roundup-Issue-Status: chatting
1503 Content-Transfer-Encoding: quoted-printable
1506 John Doe <john@test.test> added the comment:
1508 This is a followup
1510 ----------
1511 nosy: +john
1512 status: unread -> chatting
1514 _______________________________________________________________________
1515 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1516 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1517 _______________________________________________________________________
1519 ''')
1521     def testFollowupNoNosyAuthor(self):
1522         self.doNewIssue()
1523         self.instance.config.ADD_AUTHOR_TO_NOSY = 'no'
1524         self._handle_mail('''Content-Type: text/plain;
1525   charset="iso-8859-1"
1526 From: john@test.test
1527 To: issue_tracker@your.tracker.email.domain.example
1528 Message-Id: <followup_dummy_id>
1529 In-Reply-To: <dummy_test_message_id>
1530 Subject: [issue1] Testing...
1532 This is a followup
1533 ''')
1534         self.compareMessages(self._get_mail(),
1535 '''FROM: roundup-admin@your.tracker.email.domain.example
1536 TO: chef@bork.bork.bork, richard@test.test
1537 Content-Type: text/plain; charset="utf-8"
1538 Subject: [issue1] Testing...
1539 To: chef@bork.bork.bork, richard@test.test
1540 From: John Doe <issue_tracker@your.tracker.email.domain.example>
1541 Reply-To: Roundup issue tracker
1542  <issue_tracker@your.tracker.email.domain.example>
1543 MIME-Version: 1.0
1544 Message-Id: <followup_dummy_id>
1545 In-Reply-To: <dummy_test_message_id>
1546 X-Roundup-Name: Roundup issue tracker
1547 X-Roundup-Loop: hello
1548 X-Roundup-Issue-Status: chatting
1549 Content-Transfer-Encoding: quoted-printable
1552 John Doe <john@test.test> added the comment:
1554 This is a followup
1556 ----------
1557 status: unread -> chatting
1559 _______________________________________________________________________
1560 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1561 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1562 _______________________________________________________________________
1564 ''')
1566     def testFollowupNoNosyRecipients(self):
1567         self.doNewIssue()
1568         self.instance.config.ADD_RECIPIENTS_TO_NOSY = 'no'
1569         self._handle_mail('''Content-Type: text/plain;
1570   charset="iso-8859-1"
1571 From: richard@test.test
1572 To: issue_tracker@your.tracker.email.domain.example
1573 Cc: john@test.test
1574 Message-Id: <followup_dummy_id>
1575 In-Reply-To: <dummy_test_message_id>
1576 Subject: [issue1] Testing...
1578 This is a followup
1579 ''')
1580         self.compareMessages(self._get_mail(),
1581 '''FROM: roundup-admin@your.tracker.email.domain.example
1582 TO: chef@bork.bork.bork
1583 Content-Type: text/plain; charset="utf-8"
1584 Subject: [issue1] Testing...
1585 To: chef@bork.bork.bork
1586 From: richard <issue_tracker@your.tracker.email.domain.example>
1587 Reply-To: Roundup issue tracker
1588  <issue_tracker@your.tracker.email.domain.example>
1589 MIME-Version: 1.0
1590 Message-Id: <followup_dummy_id>
1591 In-Reply-To: <dummy_test_message_id>
1592 X-Roundup-Name: Roundup issue tracker
1593 X-Roundup-Loop: hello
1594 X-Roundup-Issue-Status: chatting
1595 Content-Transfer-Encoding: quoted-printable
1598 richard <richard@test.test> added the comment:
1600 This is a followup
1602 ----------
1603 status: unread -> chatting
1605 _______________________________________________________________________
1606 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1607 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1608 _______________________________________________________________________
1610 ''')
1612     def testFollowupEmptyMessage(self):
1613         self.doNewIssue()
1615         self._handle_mail('''Content-Type: text/plain;
1616   charset="iso-8859-1"
1617 From: richard <richard@test.test>
1618 To: issue_tracker@your.tracker.email.domain.example
1619 Message-Id: <followup_dummy_id>
1620 In-Reply-To: <dummy_test_message_id>
1621 Subject: [issue1] Testing... [assignedto=mary; nosy=+john]
1623 ''')
1624         l = self.db.issue.get('1', 'nosy')
1625         l.sort()
1626         self.assertEqual(l, [self.chef_id, self.richard_id, self.mary_id,
1627             self.john_id])
1629         # should be no file created (ie. no message)
1630         assert not os.path.exists(SENDMAILDEBUG)
1632     def testFollowupEmptyMessageNoSubject(self):
1633         self.doNewIssue()
1635         self._handle_mail('''Content-Type: text/plain;
1636   charset="iso-8859-1"
1637 From: richard <richard@test.test>
1638 To: issue_tracker@your.tracker.email.domain.example
1639 Message-Id: <followup_dummy_id>
1640 In-Reply-To: <dummy_test_message_id>
1641 Subject: [issue1] [assignedto=mary; nosy=+john]
1643 ''')
1644         l = self.db.issue.get('1', 'nosy')
1645         l.sort()
1646         self.assertEqual(l, [self.chef_id, self.richard_id, self.mary_id,
1647             self.john_id])
1649         # should be no file created (ie. no message)
1650         assert not os.path.exists(SENDMAILDEBUG)
1652     def testNosyRemove(self):
1653         self.doNewIssue()
1655         self._handle_mail('''Content-Type: text/plain;
1656   charset="iso-8859-1"
1657 From: richard <richard@test.test>
1658 To: issue_tracker@your.tracker.email.domain.example
1659 Message-Id: <followup_dummy_id>
1660 In-Reply-To: <dummy_test_message_id>
1661 Subject: [issue1] Testing... [nosy=-richard]
1663 ''')
1664         l = self.db.issue.get('1', 'nosy')
1665         l.sort()
1666         self.assertEqual(l, [self.chef_id])
1668         # NO NOSY MESSAGE SHOULD BE SENT!
1669         assert not os.path.exists(SENDMAILDEBUG)
1671     def testNewUserAuthor(self):
1672         self.db.commit()
1673         l = self.db.user.list()
1674         l.sort()
1675         message = '''Content-Type: text/plain;
1676   charset="iso-8859-1"
1677 From: fubar <fubar@bork.bork.bork>
1678 To: issue_tracker@your.tracker.email.domain.example
1679 Message-Id: <dummy_test_message_id>
1680 Subject: [issue] Testing...
1682 This is a test submission of a new issue.
1683 '''
1684         self.db.security.role['anonymous'].permissions=[]
1685         anonid = self.db.user.lookup('anonymous')
1686         self.db.user.set(anonid, roles='Anonymous')
1687         try:
1688             self._handle_mail(message)
1689         except Unauthorized, value:
1690             body_diff = self.compareMessages(str(value), """
1691 You are not a registered user.
1693 Unknown address: fubar@bork.bork.bork
1694 """)
1695             assert not body_diff, body_diff
1696         else:
1697             raise AssertionError, "Unathorized not raised when handling mail"
1699         # Add Web Access role to anonymous, and try again to make sure
1700         # we get a "please register at:" message this time.
1701         p = [
1702             self.db.security.getPermission('Register', 'user'),
1703             self.db.security.getPermission('Web Access', None),
1704         ]
1705         self.db.security.role['anonymous'].permissions=p
1706         try:
1707             self._handle_mail(message)
1708         except Unauthorized, value:
1709             body_diff = self.compareMessages(str(value), """
1710 You are not a registered user. Please register at:
1712 http://tracker.example/cgi-bin/roundup.cgi/bugs/user?template=register
1714 ...before sending mail to the tracker.
1716 Unknown address: fubar@bork.bork.bork
1717 """)
1718             assert not body_diff, body_diff
1719         else:
1720             raise AssertionError, "Unathorized not raised when handling mail"
1722         # Make sure list of users is the same as before.
1723         m = self.db.user.list()
1724         m.sort()
1725         self.assertEqual(l, m)
1727         # now with the permission
1728         p = [
1729             self.db.security.getPermission('Register', 'user'),
1730             self.db.security.getPermission('Email Access', None),
1731         ]
1732         self.db.security.role['anonymous'].permissions=p
1733         self._handle_mail(message)
1734         m = self.db.user.list()
1735         m.sort()
1736         self.assertNotEqual(l, m)
1738     def testNewUserAuthorEncodedName(self):
1739         l = set(self.db.user.list())
1740         # From: name has Euro symbol in it
1741         message = '''Content-Type: text/plain;
1742   charset="iso-8859-1"
1743 From: =?utf8?b?SOKCrGxsbw==?= <fubar@bork.bork.bork>
1744 To: issue_tracker@your.tracker.email.domain.example
1745 Message-Id: <dummy_test_message_id>
1746 Subject: [issue] Testing...
1748 This is a test submission of a new issue.
1749 '''
1750         p = [
1751             self.db.security.getPermission('Register', 'user'),
1752             self.db.security.getPermission('Email Access', None),
1753             self.db.security.getPermission('Create', 'issue'),
1754             self.db.security.getPermission('Create', 'msg'),
1755         ]
1756         self.db.security.role['anonymous'].permissions = p
1757         self._handle_mail(message)
1758         m = set(self.db.user.list())
1759         new = list(m - l)[0]
1760         name = self.db.user.get(new, 'realname')
1761         self.assertEquals(name, 'H€llo')
1763     def testUnknownUser(self):
1764         l = set(self.db.user.list())
1765         message = '''Content-Type: text/plain;
1766   charset="iso-8859-1"
1767 From: Nonexisting User <nonexisting@bork.bork.bork>
1768 To: issue_tracker@your.tracker.email.domain.example
1769 Message-Id: <dummy_test_message_id>
1770 Subject: [issue] Testing nonexisting user...
1772 This is a test submission of a new issue.
1773 '''
1774         handler = self._create_mailgw(message)
1775         # we want a bounce message:
1776         handler.trapExceptions = 1
1777         ret = handler.main(StringIO(message))
1778         self.compareMessages(self._get_mail(),
1779 '''FROM: Roundup issue tracker <roundup-admin@your.tracker.email.domain.example>
1780 TO: nonexisting@bork.bork.bork
1781 From nobody Tue Jul 14 12:04:11 2009
1782 Content-Type: multipart/mixed; boundary="===============0639262320=="
1783 MIME-Version: 1.0
1784 Subject: Failed issue tracker submission
1785 To: nonexisting@bork.bork.bork
1786 From: Roundup issue tracker <roundup-admin@your.tracker.email.domain.example>
1787 Date: Tue, 14 Jul 2009 12:04:11 +0000
1788 Precedence: bulk
1789 X-Roundup-Name: Roundup issue tracker
1790 X-Roundup-Loop: hello
1791 X-Roundup-Version: 1.4.8
1792 MIME-Version: 1.0
1794 --===============0639262320==
1795 Content-Type: text/plain; charset="us-ascii"
1796 MIME-Version: 1.0
1797 Content-Transfer-Encoding: 7bit
1801 You are not a registered user. Please register at:
1803 http://tracker.example/cgi-bin/roundup.cgi/bugs/user?template=register
1805 ...before sending mail to the tracker.
1807 Unknown address: nonexisting@bork.bork.bork
1809 --===============0639262320==
1810 Content-Type: text/plain; charset="us-ascii"
1811 MIME-Version: 1.0
1812 Content-Transfer-Encoding: 7bit
1814 Content-Type: text/plain;
1815   charset="iso-8859-1"
1816 From: Nonexisting User <nonexisting@bork.bork.bork>
1817 To: issue_tracker@your.tracker.email.domain.example
1818 Message-Id: <dummy_test_message_id>
1819 Subject: [issue] Testing nonexisting user...
1821 This is a test submission of a new issue.
1823 --===============0639262320==--
1824 ''')
1826     def testEnc01(self):
1827         self.db.user.set(self.mary_id,
1828             realname='\xe4\xf6\xfc\xc4\xd6\xdc\xdf, Mary'.decode
1829             ('latin-1').encode('utf-8'))
1830         self.doNewIssue()
1831         self._handle_mail('''Content-Type: text/plain;
1832   charset="iso-8859-1"
1833 From: mary <mary@test.test>
1834 To: issue_tracker@your.tracker.email.domain.example
1835 Message-Id: <followup_dummy_id>
1836 In-Reply-To: <dummy_test_message_id>
1837 Subject: [issue1] Testing...
1838 Content-Type: text/plain;
1839         charset="iso-8859-1"
1840 Content-Transfer-Encoding: quoted-printable
1842 A message with encoding (encoded oe =F6)
1844 ''')
1845         self.compareMessages(self._get_mail(),
1846 '''FROM: roundup-admin@your.tracker.email.domain.example
1847 TO: chef@bork.bork.bork, richard@test.test
1848 Content-Type: text/plain; charset="utf-8"
1849 Subject: [issue1] Testing...
1850 To: chef@bork.bork.bork, richard@test.test
1851 From: =?utf-8?b?w6TDtsO8w4TDlsOcw58sIE1hcnk=?=
1852  <issue_tracker@your.tracker.email.domain.example>
1853 Reply-To: Roundup issue tracker
1854  <issue_tracker@your.tracker.email.domain.example>
1855 MIME-Version: 1.0
1856 Message-Id: <followup_dummy_id>
1857 In-Reply-To: <dummy_test_message_id>
1858 X-Roundup-Name: Roundup issue tracker
1859 X-Roundup-Loop: hello
1860 X-Roundup-Issue-Status: chatting
1861 Content-Transfer-Encoding: quoted-printable
1864 =C3=A4=C3=B6=C3=BC=C3=84=C3=96=C3=9C=C3=9F, Mary <mary@test.test> added the=
1865  comment:
1867 A message with encoding (encoded oe =C3=B6)
1869 ----------
1870 status: unread -> chatting
1872 _______________________________________________________________________
1873 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1874 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1875 _______________________________________________________________________
1876 ''')
1878     def testEncNonUTF8(self):
1879         self.doNewIssue()
1880         self.instance.config.EMAIL_CHARSET = 'iso-8859-1'
1881         self._handle_mail('''Content-Type: text/plain;
1882   charset="iso-8859-1"
1883 From: mary <mary@test.test>
1884 To: issue_tracker@your.tracker.email.domain.example
1885 Message-Id: <followup_dummy_id>
1886 In-Reply-To: <dummy_test_message_id>
1887 Subject: [issue1] Testing...
1888 Content-Type: text/plain;
1889         charset="iso-8859-1"
1890 Content-Transfer-Encoding: quoted-printable
1892 A message with encoding (encoded oe =F6)
1894 ''')
1895         self.compareMessages(self._get_mail(),
1896 '''FROM: roundup-admin@your.tracker.email.domain.example
1897 TO: chef@bork.bork.bork, richard@test.test
1898 Content-Type: text/plain; charset="iso-8859-1"
1899 Subject: [issue1] Testing...
1900 To: chef@bork.bork.bork, richard@test.test
1901 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
1902 Reply-To: Roundup issue tracker
1903  <issue_tracker@your.tracker.email.domain.example>
1904 MIME-Version: 1.0
1905 Message-Id: <followup_dummy_id>
1906 In-Reply-To: <dummy_test_message_id>
1907 X-Roundup-Name: Roundup issue tracker
1908 X-Roundup-Loop: hello
1909 X-Roundup-Issue-Status: chatting
1910 Content-Transfer-Encoding: quoted-printable
1913 Contrary, Mary <mary@test.test> added the comment:
1915 A message with encoding (encoded oe =F6)
1917 ----------
1918 status: unread -> chatting
1920 _______________________________________________________________________
1921 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1922 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1923 _______________________________________________________________________
1924 ''')
1927     def testMultipartEnc01(self):
1928         self.doNewIssue()
1929         self._handle_mail('''Content-Type: text/plain;
1930   charset="iso-8859-1"
1931 From: mary <mary@test.test>
1932 To: issue_tracker@your.tracker.email.domain.example
1933 Message-Id: <followup_dummy_id>
1934 In-Reply-To: <dummy_test_message_id>
1935 Subject: [issue1] Testing...
1936 Content-Type: multipart/mixed;
1937         boundary="----_=_NextPart_000_01"
1939 This message is in MIME format. Since your mail reader does not understand
1940 this format, some or all of this message may not be legible.
1942 ------_=_NextPart_000_01
1943 Content-Type: text/plain;
1944         charset="iso-8859-1"
1945 Content-Transfer-Encoding: quoted-printable
1947 A message with first part encoded (encoded oe =F6)
1949 ''')
1950         self.compareMessages(self._get_mail(),
1951 '''FROM: roundup-admin@your.tracker.email.domain.example
1952 TO: chef@bork.bork.bork, richard@test.test
1953 Content-Type: text/plain; charset="utf-8"
1954 Subject: [issue1] Testing...
1955 To: chef@bork.bork.bork, richard@test.test
1956 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
1957 Reply-To: Roundup issue tracker
1958  <issue_tracker@your.tracker.email.domain.example>
1959 MIME-Version: 1.0
1960 Message-Id: <followup_dummy_id>
1961 In-Reply-To: <dummy_test_message_id>
1962 X-Roundup-Name: Roundup issue tracker
1963 X-Roundup-Loop: hello
1964 X-Roundup-Issue-Status: chatting
1965 Content-Transfer-Encoding: quoted-printable
1968 Contrary, Mary <mary@test.test> added the comment:
1970 A message with first part encoded (encoded oe =C3=B6)
1972 ----------
1973 status: unread -> chatting
1975 _______________________________________________________________________
1976 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1977 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1978 _______________________________________________________________________
1979 ''')
1981     def testContentDisposition(self):
1982         self.doNewIssue()
1983         self._handle_mail('''Content-Type: text/plain;
1984   charset="iso-8859-1"
1985 From: mary <mary@test.test>
1986 To: issue_tracker@your.tracker.email.domain.example
1987 Message-Id: <followup_dummy_id>
1988 In-Reply-To: <dummy_test_message_id>
1989 Subject: [issue1] Testing...
1990 Content-Type: multipart/mixed; boundary="bCsyhTFzCvuiizWE"
1991 Content-Disposition: inline
1994 --bCsyhTFzCvuiizWE
1995 Content-Type: text/plain; charset=us-ascii
1996 Content-Disposition: inline
1998 test attachment binary
2000 --bCsyhTFzCvuiizWE
2001 Content-Type: application/octet-stream
2002 Content-Disposition: attachment; filename="main.dvi"
2003 Content-Transfer-Encoding: base64
2005 SnVzdCBhIHRlc3QgAQo=
2007 --bCsyhTFzCvuiizWE--
2008 ''')
2009         messages = self.db.issue.get('1', 'messages')
2010         messages.sort()
2011         file = self.db.file.getnode (self.db.msg.get(messages[-1], 'files')[0])
2012         self.assertEqual(file.name, 'main.dvi')
2013         self.assertEqual(file.content, 'Just a test \001\n')
2015     def testFollowupStupidQuoting(self):
2016         self.doNewIssue()
2018         self._handle_mail('''Content-Type: text/plain;
2019   charset="iso-8859-1"
2020 From: richard <richard@test.test>
2021 To: issue_tracker@your.tracker.email.domain.example
2022 Message-Id: <followup_dummy_id>
2023 In-Reply-To: <dummy_test_message_id>
2024 Subject: Re: "[issue1] Testing... "
2026 This is a followup
2027 ''')
2028         self.compareMessages(self._get_mail(),
2029 '''FROM: roundup-admin@your.tracker.email.domain.example
2030 TO: chef@bork.bork.bork
2031 Content-Type: text/plain; charset="utf-8"
2032 Subject: [issue1] Testing...
2033 To: chef@bork.bork.bork
2034 From: richard <issue_tracker@your.tracker.email.domain.example>
2035 Reply-To: Roundup issue tracker
2036  <issue_tracker@your.tracker.email.domain.example>
2037 MIME-Version: 1.0
2038 Message-Id: <followup_dummy_id>
2039 In-Reply-To: <dummy_test_message_id>
2040 X-Roundup-Name: Roundup issue tracker
2041 X-Roundup-Loop: hello
2042 X-Roundup-Issue-Status: chatting
2043 Content-Transfer-Encoding: quoted-printable
2046 richard <richard@test.test> added the comment:
2048 This is a followup
2050 ----------
2051 status: unread -> chatting
2053 _______________________________________________________________________
2054 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
2055 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
2056 _______________________________________________________________________
2057 ''')
2059     def testEmailQuoting(self):
2060         self.instance.config.EMAIL_KEEP_QUOTED_TEXT = 'no'
2061         self.innerTestQuoting('''This is a followup
2062 ''')
2064     def testEmailQuotingRemove(self):
2065         self.instance.config.EMAIL_KEEP_QUOTED_TEXT = 'yes'
2066         self.innerTestQuoting('''Blah blah wrote:
2067 > Blah bklaskdfj sdf asdf jlaskdf skj sdkfjl asdf
2068 >  skdjlkjsdfalsdkfjasdlfkj dlfksdfalksd fj
2071 This is a followup
2072 ''')
2074     def innerTestQuoting(self, expect):
2075         nodeid = self.doNewIssue()
2077         messages = self.db.issue.get(nodeid, 'messages')
2079         self._handle_mail('''Content-Type: text/plain;
2080   charset="iso-8859-1"
2081 From: richard <richard@test.test>
2082 To: issue_tracker@your.tracker.email.domain.example
2083 Message-Id: <followup_dummy_id>
2084 In-Reply-To: <dummy_test_message_id>
2085 Subject: Re: [issue1] Testing...
2087 Blah blah wrote:
2088 > Blah bklaskdfj sdf asdf jlaskdf skj sdkfjl asdf
2089 >  skdjlkjsdfalsdkfjasdlfkj dlfksdfalksd fj
2092 This is a followup
2093 ''')
2094         # figure the new message id
2095         newmessages = self.db.issue.get(nodeid, 'messages')
2096         for msg in messages:
2097             newmessages.remove(msg)
2098         messageid = newmessages[0]
2100         self.compareMessages(self.db.msg.get(messageid, 'content'), expect)
2102     def testUserLookup(self):
2103         i = self.db.user.create(username='user1', address='user1@foo.com')
2104         self.assertEqual(uidFromAddress(self.db, ('', 'user1@foo.com'), 0), i)
2105         self.assertEqual(uidFromAddress(self.db, ('', 'USER1@foo.com'), 0), i)
2106         i = self.db.user.create(username='user2', address='USER2@foo.com')
2107         self.assertEqual(uidFromAddress(self.db, ('', 'USER2@foo.com'), 0), i)
2108         self.assertEqual(uidFromAddress(self.db, ('', 'user2@foo.com'), 0), i)
2110     def testUserAlternateLookup(self):
2111         i = self.db.user.create(username='user1', address='user1@foo.com',
2112                                 alternate_addresses='user1@bar.com')
2113         self.assertEqual(uidFromAddress(self.db, ('', 'user1@bar.com'), 0), i)
2114         self.assertEqual(uidFromAddress(self.db, ('', 'USER1@bar.com'), 0), i)
2116     def testUserCreate(self):
2117         i = uidFromAddress(self.db, ('', 'user@foo.com'), 1)
2118         self.assertNotEqual(uidFromAddress(self.db, ('', 'user@bar.com'), 1), i)
2120     def testRFC2822(self):
2121         ascii_header = "[issue243] This is a \"test\" - with 'quotation' marks"
2122         unicode_header = '[issue244] \xd0\xb0\xd0\xbd\xd0\xb4\xd1\x80\xd0\xb5\xd0\xb9'
2123         unicode_encoded = '=?utf-8?q?[issue244]_=D0=B0=D0=BD=D0=B4=D1=80=D0=B5=D0=B9?='
2124         self.assertEqual(rfc2822.encode_header(ascii_header), ascii_header)
2125         self.assertEqual(rfc2822.encode_header(unicode_header), unicode_encoded)
2127     def testRegistrationConfirmation(self):
2128         otk = "Aj4euk4LZSAdwePohj90SME5SpopLETL"
2129         self.db.getOTKManager().set(otk, username='johannes')
2130         self._handle_mail('''Content-Type: text/plain;
2131   charset="iso-8859-1"
2132 From: Chef <chef@bork.bork.bork>
2133 To: issue_tracker@your.tracker.email.domain.example
2134 Cc: richard@test.test
2135 Message-Id: <dummy_test_message_id>
2136 Subject: Re: Complete your registration to Roundup issue tracker
2137  -- key %s
2139 This is a test confirmation of registration.
2140 ''' % otk)
2141         self.db.user.lookup('johannes')
2143     def testFollowupOnNonIssue(self):
2144         self.db.keyword.create(name='Foo')
2145         self._handle_mail('''Content-Type: text/plain;
2146   charset="iso-8859-1"
2147 From: richard <richard@test.test>
2148 To: issue_tracker@your.tracker.email.domain.example
2149 Message-Id: <followup_dummy_id>
2150 In-Reply-To: <dummy_test_message_id>
2151 Subject: [keyword1] Testing... [name=Bar]
2153 ''')
2154         self.assertEqual(self.db.keyword.get('1', 'name'), 'Bar')
2156     def testResentFrom(self):
2157         nodeid = self._handle_mail('''Content-Type: text/plain;
2158   charset="iso-8859-1"
2159 From: Chef <chef@bork.bork.bork>
2160 Resent-From: mary <mary@test.test>
2161 To: issue_tracker@your.tracker.email.domain.example
2162 Cc: richard@test.test
2163 Message-Id: <dummy_test_message_id>
2164 Subject: [issue] Testing...
2166 This is a test submission of a new issue.
2167 ''')
2168         assert not os.path.exists(SENDMAILDEBUG)
2169         l = self.db.issue.get(nodeid, 'nosy')
2170         l.sort()
2171         self.assertEqual(l, [self.richard_id, self.mary_id])
2172         return nodeid
2174     def testDejaVu(self):
2175         self.assertRaises(IgnoreLoop, self._handle_mail,
2176             '''Content-Type: text/plain;
2177   charset="iso-8859-1"
2178 From: Chef <chef@bork.bork.bork>
2179 X-Roundup-Loop: hello
2180 To: issue_tracker@your.tracker.email.domain.example
2181 Cc: richard@test.test
2182 Message-Id: <dummy_test_message_id>
2183 Subject: Re: [issue] Testing...
2185 Hi, I've been mis-configured to loop messages back to myself.
2186 ''')
2188     def testItsBulkStupid(self):
2189         self.assertRaises(IgnoreBulk, self._handle_mail,
2190             '''Content-Type: text/plain;
2191   charset="iso-8859-1"
2192 From: Chef <chef@bork.bork.bork>
2193 Precedence: bulk
2194 To: issue_tracker@your.tracker.email.domain.example
2195 Cc: richard@test.test
2196 Message-Id: <dummy_test_message_id>
2197 Subject: Re: [issue] Testing...
2199 Hi, I'm on holidays, and this is a dumb auto-responder.
2200 ''')
2202     def testAutoReplyEmailsAreIgnored(self):
2203         self.assertRaises(IgnoreBulk, self._handle_mail,
2204             '''Content-Type: text/plain;
2205   charset="iso-8859-1"
2206 From: Chef <chef@bork.bork.bork>
2207 To: issue_tracker@your.tracker.email.domain.example
2208 Cc: richard@test.test
2209 Message-Id: <dummy_test_message_id>
2210 Subject: Re: [issue] Out of office AutoReply: Back next week
2212 Hi, I am back in the office next week
2213 ''')
2215     def testNoSubject(self):
2216         self.assertRaises(MailUsageError, self._handle_mail,
2217             '''Content-Type: text/plain;
2218   charset="iso-8859-1"
2219 From: Chef <chef@bork.bork.bork>
2220 To: issue_tracker@your.tracker.email.domain.example
2221 Cc: richard@test.test
2222 Reply-To: chef@bork.bork.bork
2223 Message-Id: <dummy_test_message_id>
2225 ''')
2227     #
2228     # TEST FOR INVALID DESIGNATOR HANDLING
2229     #
2230     def testInvalidDesignator(self):
2231         self.assertRaises(MailUsageError, self._handle_mail,
2232             '''Content-Type: text/plain;
2233   charset="iso-8859-1"
2234 From: Chef <chef@bork.bork.bork>
2235 To: issue_tracker@your.tracker.email.domain.example
2236 Subject: [frobulated] testing
2237 Cc: richard@test.test
2238 Reply-To: chef@bork.bork.bork
2239 Message-Id: <dummy_test_message_id>
2241 ''')
2242         self.assertRaises(MailUsageError, self._handle_mail,
2243             '''Content-Type: text/plain;
2244   charset="iso-8859-1"
2245 From: Chef <chef@bork.bork.bork>
2246 To: issue_tracker@your.tracker.email.domain.example
2247 Subject: [issue12345] testing
2248 Cc: richard@test.test
2249 Reply-To: chef@bork.bork.bork
2250 Message-Id: <dummy_test_message_id>
2252 ''')
2254     def testInvalidClassLoose(self):
2255         self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'loose'
2256         nodeid = self._handle_mail('''Content-Type: text/plain;
2257   charset="iso-8859-1"
2258 From: Chef <chef@bork.bork.bork>
2259 To: issue_tracker@your.tracker.email.domain.example
2260 Subject: [frobulated] testing
2261 Cc: richard@test.test
2262 Reply-To: chef@bork.bork.bork
2263 Message-Id: <dummy_test_message_id>
2265 ''')
2266         assert not os.path.exists(SENDMAILDEBUG)
2267         self.assertEqual(self.db.issue.get(nodeid, 'title'),
2268             '[frobulated] testing')
2270     def testInvalidClassLooseReply(self):
2271         self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'loose'
2272         nodeid = self._handle_mail('''Content-Type: text/plain;
2273   charset="iso-8859-1"
2274 From: Chef <chef@bork.bork.bork>
2275 To: issue_tracker@your.tracker.email.domain.example
2276 Subject: Re: [frobulated] testing
2277 Cc: richard@test.test
2278 Reply-To: chef@bork.bork.bork
2279 Message-Id: <dummy_test_message_id>
2281 ''')
2282         assert not os.path.exists(SENDMAILDEBUG)
2283         self.assertEqual(self.db.issue.get(nodeid, 'title'),
2284             '[frobulated] testing')
2286     def testInvalidClassLoose(self):
2287         self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'loose'
2288         nodeid = self._handle_mail('''Content-Type: text/plain;
2289   charset="iso-8859-1"
2290 From: Chef <chef@bork.bork.bork>
2291 To: issue_tracker@your.tracker.email.domain.example
2292 Subject: [issue1234] testing
2293 Cc: richard@test.test
2294 Reply-To: chef@bork.bork.bork
2295 Message-Id: <dummy_test_message_id>
2297 ''')
2298         assert not os.path.exists(SENDMAILDEBUG)
2299         self.assertEqual(self.db.issue.get(nodeid, 'title'),
2300             '[issue1234] testing')
2302     def testClassLooseOK(self):
2303         self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'loose'
2304         self.db.keyword.create(name='Foo')
2305         nodeid = self._handle_mail('''Content-Type: text/plain;
2306   charset="iso-8859-1"
2307 From: Chef <chef@bork.bork.bork>
2308 To: issue_tracker@your.tracker.email.domain.example
2309 Subject: [keyword1] Testing... [name=Bar]
2310 Cc: richard@test.test
2311 Reply-To: chef@bork.bork.bork
2312 Message-Id: <dummy_test_message_id>
2314 ''')
2315         assert not os.path.exists(SENDMAILDEBUG)
2316         self.assertEqual(self.db.keyword.get('1', 'name'), 'Bar')
2318     def testClassStrictInvalid(self):
2319         self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'strict'
2320         self.instance.config.MAILGW_DEFAULT_CLASS = ''
2322         message = '''Content-Type: text/plain;
2323   charset="iso-8859-1"
2324 From: Chef <chef@bork.bork.bork>
2325 To: issue_tracker@your.tracker.email.domain.example
2326 Subject: Testing...
2327 Cc: richard@test.test
2328 Reply-To: chef@bork.bork.bork
2329 Message-Id: <dummy_test_message_id>
2331 '''
2332         self.assertRaises(MailUsageError, self._handle_mail, message)
2334     def testClassStrictValid(self):
2335         self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'strict'
2336         self.instance.config.MAILGW_DEFAULT_CLASS = ''
2338         nodeid = self._handle_mail('''Content-Type: text/plain;
2339   charset="iso-8859-1"
2340 From: Chef <chef@bork.bork.bork>
2341 To: issue_tracker@your.tracker.email.domain.example
2342 Subject: [issue] Testing...
2343 Cc: richard@test.test
2344 Reply-To: chef@bork.bork.bork
2345 Message-Id: <dummy_test_message_id>
2347 ''')
2349         assert not os.path.exists(SENDMAILDEBUG)
2350         self.assertEqual(self.db.issue.get(nodeid, 'title'), 'Testing...')
2352     #
2353     # TEST FOR INVALID COMMANDS HANDLING
2354     #
2355     def testInvalidCommands(self):
2356         self.assertRaises(MailUsageError, self._handle_mail,
2357             '''Content-Type: text/plain;
2358   charset="iso-8859-1"
2359 From: Chef <chef@bork.bork.bork>
2360 To: issue_tracker@your.tracker.email.domain.example
2361 Subject: testing [frobulated]
2362 Cc: richard@test.test
2363 Reply-To: chef@bork.bork.bork
2364 Message-Id: <dummy_test_message_id>
2366 ''')
2368     def testInvalidCommandPassthrough(self):
2369         self.instance.config.MAILGW_SUBJECT_SUFFIX_PARSING = 'none'
2370         nodeid = self._handle_mail('''Content-Type: text/plain;
2371   charset="iso-8859-1"
2372 From: Chef <chef@bork.bork.bork>
2373 To: issue_tracker@your.tracker.email.domain.example
2374 Subject: testing [frobulated]
2375 Cc: richard@test.test
2376 Reply-To: chef@bork.bork.bork
2377 Message-Id: <dummy_test_message_id>
2379 ''')
2380         assert not os.path.exists(SENDMAILDEBUG)
2381         self.assertEqual(self.db.issue.get(nodeid, 'title'),
2382             'testing [frobulated]')
2384     def testInvalidCommandPassthroughLoose(self):
2385         self.instance.config.MAILGW_SUBJECT_SUFFIX_PARSING = 'loose'
2386         nodeid = self._handle_mail('''Content-Type: text/plain;
2387   charset="iso-8859-1"
2388 From: Chef <chef@bork.bork.bork>
2389 To: issue_tracker@your.tracker.email.domain.example
2390 Subject: testing [frobulated]
2391 Cc: richard@test.test
2392 Reply-To: chef@bork.bork.bork
2393 Message-Id: <dummy_test_message_id>
2395 ''')
2396         assert not os.path.exists(SENDMAILDEBUG)
2397         self.assertEqual(self.db.issue.get(nodeid, 'title'),
2398             'testing [frobulated]')
2400     def testInvalidCommandPassthroughLooseOK(self):
2401         self.instance.config.MAILGW_SUBJECT_SUFFIX_PARSING = 'loose'
2402         nodeid = self._handle_mail('''Content-Type: text/plain;
2403   charset="iso-8859-1"
2404 From: Chef <chef@bork.bork.bork>
2405 To: issue_tracker@your.tracker.email.domain.example
2406 Subject: testing [assignedto=mary]
2407 Cc: richard@test.test
2408 Reply-To: chef@bork.bork.bork
2409 Message-Id: <dummy_test_message_id>
2411 ''')
2412         assert not os.path.exists(SENDMAILDEBUG)
2413         self.assertEqual(self.db.issue.get(nodeid, 'title'), 'testing')
2414         self.assertEqual(self.db.issue.get(nodeid, 'assignedto'), self.mary_id)
2416     def testCommandDelimiters(self):
2417         self.instance.config.MAILGW_SUBJECT_SUFFIX_DELIMITERS = '{}'
2418         nodeid = self._handle_mail('''Content-Type: text/plain;
2419   charset="iso-8859-1"
2420 From: Chef <chef@bork.bork.bork>
2421 To: issue_tracker@your.tracker.email.domain.example
2422 Subject: testing {assignedto=mary}
2423 Cc: richard@test.test
2424 Reply-To: chef@bork.bork.bork
2425 Message-Id: <dummy_test_message_id>
2427 ''')
2428         assert not os.path.exists(SENDMAILDEBUG)
2429         self.assertEqual(self.db.issue.get(nodeid, 'title'), 'testing')
2430         self.assertEqual(self.db.issue.get(nodeid, 'assignedto'), self.mary_id)
2432     def testPrefixDelimiters(self):
2433         self.instance.config.MAILGW_SUBJECT_SUFFIX_DELIMITERS = '{}'
2434         self.db.keyword.create(name='Foo')
2435         self._handle_mail('''Content-Type: text/plain;
2436   charset="iso-8859-1"
2437 From: richard <richard@test.test>
2438 To: issue_tracker@your.tracker.email.domain.example
2439 Message-Id: <followup_dummy_id>
2440 In-Reply-To: <dummy_test_message_id>
2441 Subject: {keyword1} Testing... {name=Bar}
2443 ''')
2444         assert not os.path.exists(SENDMAILDEBUG)
2445         self.assertEqual(self.db.keyword.get('1', 'name'), 'Bar')
2447     def testCommandDelimitersIgnore(self):
2448         self.instance.config.MAILGW_SUBJECT_SUFFIX_DELIMITERS = '{}'
2449         nodeid = self._handle_mail('''Content-Type: text/plain;
2450   charset="iso-8859-1"
2451 From: Chef <chef@bork.bork.bork>
2452 To: issue_tracker@your.tracker.email.domain.example
2453 Subject: testing [assignedto=mary]
2454 Cc: richard@test.test
2455 Reply-To: chef@bork.bork.bork
2456 Message-Id: <dummy_test_message_id>
2458 ''')
2459         assert not os.path.exists(SENDMAILDEBUG)
2460         self.assertEqual(self.db.issue.get(nodeid, 'title'),
2461             'testing [assignedto=mary]')
2462         self.assertEqual(self.db.issue.get(nodeid, 'assignedto'), None)
2464     def testReplytoMatch(self):
2465         self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'loose'
2466         nodeid = self.doNewIssue()
2467         nodeid2 = self._handle_mail('''Content-Type: text/plain;
2468   charset="iso-8859-1"
2469 From: Chef <chef@bork.bork.bork>
2470 To: issue_tracker@your.tracker.email.domain.example
2471 Message-Id: <dummy_test_message_id2>
2472 In-Reply-To: <dummy_test_message_id>
2473 Subject: Testing...
2475 Followup message.
2476 ''')
2478         nodeid3 = self._handle_mail('''Content-Type: text/plain;
2479   charset="iso-8859-1"
2480 From: Chef <chef@bork.bork.bork>
2481 To: issue_tracker@your.tracker.email.domain.example
2482 Message-Id: <dummy_test_message_id3>
2483 In-Reply-To: <dummy_test_message_id2>
2484 Subject: Testing...
2486 Yet another message in the same thread/issue.
2487 ''')
2489         self.assertEqual(nodeid, nodeid2)
2490         self.assertEqual(nodeid, nodeid3)
2492     def testHelpSubject(self):
2493         message = '''Content-Type: text/plain;
2494   charset="iso-8859-1"
2495 From: Chef <chef@bork.bork.bork>
2496 To: issue_tracker@your.tracker.email.domain.example
2497 Message-Id: <dummy_test_message_id2>
2498 In-Reply-To: <dummy_test_message_id>
2499 Subject: hElp
2502 '''
2503         self.assertRaises(MailUsageHelp, self._handle_mail, message)
2505     def testMaillistSubject(self):
2506         self.instance.config.MAILGW_SUBJECT_SUFFIX_DELIMITERS = '[]'
2507         self.db.keyword.create(name='Foo')
2508         self._handle_mail('''Content-Type: text/plain;
2509   charset="iso-8859-1"
2510 From: Chef <chef@bork.bork.bork>
2511 To: issue_tracker@your.tracker.email.domain.example
2512 Subject: [mailinglist-name] [keyword1] Testing.. [name=Bar]
2513 Cc: richard@test.test
2514 Reply-To: chef@bork.bork.bork
2515 Message-Id: <dummy_test_message_id>
2517 ''')
2519         assert not os.path.exists(SENDMAILDEBUG)
2520         self.assertEqual(self.db.keyword.get('1', 'name'), 'Bar')
2522     def testUnknownPrefixSubject(self):
2523         self.db.keyword.create(name='Foo')
2524         self._handle_mail('''Content-Type: text/plain;
2525   charset="iso-8859-1"
2526 From: Chef <chef@bork.bork.bork>
2527 To: issue_tracker@your.tracker.email.domain.example
2528 Subject: VeryStrangeRe: [keyword1] Testing.. [name=Bar]
2529 Cc: richard@test.test
2530 Reply-To: chef@bork.bork.bork
2531 Message-Id: <dummy_test_message_id>
2533 ''')
2535         assert not os.path.exists(SENDMAILDEBUG)
2536         self.assertEqual(self.db.keyword.get('1', 'name'), 'Bar')
2538     def testOneCharSubject(self):
2539         message = '''Content-Type: text/plain;
2540   charset="iso-8859-1"
2541 From: Chef <chef@bork.bork.bork>
2542 To: issue_tracker@your.tracker.email.domain.example
2543 Subject: b
2544 Cc: richard@test.test
2545 Reply-To: chef@bork.bork.bork
2546 Message-Id: <dummy_test_message_id>
2548 '''
2549         try:
2550             self._handle_mail(message)
2551         except MailUsageError:
2552             self.fail('MailUsageError raised')
2554     def testIssueidLast(self):
2555         nodeid1 = self.doNewIssue()
2556         nodeid2 = self._handle_mail('''Content-Type: text/plain;
2557   charset="iso-8859-1"
2558 From: mary <mary@test.test>
2559 To: issue_tracker@your.tracker.email.domain.example
2560 Message-Id: <followup_dummy_id>
2561 In-Reply-To: <dummy_test_message_id>
2562 Subject: New title [issue1]
2564 This is a second followup
2565 ''')
2567         assert nodeid1 == nodeid2
2568         self.assertEqual(self.db.issue.get(nodeid2, 'title'), "Testing...")
2570     def testSecurityMessagePermissionContent(self):
2571         id = self.doNewIssue()
2572         issue = self.db.issue.getnode (id)
2573         self.db.security.addRole(name='Nomsg')
2574         self.db.security.addPermissionToRole('Nomsg', 'Email Access')
2575         for cl in 'issue', 'file', 'keyword':
2576             for p in 'View', 'Edit', 'Create':
2577                 self.db.security.addPermissionToRole('Nomsg', p, cl)
2578         self.db.user.set(self.mary_id, roles='Nomsg')
2579         nodeid = self._handle_mail('''Content-Type: text/plain;
2580   charset="iso-8859-1"
2581 From: Chef <chef@bork.bork.bork>
2582 To: issue_tracker@your.tracker.email.domain.example
2583 Message-Id: <dummy_test_message_id_2>
2584 Subject: [issue%(id)s] Testing... [nosy=+mary]
2586 Just a test reply
2587 '''%locals())
2588         assert os.path.exists(SENDMAILDEBUG)
2589         self.compareMessages(self._get_mail(),
2590 '''FROM: roundup-admin@your.tracker.email.domain.example
2591 TO: chef@bork.bork.bork, richard@test.test
2592 Content-Type: text/plain; charset="utf-8"
2593 Subject: [issue1] Testing...
2594 To: richard@test.test
2595 From: "Bork, Chef" <issue_tracker@your.tracker.email.domain.example>
2596 Reply-To: Roundup issue tracker
2597  <issue_tracker@your.tracker.email.domain.example>
2598 MIME-Version: 1.0
2599 Message-Id: <dummy_test_message_id_2>
2600 In-Reply-To: <dummy_test_message_id>
2601 X-Roundup-Name: Roundup issue tracker
2602 X-Roundup-Loop: hello
2603 X-Roundup-Issue-Status: chatting
2604 Content-Transfer-Encoding: quoted-printable
2607 Bork, Chef <chef@bork.bork.bork> added the comment:
2609 Just a test reply
2611 ----------
2612 nosy: +mary
2613 status: unread -> chatting
2615 _______________________________________________________________________
2616 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
2617 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
2618 _______________________________________________________________________
2619 ''')
2621     def testOutlookAttachment(self):
2622         message = '''X-MimeOLE: Produced By Microsoft Exchange V6.5
2623 Content-class: urn:content-classes:message
2624 MIME-Version: 1.0
2625 Content-Type: multipart/mixed;
2626         boundary="----_=_NextPart_001_01CACA65.40A51CBC"
2627 Subject: Example of a failed outlook attachment e-mail
2628 Date: Tue, 23 Mar 2010 01:43:44 -0700
2629 Message-ID: <CA37F17219784343816CA6613D2E339205E7D0F9@nrcwstexb1.nrc.ca>
2630 X-MS-Has-Attach: yes
2631 X-MS-TNEF-Correlator: 
2632 Thread-Topic: Example of a failed outlook attachment e-mail
2633 Thread-Index: AcrKJo/t3pUBBwTpSwWNE3LE67UBDQ==
2634 From: "Hugh" <richard@test.test>
2635 To: <richard@test.test>
2636 X-OriginalArrivalTime: 23 Mar 2010 08:45:57.0350 (UTC) FILETIME=[41893860:01CACA65]
2638 This is a multi-part message in MIME format.
2640 ------_=_NextPart_001_01CACA65.40A51CBC
2641 Content-Type: multipart/alternative;
2642         boundary="----_=_NextPart_002_01CACA65.40A51CBC"
2645 ------_=_NextPart_002_01CACA65.40A51CBC
2646 Content-Type: text/plain;
2647         charset="us-ascii"
2648 Content-Transfer-Encoding: quoted-printable
2651 Hi Richard,
2653 I suppose this isn't the exact message that was sent but is a resend of
2654 one of my trial messages that failed.  For your benefit I changed the
2655 subject line and am adding these words to the message body.  Should
2656 still be as problematic, but if you like I can resend an exact copy of a
2657 failed message changing nothing except putting your address instead of
2658 our tracker.
2660 Thanks very much for taking time to look into this.  Much appreciated.
2662  <<battery backup>>=20
2664 ------_=_NextPart_002_01CACA65.40A51CBC
2665 Content-Type: text/html;
2666         charset="us-ascii"
2667 Content-Transfer-Encoding: quoted-printable
2669 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
2670 <HTML>
2671 <HEAD>
2672 <META HTTP-EQUIV=3D"Content-Type" CONTENT=3D"text/html; =
2673 charset=3Dus-ascii">
2674 <META NAME=3D"Generator" CONTENT=3D"MS Exchange Server version =
2675 6.5.7654.12">
2676 <TITLE>Example of a failed outlook attachment e-mail</TITLE>
2677 </HEAD>
2678 <BODY>
2679 <!-- Converted from text/rtf format -->
2680 <BR>
2682 <P><FONT SIZE=3D2 FACE=3D"Arial">Hi Richard,</FONT>
2683 </P>
2685 <P><FONT SIZE=3D2 FACE=3D"Arial">I suppose this isn't the exact message =
2686 that was sent but is a resend of one of my trial messages that =
2687 failed.&nbsp; For your benefit I changed the subject line and am adding =
2688 these words to the message body.&nbsp; Should still be as problematic, =
2689 but if you like I can resend an exact copy of a failed message changing =
2690 nothing except putting your address instead of our tracker.</FONT></P>
2692 <P><FONT SIZE=3D2 FACE=3D"Arial">Thanks very much for taking time to =
2693 look into this.&nbsp; Much appreciated.</FONT>
2694 </P>
2695 <BR>
2697 <P><FONT FACE=3D"Arial" SIZE=3D2 COLOR=3D"#000000"> &lt;&lt;battery =
2698 backup&gt;&gt; </FONT>
2699 </P>
2701 </BODY>
2702 </HTML>
2703 ------_=_NextPart_002_01CACA65.40A51CBC--
2705 ------_=_NextPart_001_01CACA65.40A51CBC
2706 Content-Type: message/rfc822
2707 Content-Transfer-Encoding: 7bit
2709 X-MimeOLE: Produced By Microsoft Exchange V6.5
2710 MIME-Version: 1.0
2711 Content-Type: multipart/alternative;
2712         boundary="----_=_NextPart_003_01CAC15A.29717800"
2713 X-OriginalArrivalTime: 11 Mar 2010 20:33:51.0249 (UTC) FILETIME=[28FEE010:01CAC15A]
2714 Content-class: urn:content-classes:message
2715 Subject: battery backup
2716 Date: Thu, 11 Mar 2010 13:33:43 -0700
2717 Message-ID: <p06240809c7bf02f9624c@[128.114.22.203]>
2718 X-MS-Has-Attach: 
2719 X-MS-TNEF-Correlator: 
2720 Thread-Topic: battery backup
2721 Thread-Index: AcrBWimtulTrSvBdQ2CcfZ8lyQdxmQ==
2722 From: "Jerry" <jerry@test.test>
2723 To: "Hugh" <hugh@test.test>
2725 This is a multi-part message in MIME format.
2727 ------_=_NextPart_003_01CAC15A.29717800
2728 Content-Type: text/plain;
2729         charset="iso-8859-1"
2730 Content-Transfer-Encoding: quoted-printable
2732 Dear Hugh,
2733         A car batter has an energy capacity of ~ 500Wh.  A UPS=20
2734 battery is worse than this.
2736 if we need to provied 100kW for 30 minutes that will take 100 car=20
2737 batteries.  This seems like an awful lot of batteries.
2739 Of course I like your idea of making the time 1 minute, so we get to=20
2740 a more modest number of batteries
2742 Jerry
2745 ------_=_NextPart_003_01CAC15A.29717800
2746 Content-Type: text/html;
2747         charset="iso-8859-1"
2748 Content-Transfer-Encoding: quoted-printable
2750 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
2751 <HTML>
2752 <HEAD>
2753 <META HTTP-EQUIV=3D"Content-Type" CONTENT=3D"text/html; =
2754 charset=3Diso-8859-1">
2755 <META NAME=3D"Generator" CONTENT=3D"MS Exchange Server version =
2756 6.5.7654.12">
2757 <TITLE>battery backup</TITLE>
2758 </HEAD>
2759 <BODY>
2760 <!-- Converted from text/plain format -->
2762 <P><FONT SIZE=3D2>Dear Hugh,</FONT>
2764 <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <FONT SIZE=3D2>A car =
2765 batter has an energy capacity of ~ 500Wh.&nbsp; A UPS </FONT>
2767 <BR><FONT SIZE=3D2>battery is worse than this.</FONT>
2768 </P>
2770 <P><FONT SIZE=3D2>if we need to provied 100kW for 30 minutes that will =
2771 take 100 car </FONT>
2773 <BR><FONT SIZE=3D2>batteries.&nbsp; This seems like an awful lot of =
2774 batteries.</FONT>
2775 </P>
2777 <P><FONT SIZE=3D2>Of course I like your idea of making the time 1 =
2778 minute, so we get to </FONT>
2780 <BR><FONT SIZE=3D2>a more modest number of batteries</FONT>
2781 </P>
2783 <P><FONT SIZE=3D2>Jerry</FONT>
2784 </P>
2786 </BODY>
2787 </HTML>
2788 ------_=_NextPart_003_01CAC15A.29717800--
2790 ------_=_NextPart_001_01CACA65.40A51CBC--
2791 '''
2792         nodeid = self._handle_mail(message)
2793         assert not os.path.exists(SENDMAILDEBUG)
2794         msgid = self.db.issue.get(nodeid, 'messages')[0]
2795         self.assert_(self.db.msg.get(msgid, 'content').startswith('Hi Richard'))
2796         self.assertEqual(self.db.msg.get(msgid, 'files'), ['1', '2'])
2797         fileid = self.db.msg.get(msgid, 'files')[0]
2798         self.assertEqual(self.db.file.get(fileid, 'type'), 'text/html')
2799         fileid = self.db.msg.get(msgid, 'files')[1]
2800         self.assertEqual(self.db.file.get(fileid, 'type'), 'message/rfc822')
2802     def testForwardedMessageAttachment(self):
2803         message = '''Return-Path: <rgg@test.test>
2804 Received: from localhost(127.0.0.1), claiming to be "[115.130.26.69]"
2805 via SMTP by localhost, id smtpdAAApLaWrq; Tue Apr 13 23:10:05 2010
2806 Message-ID: <4BC4F9C7.50409@test.test>
2807 Date: Wed, 14 Apr 2010 09:09:59 +1000
2808 From: Rupert Goldie <rgg@test.test>
2809 User-Agent: Thunderbird 2.0.0.24 (Windows/20100228)
2810 MIME-Version: 1.0
2811 To: ekit issues <issues@test.test>
2812 Subject: [Fwd: PHP ERROR (fb)] post limit reached
2813 Content-Type: multipart/mixed; boundary="------------000807090608060304010403"
2815 This is a multi-part message in MIME format.
2816 --------------000807090608060304010403
2817 Content-Type: text/plain; charset=ISO-8859-1; format=flowed
2818 Content-Transfer-Encoding: 7bit
2820 Catch this exception and log it without emailing.
2822 --------------000807090608060304010403
2823 Content-Type: message/rfc822; name="PHP ERROR (fb).eml"
2824 Content-Transfer-Encoding: 7bit
2825 Content-Disposition: inline; filename="PHP ERROR (fb).eml"
2827 Return-Path: <ektravj@test.test>
2828 X-Sieve: CMU Sieve 2.2
2829 via SMTP by crown.off.ekorp.com, id smtpdAAA1JaW1o; Tue Apr 13 23:01:04 2010
2830 X-Virus-Scanned: by amavisd-new at ekit.com
2831 To: facebook-errors@test.test
2832 From: ektravj@test.test
2833 Subject: PHP ERROR (fb)
2834 Message-Id: <20100413230100.D601D27E84@mail2.elax3.ekorp.com>
2835 Date: Tue, 13 Apr 2010 23:01:00 +0000 (UTC)
2837 [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
2838 Stack trace:
2839 #0 /app/01/www/virtual/fb.ekit.com/htdocs/gateway/ekit/feed/index.php(178): fb_exceptions(Object(FacebookRestClientException))
2840 #1 {main}
2841  thrown in /app/01/www/virtual/fb.ekit.com/htdocs/includes/functions.php on line 280
2844 --------------000807090608060304010403--
2845 '''
2846         nodeid = self._handle_mail(message)
2847         assert not os.path.exists(SENDMAILDEBUG)
2848         msgid = self.db.issue.get(nodeid, 'messages')[0]
2849         self.assertEqual(self.db.msg.get(msgid, 'content'),
2850             'Catch this exception and log it without emailing.')
2851         self.assertEqual(self.db.msg.get(msgid, 'files'), ['1'])
2852         fileid = self.db.msg.get(msgid, 'files')[0]
2853         self.assertEqual(self.db.file.get(fileid, 'type'), 'message/rfc822')
2855 def test_suite():
2856     suite = unittest.TestSuite()
2857     suite.addTest(unittest.makeSuite(MailgwTestCase))
2858     return suite
2860 if __name__ == '__main__':
2861     runner = unittest.TextTestRunner()
2862     unittest.main(testRunner=runner)
2864 # vim: set filetype=python sts=4 sw=4 et si :