Code

- fix new mailgw test (-c option :-)
[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... [status=chatting;priority=critical]
273 Hi there!
274 ''', (('-c', 'issue'),))
275         self.assertEqual(self.db.issue.get(nodeid, 'title'), 'Testing...')
276         self.assertEqual(self.db.issue.get(nodeid, 'status'), '3')
277         self.assertEqual(self.db.issue.get(nodeid, 'priority'), '1')
279     def doNewIssue(self):
280         nodeid = self._handle_mail('''Content-Type: text/plain;
281   charset="iso-8859-1"
282 From: Chef <chef@bork.bork.bork>
283 To: issue_tracker@your.tracker.email.domain.example
284 Cc: richard@test.test
285 Message-Id: <dummy_test_message_id>
286 Subject: [issue] Testing...
288 This is a test submission of a new issue.
289 ''')
290         assert not os.path.exists(SENDMAILDEBUG)
291         l = self.db.issue.get(nodeid, 'nosy')
292         l.sort()
293         self.assertEqual(l, [self.chef_id, self.richard_id])
294         return nodeid
296     def testNewIssue(self):
297         self.doNewIssue()
299     def testNewIssueNosy(self):
300         self.instance.config.ADD_AUTHOR_TO_NOSY = 'yes'
301         nodeid = self._handle_mail('''Content-Type: text/plain;
302   charset="iso-8859-1"
303 From: Chef <chef@bork.bork.bork>
304 To: issue_tracker@your.tracker.email.domain.example
305 Cc: richard@test.test
306 Message-Id: <dummy_test_message_id>
307 Subject: [issue] Testing...
309 This is a test submission of a new issue.
310 ''')
311         assert not os.path.exists(SENDMAILDEBUG)
312         l = self.db.issue.get(nodeid, 'nosy')
313         l.sort()
314         self.assertEqual(l, [self.chef_id, self.richard_id])
316     def testAlternateAddress(self):
317         self._handle_mail('''Content-Type: text/plain;
318   charset="iso-8859-1"
319 From: John Doe <john.doe@test.test>
320 To: issue_tracker@your.tracker.email.domain.example
321 Message-Id: <dummy_test_message_id>
322 Subject: [issue] Testing...
324 This is a test submission of a new issue.
325 ''')
326         userlist = self.db.user.list()
327         assert not os.path.exists(SENDMAILDEBUG)
328         self.assertEqual(userlist, self.db.user.list(),
329             "user created when it shouldn't have been")
331     def testNewIssueNoClass(self):
332         self._handle_mail('''Content-Type: text/plain;
333   charset="iso-8859-1"
334 From: Chef <chef@bork.bork.bork>
335 To: issue_tracker@your.tracker.email.domain.example
336 Cc: richard@test.test
337 Message-Id: <dummy_test_message_id>
338 Subject: Testing...
340 This is a test submission of a new issue.
341 ''')
342         assert not os.path.exists(SENDMAILDEBUG)
344     def testNewIssueAuthMsg(self):
345         # TODO: fix the damn config - this is apalling
346         self.db.config.MESSAGES_TO_AUTHOR = 'yes'
347         self._handle_mail('''Content-Type: text/plain;
348   charset="iso-8859-1"
349 From: Chef <chef@bork.bork.bork>
350 To: issue_tracker@your.tracker.email.domain.example
351 Message-Id: <dummy_test_message_id>
352 Subject: [issue] Testing... [nosy=mary; assignedto=richard]
354 This is a test submission of a new issue.
355 ''')
356         self.compareMessages(self._get_mail(),
357 '''FROM: roundup-admin@your.tracker.email.domain.example
358 TO: chef@bork.bork.bork, mary@test.test, richard@test.test
359 Content-Type: text/plain; charset="utf-8"
360 Subject: [issue1] Testing...
361 To: chef@bork.bork.bork, mary@test.test, richard@test.test
362 From: "Bork, Chef" <issue_tracker@your.tracker.email.domain.example>
363 Reply-To: Roundup issue tracker
364  <issue_tracker@your.tracker.email.domain.example>
365 MIME-Version: 1.0
366 Message-Id: <dummy_test_message_id>
367 X-Roundup-Name: Roundup issue tracker
368 X-Roundup-Loop: hello
369 X-Roundup-Issue-Status: unread
370 Content-Transfer-Encoding: quoted-printable
373 New submission from Bork, Chef <chef@bork.bork.bork>:
375 This is a test submission of a new issue.
377 ----------
378 assignedto: richard
379 messages: 1
380 nosy: Chef, mary, richard
381 status: unread
382 title: Testing...
384 _______________________________________________________________________
385 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
386 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
387 _______________________________________________________________________
388 ''')
390     def testNewIssueNoAuthorInfo(self):
391         self.db.config.MAIL_ADD_AUTHORINFO = 'no'
392         self._handle_mail('''Content-Type: text/plain;
393   charset="iso-8859-1"
394 From: Chef <chef@bork.bork.bork>
395 To: issue_tracker@your.tracker.email.domain.example
396 Message-Id: <dummy_test_message_id>
397 Subject: [issue] Testing... [nosy=mary; assignedto=richard]
399 This is a test submission of a new issue.
400 ''')
401         self.compareMessages(self._get_mail(),
402 '''FROM: roundup-admin@your.tracker.email.domain.example
403 TO: chef@bork.bork.bork, mary@test.test, richard@test.test
404 Content-Type: text/plain; charset="utf-8"
405 Subject: [issue1] Testing...
406 To: mary@test.test, richard@test.test
407 From: "Bork, Chef" <issue_tracker@your.tracker.email.domain.example>
408 Reply-To: Roundup issue tracker
409  <issue_tracker@your.tracker.email.domain.example>
410 MIME-Version: 1.0
411 Message-Id: <dummy_test_message_id>
412 X-Roundup-Name: Roundup issue tracker
413 X-Roundup-Loop: hello
414 X-Roundup-Issue-Status: unread
415 Content-Transfer-Encoding: quoted-printable
417 This is a test submission of a new issue.
419 ----------
420 assignedto: richard
421 messages: 1
422 nosy: Chef, mary, richard
423 status: unread
424 title: Testing...
426 _______________________________________________________________________
427 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
428 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
429 _______________________________________________________________________
430 ''')
432     def testNewIssueNoAuthorEmail(self):
433         self.db.config.MAIL_ADD_AUTHOREMAIL = 'no'
434         self._handle_mail('''Content-Type: text/plain;
435   charset="iso-8859-1"
436 From: Chef <chef@bork.bork.bork>
437 To: issue_tracker@your.tracker.email.domain.example
438 Message-Id: <dummy_test_message_id>
439 Subject: [issue] Testing... [nosy=mary; assignedto=richard]
441 This is a test submission of a new issue.
442 ''')
443         self.compareMessages(self._get_mail(),
444 '''FROM: roundup-admin@your.tracker.email.domain.example
445 TO: chef@bork.bork.bork, mary@test.test, richard@test.test
446 Content-Type: text/plain; charset="utf-8"
447 Subject: [issue1] Testing...
448 To: mary@test.test, richard@test.test
449 From: "Bork, Chef" <issue_tracker@your.tracker.email.domain.example>
450 Reply-To: Roundup issue tracker
451  <issue_tracker@your.tracker.email.domain.example>
452 MIME-Version: 1.0
453 Message-Id: <dummy_test_message_id>
454 X-Roundup-Name: Roundup issue tracker
455 X-Roundup-Loop: hello
456 X-Roundup-Issue-Status: unread
457 Content-Transfer-Encoding: quoted-printable
459 New submission from Bork, Chef:
461 This is a test submission of a new issue.
463 ----------
464 assignedto: richard
465 messages: 1
466 nosy: Chef, mary, richard
467 status: unread
468 title: Testing...
470 _______________________________________________________________________
471 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
472 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
473 _______________________________________________________________________
474 ''')
476     multipart_msg = '''From: mary <mary@test.test>
477 To: issue_tracker@your.tracker.email.domain.example
478 Message-Id: <followup_dummy_id>
479 In-Reply-To: <dummy_test_message_id>
480 Subject: [issue1] Testing...
481 Content-Type: multipart/mixed; boundary="bxyzzy"
482 Content-Disposition: inline
485 --bxyzzy
486 Content-Type: multipart/alternative; boundary="bCsyhTFzCvuiizWE"
487 Content-Disposition: inline
489 --bCsyhTFzCvuiizWE
490 Content-Type: text/plain; charset=us-ascii
491 Content-Disposition: inline
493 test attachment first text/plain
495 --bCsyhTFzCvuiizWE
496 Content-Type: application/octet-stream
497 Content-Disposition: attachment; filename="first.dvi"
498 Content-Transfer-Encoding: base64
500 SnVzdCBhIHRlc3QgAQo=
502 --bCsyhTFzCvuiizWE
503 Content-Type: text/plain; charset=us-ascii
504 Content-Disposition: inline
506 test attachment second text/plain
508 --bCsyhTFzCvuiizWE
509 Content-Type: text/html
510 Content-Disposition: inline
512 <html>
513 to be ignored.
514 </html>
516 --bCsyhTFzCvuiizWE--
518 --bxyzzy
519 Content-Type: multipart/alternative; boundary="bCsyhTFzCvuiizWF"
520 Content-Disposition: inline
522 --bCsyhTFzCvuiizWF
523 Content-Type: text/plain; charset=us-ascii
524 Content-Disposition: inline
526 test attachment third text/plain
528 --bCsyhTFzCvuiizWF
529 Content-Type: application/octet-stream
530 Content-Disposition: attachment; filename="second.dvi"
531 Content-Transfer-Encoding: base64
533 SnVzdCBhIHRlc3QK
535 --bCsyhTFzCvuiizWF--
537 --bxyzzy--
538 '''
540     multipart_msg_latin1 = '''From: mary <mary@test.test>
541 To: issue_tracker@your.tracker.email.domain.example
542 Message-Id: <followup_dummy_id>
543 In-Reply-To: <dummy_test_message_id>
544 Subject: [issue1] Testing...
545 Content-Type: multipart/alternative; boundary=001485f339f8f361fb049188dbba
548 --001485f339f8f361fb049188dbba
549 Content-Type: text/plain; charset=ISO-8859-1
550 Content-Transfer-Encoding: quoted-printable
552 umlaut =E4=F6=FC=C4=D6=DC=DF
554 --001485f339f8f361fb049188dbba
555 Content-Type: text/html; charset=ISO-8859-1
556 Content-Transfer-Encoding: quoted-printable
558 <html>umlaut =E4=F6=FC=C4=D6=DC=DF</html>
560 --001485f339f8f361fb049188dbba--
561 '''
563     multipart_msg_rfc822 = '''From: mary <mary@test.test>
564 To: issue_tracker@your.tracker.email.domain.example
565 Message-Id: <followup_dummy_id>
566 In-Reply-To: <dummy_test_message_id>
567 Subject: [issue1] Testing...
568 Content-Type: multipart/mixed; boundary=001485f339f8f361fb049188dbba
570 This is a multi-part message in MIME format.
571 --001485f339f8f361fb049188dbba
572 Content-Type: text/plain; charset=ISO-8859-15
573 Content-Transfer-Encoding: 7bit
575 First part: Text
577 --001485f339f8f361fb049188dbba
578 Content-Type: message/rfc822; name="Fwd: Original email subject.eml"
579 Content-Transfer-Encoding: 7bit
580 Content-Disposition: attachment; filename="Fwd: Original email subject.eml"
582 Message-Id: <followup_dummy_id_2>
583 In-Reply-To: <dummy_test_message_id_2>
584 MIME-Version: 1.0
585 Subject: Fwd: Original email subject
586 Date: Mon, 23 Aug 2010 08:23:33 +0200
587 Content-Type: multipart/alternative; boundary="090500050101020406060002"
589 This is a multi-part message in MIME format.
590 --090500050101020406060002
591 Content-Type: text/plain; charset=ISO-8859-15; format=flowed
592 Content-Transfer-Encoding: 7bit
594 some text in inner email
595 ========================
597 --090500050101020406060002
598 Content-Type: text/html; charset=ISO-8859-15
599 Content-Transfer-Encoding: 7bit
601 <html>
602 some text in inner email
603 ========================
604 </html>
606 --090500050101020406060002--
608 --001485f339f8f361fb049188dbba--
609 '''
611     def testMultipartKeepAlternatives(self):
612         self.doNewIssue()
613         self._handle_mail(self.multipart_msg)
614         messages = self.db.issue.get('1', 'messages')
615         messages.sort()
616         msg = self.db.msg.getnode (messages[-1])
617         assert(len(msg.files) == 5)
618         names = {0 : 'first.dvi', 4 : 'second.dvi'}
619         content = {3 : 'test attachment third text/plain\n',
620                    4 : 'Just a test\n'}
621         for n, id in enumerate (msg.files):
622             f = self.db.file.getnode (id)
623             self.assertEqual(f.name, names.get (n, 'unnamed'))
624             if n in content :
625                 self.assertEqual(f.content, content [n])
626         self.assertEqual(msg.content, 'test attachment second text/plain')
628     def testMultipartDropAlternatives(self):
629         self.doNewIssue()
630         self.db.config.MAILGW_IGNORE_ALTERNATIVES = True
631         self._handle_mail(self.multipart_msg)
632         messages = self.db.issue.get('1', 'messages')
633         messages.sort()
634         msg = self.db.msg.getnode (messages[-1])
635         assert(len(msg.files) == 2)
636         names = {1 : 'second.dvi'}
637         content = {0 : 'test attachment third text/plain\n',
638                    1 : 'Just a test\n'}
639         for n, id in enumerate (msg.files):
640             f = self.db.file.getnode (id)
641             self.assertEqual(f.name, names.get (n, 'unnamed'))
642             if n in content :
643                 self.assertEqual(f.content, content [n])
644         self.assertEqual(msg.content, 'test attachment second text/plain')
646     def testMultipartCharsetUTF8NoAttach(self):
647         c = 'umlaut \xc3\xa4\xc3\xb6\xc3\xbc\xc3\x84\xc3\x96\xc3\x9c\xc3\x9f'
648         self.doNewIssue()
649         self.db.config.NOSY_MAX_ATTACHMENT_SIZE = 0
650         self._handle_mail(self.multipart_msg_latin1)
651         messages = self.db.issue.get('1', 'messages')
652         messages.sort()
653         msg = self.db.msg.getnode (messages[-1])
654         assert(len(msg.files) == 1)
655         name = 'unnamed'
656         content = '<html>' + c + '</html>\n'
657         for n, id in enumerate (msg.files):
658             f = self.db.file.getnode (id)
659             self.assertEqual(f.name, name)
660             self.assertEqual(f.content, content)
661         self.assertEqual(msg.content, c)
662         self.compareMessages(self._get_mail(),
663 '''FROM: roundup-admin@your.tracker.email.domain.example
664 TO: chef@bork.bork.bork, richard@test.test
665 Content-Type: text/plain; charset="utf-8"
666 Subject: [issue1] Testing...
667 To: chef@bork.bork.bork, richard@test.test
668 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
669 Reply-To: Roundup issue tracker
670  <issue_tracker@your.tracker.email.domain.example>
671 MIME-Version: 1.0
672 Message-Id: <followup_dummy_id>
673 In-Reply-To: <dummy_test_message_id>
674 X-Roundup-Name: Roundup issue tracker
675 X-Roundup-Loop: hello
676 X-Roundup-Issue-Status: chatting
677 X-Roundup-Issue-Files: unnamed
678 Content-Transfer-Encoding: quoted-printable
681 Contrary, Mary <mary@test.test> added the comment:
683 umlaut =C3=A4=C3=B6=C3=BC=C3=84=C3=96=C3=9C=C3=9F
684 File 'unnamed' not attached - you can download it from http://tracker.examp=
685 le/cgi-bin/roundup.cgi/bugs/file1.
687 ----------
688 status: unread -> chatting
690 _______________________________________________________________________
691 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
692 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
693 _______________________________________________________________________
694 ''')
696     def testMultipartCharsetLatin1NoAttach(self):
697         c = 'umlaut \xc3\xa4\xc3\xb6\xc3\xbc\xc3\x84\xc3\x96\xc3\x9c\xc3\x9f'
698         self.doNewIssue()
699         self.db.config.NOSY_MAX_ATTACHMENT_SIZE = 0
700         self.db.config.MAIL_CHARSET = 'iso-8859-1'
701         self._handle_mail(self.multipart_msg_latin1)
702         messages = self.db.issue.get('1', 'messages')
703         messages.sort()
704         msg = self.db.msg.getnode (messages[-1])
705         assert(len(msg.files) == 1)
706         name = 'unnamed'
707         content = '<html>' + c + '</html>\n'
708         for n, id in enumerate (msg.files):
709             f = self.db.file.getnode (id)
710             self.assertEqual(f.name, name)
711             self.assertEqual(f.content, content)
712         self.assertEqual(msg.content, c)
713         self.compareMessages(self._get_mail(),
714 '''FROM: roundup-admin@your.tracker.email.domain.example
715 TO: chef@bork.bork.bork, richard@test.test
716 Content-Type: text/plain; charset="iso-8859-1"
717 Subject: [issue1] Testing...
718 To: chef@bork.bork.bork, richard@test.test
719 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
720 Reply-To: Roundup issue tracker
721  <issue_tracker@your.tracker.email.domain.example>
722 MIME-Version: 1.0
723 Message-Id: <followup_dummy_id>
724 In-Reply-To: <dummy_test_message_id>
725 X-Roundup-Name: Roundup issue tracker
726 X-Roundup-Loop: hello
727 X-Roundup-Issue-Status: chatting
728 X-Roundup-Issue-Files: unnamed
729 Content-Transfer-Encoding: quoted-printable
732 Contrary, Mary <mary@test.test> added the comment:
734 umlaut =E4=F6=FC=C4=D6=DC=DF
735 File 'unnamed' not attached - you can download it from http://tracker.examp=
736 le/cgi-bin/roundup.cgi/bugs/file1.
738 ----------
739 status: unread -> chatting
741 _______________________________________________________________________
742 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
743 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
744 _______________________________________________________________________
745 ''')
747     def testMultipartCharsetUTF8AttachFile(self):
748         c = 'umlaut \xc3\xa4\xc3\xb6\xc3\xbc\xc3\x84\xc3\x96\xc3\x9c\xc3\x9f'
749         self.doNewIssue()
750         self._handle_mail(self.multipart_msg_latin1)
751         messages = self.db.issue.get('1', 'messages')
752         messages.sort()
753         msg = self.db.msg.getnode (messages[-1])
754         assert(len(msg.files) == 1)
755         name = 'unnamed'
756         content = '<html>' + c + '</html>\n'
757         for n, id in enumerate (msg.files):
758             f = self.db.file.getnode (id)
759             self.assertEqual(f.name, name)
760             self.assertEqual(f.content, content)
761         self.assertEqual(msg.content, c)
762         self.compareMessages(self._get_mail(),
763 '''FROM: roundup-admin@your.tracker.email.domain.example
764 TO: chef@bork.bork.bork, richard@test.test
765 Content-Type: multipart/mixed; boundary="utf-8"
766 Subject: [issue1] Testing...
767 To: chef@bork.bork.bork, richard@test.test
768 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
769 Reply-To: Roundup issue tracker
770  <issue_tracker@your.tracker.email.domain.example>
771 MIME-Version: 1.0
772 Message-Id: <followup_dummy_id>
773 In-Reply-To: <dummy_test_message_id>
774 X-Roundup-Name: Roundup issue tracker
775 X-Roundup-Loop: hello
776 X-Roundup-Issue-Status: chatting
777 X-Roundup-Issue-Files: unnamed
778 Content-Transfer-Encoding: quoted-printable
781 --utf-8
782 MIME-Version: 1.0
783 Content-Type: text/plain; charset="utf-8"
784 Content-Transfer-Encoding: quoted-printable
787 Contrary, Mary <mary@test.test> added the comment:
789 umlaut =C3=A4=C3=B6=C3=BC=C3=84=C3=96=C3=9C=C3=9F
791 ----------
792 status: unread -> chatting
794 _______________________________________________________________________
795 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
796 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
797 _______________________________________________________________________
798 --utf-8
799 Content-Type: text/html
800 MIME-Version: 1.0
801 Content-Transfer-Encoding: base64
802 Content-Disposition: attachment;
803  filename="unnamed"
805 PGh0bWw+dW1sYXV0IMOkw7bDvMOEw5bDnMOfPC9odG1sPgo=
807 --utf-8--
808 ''')
810     def testMultipartCharsetLatin1AttachFile(self):
811         c = 'umlaut \xc3\xa4\xc3\xb6\xc3\xbc\xc3\x84\xc3\x96\xc3\x9c\xc3\x9f'
812         self.doNewIssue()
813         self.db.config.MAIL_CHARSET = 'iso-8859-1'
814         self._handle_mail(self.multipart_msg_latin1)
815         messages = self.db.issue.get('1', 'messages')
816         messages.sort()
817         msg = self.db.msg.getnode (messages[-1])
818         assert(len(msg.files) == 1)
819         name = 'unnamed'
820         content = '<html>' + c + '</html>\n'
821         for n, id in enumerate (msg.files):
822             f = self.db.file.getnode (id)
823             self.assertEqual(f.name, name)
824             self.assertEqual(f.content, content)
825         self.assertEqual(msg.content, c)
826         self.compareMessages(self._get_mail(),
827 '''FROM: roundup-admin@your.tracker.email.domain.example
828 TO: chef@bork.bork.bork, richard@test.test
829 Content-Type: multipart/mixed; boundary="utf-8"
830 Subject: [issue1] Testing...
831 To: chef@bork.bork.bork, richard@test.test
832 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
833 Reply-To: Roundup issue tracker
834  <issue_tracker@your.tracker.email.domain.example>
835 MIME-Version: 1.0
836 Message-Id: <followup_dummy_id>
837 In-Reply-To: <dummy_test_message_id>
838 X-Roundup-Name: Roundup issue tracker
839 X-Roundup-Loop: hello
840 X-Roundup-Issue-Status: chatting
841 X-Roundup-Issue-Files: unnamed
842 Content-Transfer-Encoding: quoted-printable
845 --utf-8
846 MIME-Version: 1.0
847 Content-Type: text/plain; charset="iso-8859-1"
848 Content-Transfer-Encoding: quoted-printable
851 Contrary, Mary <mary@test.test> added the comment:
853 umlaut =E4=F6=FC=C4=D6=DC=DF
855 ----------
856 status: unread -> chatting
858 _______________________________________________________________________
859 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
860 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
861 _______________________________________________________________________
862 --utf-8
863 Content-Type: text/html
864 MIME-Version: 1.0
865 Content-Transfer-Encoding: base64
866 Content-Disposition: attachment;
867  filename="unnamed"
869 PGh0bWw+dW1sYXV0IMOkw7bDvMOEw5bDnMOfPC9odG1sPgo=
871 --utf-8--
872 ''')
874     def testMultipartRFC822(self):
875         self.doNewIssue()
876         self._handle_mail(self.multipart_msg_rfc822)
877         messages = self.db.issue.get('1', 'messages')
878         messages.sort()
879         msg = self.db.msg.getnode (messages[-1])
880         assert(len(msg.files) == 1)
881         name = "Fwd: Original email subject.eml"
882         for n, id in enumerate (msg.files):
883             f = self.db.file.getnode (id)
884             self.assertEqual(f.name, name)
885         self.assertEqual(msg.content, 'First part: Text')
886         self.compareMessages(self._get_mail(),
887 '''TO: chef@bork.bork.bork, richard@test.test
888 Content-Type: text/plain; charset="utf-8"
889 Subject: [issue1] Testing...
890 To: chef@bork.bork.bork, richard@test.test
891 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
892 Reply-To: Roundup issue tracker
893  <issue_tracker@your.tracker.email.domain.example>
894 MIME-Version: 1.0
895 Message-Id: <followup_dummy_id>
896 In-Reply-To: <dummy_test_message_id>
897 X-Roundup-Name: Roundup issue tracker
898 X-Roundup-Loop: hello
899 X-Roundup-Issue-Status: chatting
900 X-Roundup-Issue-Files: Fwd: Original email subject.eml
901 Content-Transfer-Encoding: quoted-printable
904 --utf-8
905 MIME-Version: 1.0
906 Content-Type: text/plain; charset="utf-8"
907 Content-Transfer-Encoding: quoted-printable
910 Contrary, Mary <mary@test.test> added the comment:
912 First part: Text
914 ----------
915 status: unread -> chatting
917 _______________________________________________________________________
918 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
919 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
920 _______________________________________________________________________
921 --utf-8
922 Content-Type: message/rfc822
923 MIME-Version: 1.0
924 Content-Disposition: attachment;
925  filename="Fwd: Original email subject.eml"
927 Message-Id: <followup_dummy_id_2>
928 In-Reply-To: <dummy_test_message_id_2>
929 MIME-Version: 1.0
930 Subject: Fwd: Original email subject
931 Date: Mon, 23 Aug 2010 08:23:33 +0200
932 Content-Type: multipart/alternative; boundary="090500050101020406060002"
934 This is a multi-part message in MIME format.
935 --090500050101020406060002
936 Content-Type: text/plain; charset=ISO-8859-15; format=flowed
937 Content-Transfer-Encoding: 7bit
939 some text in inner email
940 ========================
942 --090500050101020406060002
943 Content-Type: text/html; charset=ISO-8859-15
944 Content-Transfer-Encoding: 7bit
946 <html>
947 some text in inner email
948 ========================
949 </html>
951 --090500050101020406060002--
953 --utf-8--
954 ''')
956     def testMultipartRFC822Unpack(self):
957         self.doNewIssue()
958         self.db.config.MAILGW_UNPACK_RFC822 = True
959         self._handle_mail(self.multipart_msg_rfc822)
960         messages = self.db.issue.get('1', 'messages')
961         messages.sort()
962         msg = self.db.msg.getnode (messages[-1])
963         self.assertEqual(len(msg.files), 2)
964         t = 'some text in inner email\n========================\n'
965         content = {0 : t, 1 : '<html>\n' + t + '</html>\n'}
966         for n, id in enumerate (msg.files):
967             f = self.db.file.getnode (id)
968             self.assertEqual(f.name, 'unnamed')
969             if n in content :
970                 self.assertEqual(f.content, content [n])
971         self.assertEqual(msg.content, 'First part: Text')
973     def testSimpleFollowup(self):
974         self.doNewIssue()
975         self._handle_mail('''Content-Type: text/plain;
976   charset="iso-8859-1"
977 From: mary <mary@test.test>
978 To: issue_tracker@your.tracker.email.domain.example
979 Message-Id: <followup_dummy_id>
980 In-Reply-To: <dummy_test_message_id>
981 Subject: [issue1] Testing...
983 This is a second followup
984 ''')
985         self.compareMessages(self._get_mail(),
986 '''FROM: roundup-admin@your.tracker.email.domain.example
987 TO: chef@bork.bork.bork, richard@test.test
988 Content-Type: text/plain; charset="utf-8"
989 Subject: [issue1] Testing...
990 To: chef@bork.bork.bork, richard@test.test
991 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
992 Reply-To: Roundup issue tracker
993  <issue_tracker@your.tracker.email.domain.example>
994 MIME-Version: 1.0
995 Message-Id: <followup_dummy_id>
996 In-Reply-To: <dummy_test_message_id>
997 X-Roundup-Name: Roundup issue tracker
998 X-Roundup-Loop: hello
999 X-Roundup-Issue-Status: chatting
1000 Content-Transfer-Encoding: quoted-printable
1003 Contrary, Mary <mary@test.test> added the comment:
1005 This is a second followup
1007 ----------
1008 status: unread -> chatting
1010 _______________________________________________________________________
1011 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1012 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1013 _______________________________________________________________________
1014 ''')
1016     def testFollowup(self):
1017         self.doNewIssue()
1019         self._handle_mail('''Content-Type: text/plain;
1020   charset="iso-8859-1"
1021 From: richard <richard@test.test>
1022 To: issue_tracker@your.tracker.email.domain.example
1023 Message-Id: <followup_dummy_id>
1024 In-Reply-To: <dummy_test_message_id>
1025 Subject: [issue1] Testing... [assignedto=mary; nosy=+john]
1027 This is a followup
1028 ''')
1029         l = self.db.issue.get('1', 'nosy')
1030         l.sort()
1031         self.assertEqual(l, [self.chef_id, self.richard_id, self.mary_id,
1032             self.john_id])
1034         self.compareMessages(self._get_mail(),
1035 '''FROM: roundup-admin@your.tracker.email.domain.example
1036 TO: chef@bork.bork.bork, john@test.test, mary@test.test
1037 Content-Type: text/plain; charset="utf-8"
1038 Subject: [issue1] Testing...
1039 To: chef@bork.bork.bork, john@test.test, mary@test.test
1040 From: richard <issue_tracker@your.tracker.email.domain.example>
1041 Reply-To: Roundup issue tracker
1042  <issue_tracker@your.tracker.email.domain.example>
1043 MIME-Version: 1.0
1044 Message-Id: <followup_dummy_id>
1045 In-Reply-To: <dummy_test_message_id>
1046 X-Roundup-Name: Roundup issue tracker
1047 X-Roundup-Loop: hello
1048 X-Roundup-Issue-Status: chatting
1049 Content-Transfer-Encoding: quoted-printable
1052 richard <richard@test.test> added the comment:
1054 This is a followup
1056 ----------
1057 assignedto:  -> mary
1058 nosy: +john, mary
1059 status: unread -> chatting
1061 _______________________________________________________________________
1062 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1063 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1064 _______________________________________________________________________
1065 ''')
1067     def testFollowupNoSubjectChange(self):
1068         self.db.config.MAILGW_SUBJECT_UPDATES_TITLE = 'no'
1069         self.doNewIssue()
1071         self._handle_mail('''Content-Type: text/plain;
1072   charset="iso-8859-1"
1073 From: richard <richard@test.test>
1074 To: issue_tracker@your.tracker.email.domain.example
1075 Message-Id: <followup_dummy_id>
1076 In-Reply-To: <dummy_test_message_id>
1077 Subject: [issue1] Wrzlbrmft... [assignedto=mary; nosy=+john]
1079 This is a followup
1080 ''')
1081         l = self.db.issue.get('1', 'nosy')
1082         l.sort()
1083         self.assertEqual(l, [self.chef_id, self.richard_id, self.mary_id,
1084             self.john_id])
1086         self.compareMessages(self._get_mail(),
1087 '''FROM: roundup-admin@your.tracker.email.domain.example
1088 TO: chef@bork.bork.bork, john@test.test, mary@test.test
1089 Content-Type: text/plain; charset="utf-8"
1090 Subject: [issue1] Testing...
1091 To: chef@bork.bork.bork, john@test.test, mary@test.test
1092 From: richard <issue_tracker@your.tracker.email.domain.example>
1093 Reply-To: Roundup issue tracker
1094  <issue_tracker@your.tracker.email.domain.example>
1095 MIME-Version: 1.0
1096 Message-Id: <followup_dummy_id>
1097 In-Reply-To: <dummy_test_message_id>
1098 X-Roundup-Name: Roundup issue tracker
1099 X-Roundup-Loop: hello
1100 X-Roundup-Issue-Status: chatting
1101 Content-Transfer-Encoding: quoted-printable
1104 richard <richard@test.test> added the comment:
1106 This is a followup
1108 ----------
1109 assignedto:  -> mary
1110 nosy: +john, mary
1111 status: unread -> chatting
1113 _______________________________________________________________________
1114 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1115 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1116 _______________________________________________________________________
1117 ''')
1118         self.assertEqual(self.db.issue.get('1','title'), 'Testing...')
1120     def testFollowupExplicitSubjectChange(self):
1121         self.doNewIssue()
1123         self._handle_mail('''Content-Type: text/plain;
1124   charset="iso-8859-1"
1125 From: richard <richard@test.test>
1126 To: issue_tracker@your.tracker.email.domain.example
1127 Message-Id: <followup_dummy_id>
1128 In-Reply-To: <dummy_test_message_id>
1129 Subject: [issue1] Wrzlbrmft... [assignedto=mary; nosy=+john; title=new title]
1131 This is a followup
1132 ''')
1133         l = self.db.issue.get('1', 'nosy')
1134         l.sort()
1135         self.assertEqual(l, [self.chef_id, self.richard_id, self.mary_id,
1136             self.john_id])
1138         self.compareMessages(self._get_mail(),
1139 '''FROM: roundup-admin@your.tracker.email.domain.example
1140 TO: chef@bork.bork.bork, john@test.test, mary@test.test
1141 Content-Type: text/plain; charset="utf-8"
1142 Subject: [issue1] new title
1143 To: chef@bork.bork.bork, john@test.test, mary@test.test
1144 From: richard <issue_tracker@your.tracker.email.domain.example>
1145 Reply-To: Roundup issue tracker
1146  <issue_tracker@your.tracker.email.domain.example>
1147 MIME-Version: 1.0
1148 Message-Id: <followup_dummy_id>
1149 In-Reply-To: <dummy_test_message_id>
1150 X-Roundup-Name: Roundup issue tracker
1151 X-Roundup-Loop: hello
1152 X-Roundup-Issue-Status: chatting
1153 Content-Transfer-Encoding: quoted-printable
1156 richard <richard@test.test> added the comment:
1158 This is a followup
1160 ----------
1161 assignedto:  -> mary
1162 nosy: +john, mary
1163 status: unread -> chatting
1164 title: Testing... -> new title
1166 _______________________________________________________________________
1167 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1168 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1169 _______________________________________________________________________
1170 ''')
1172     def testNosyGeneration(self):
1173         self.db.issue.create(title='test')
1175         # create a nosy message
1176         msg = self.db.msg.create(content='This is a test',
1177             author=self.richard_id, messageid='<dummy_test_message_id>')
1178         self.db.journaltag = 'richard'
1179         l = self.db.issue.create(title='test', messages=[msg],
1180             nosy=[self.chef_id, self.mary_id, self.john_id])
1182         self.compareMessages(self._get_mail(),
1183 '''FROM: roundup-admin@your.tracker.email.domain.example
1184 TO: chef@bork.bork.bork, john@test.test, mary@test.test
1185 Content-Type: text/plain; charset="utf-8"
1186 Subject: [issue2] test
1187 To: chef@bork.bork.bork, john@test.test, mary@test.test
1188 From: richard <issue_tracker@your.tracker.email.domain.example>
1189 Reply-To: Roundup issue tracker
1190  <issue_tracker@your.tracker.email.domain.example>
1191 MIME-Version: 1.0
1192 Message-Id: <dummy_test_message_id>
1193 X-Roundup-Name: Roundup issue tracker
1194 X-Roundup-Loop: hello
1195 X-Roundup-Issue-Status: unread
1196 Content-Transfer-Encoding: quoted-printable
1199 New submission from richard <richard@test.test>:
1201 This is a test
1203 ----------
1204 messages: 1
1205 nosy: Chef, john, mary, richard
1206 status: unread
1207 title: test
1209 _______________________________________________________________________
1210 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1211 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue2>
1212 _______________________________________________________________________
1213 ''')
1215     def testPropertyChangeOnly(self):
1216         self.doNewIssue()
1217         oldvalues = self.db.getnode('issue', '1').copy()
1218         oldvalues['assignedto'] = None
1219         # reconstruct old behaviour: This would reuse the
1220         # database-handle from the doNewIssue above which has committed
1221         # as user "Chef". So we close and reopen the db as that user.
1222         #self.db.close() actually don't close 'cos this empties memorydb
1223         self.db = self.instance.open('Chef')
1224         self.db.issue.set('1', assignedto=self.chef_id)
1225         self.db.commit()
1226         self.db.issue.nosymessage('1', None, oldvalues)
1228         new_mail = ""
1229         for line in self._get_mail().split("\n"):
1230             if "Message-Id: " in line:
1231                 continue
1232             if "Date: " in line:
1233                 continue
1234             new_mail += line+"\n"
1236         self.compareMessages(new_mail, """
1237 FROM: roundup-admin@your.tracker.email.domain.example
1238 TO: chef@bork.bork.bork, richard@test.test
1239 Content-Type: text/plain; charset="utf-8"
1240 Subject: [issue1] Testing...
1241 To: chef@bork.bork.bork, richard@test.test
1242 From: "Bork, Chef" <issue_tracker@your.tracker.email.domain.example>
1243 X-Roundup-Name: Roundup issue tracker
1244 X-Roundup-Loop: hello
1245 X-Roundup-Issue-Status: unread
1246 X-Roundup-Version: 1.3.3
1247 In-Reply-To: <dummy_test_message_id>
1248 MIME-Version: 1.0
1249 Reply-To: Roundup issue tracker
1250  <issue_tracker@your.tracker.email.domain.example>
1251 Content-Transfer-Encoding: quoted-printable
1254 Change by Bork, Chef <chef@bork.bork.bork>:
1257 ----------
1258 assignedto:  -> Chef
1260 _______________________________________________________________________
1261 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1262 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1263 _______________________________________________________________________
1264 """)
1267     #
1268     # FOLLOWUP TITLE MATCH
1269     #
1270     def testFollowupTitleMatch(self):
1271         self.doNewIssue()
1272         self._handle_mail('''Content-Type: text/plain;
1273   charset="iso-8859-1"
1274 From: richard <richard@test.test>
1275 To: issue_tracker@your.tracker.email.domain.example
1276 Message-Id: <followup_dummy_id>
1277 Subject: Re: Testing... [assignedto=mary; nosy=+john]
1279 This is a followup
1280 ''')
1281         self.compareMessages(self._get_mail(),
1282 '''FROM: roundup-admin@your.tracker.email.domain.example
1283 TO: chef@bork.bork.bork, john@test.test, mary@test.test
1284 Content-Type: text/plain; charset="utf-8"
1285 Subject: [issue1] Testing...
1286 To: chef@bork.bork.bork, john@test.test, mary@test.test
1287 From: richard <issue_tracker@your.tracker.email.domain.example>
1288 Reply-To: Roundup issue tracker
1289  <issue_tracker@your.tracker.email.domain.example>
1290 MIME-Version: 1.0
1291 Message-Id: <followup_dummy_id>
1292 In-Reply-To: <dummy_test_message_id>
1293 X-Roundup-Name: Roundup issue tracker
1294 X-Roundup-Loop: hello
1295 X-Roundup-Issue-Status: chatting
1296 Content-Transfer-Encoding: quoted-printable
1299 richard <richard@test.test> added the comment:
1301 This is a followup
1303 ----------
1304 assignedto:  -> mary
1305 nosy: +john, mary
1306 status: unread -> chatting
1308 _______________________________________________________________________
1309 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1310 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1311 _______________________________________________________________________
1312 ''')
1314     def testFollowupTitleMatchMultiRe(self):
1315         nodeid1 = self.doNewIssue()
1316         nodeid2 = self._handle_mail('''Content-Type: text/plain;
1317   charset="iso-8859-1"
1318 From: richard <richard@test.test>
1319 To: issue_tracker@your.tracker.email.domain.example
1320 Message-Id: <followup_dummy_id>
1321 Subject: Re: Testing... [assignedto=mary; nosy=+john]
1323 This is a followup
1324 ''')
1326         nodeid3 = self._handle_mail('''Content-Type: text/plain;
1327   charset="iso-8859-1"
1328 From: richard <richard@test.test>
1329 To: issue_tracker@your.tracker.email.domain.example
1330 Message-Id: <followup2_dummy_id>
1331 Subject: Ang: Re: Testing...
1333 This is a followup
1334 ''')
1335         self.assertEqual(nodeid1, nodeid2)
1336         self.assertEqual(nodeid1, nodeid3)
1338     def testFollowupTitleMatchNever(self):
1339         nodeid = self.doNewIssue()
1340         self.db.config.MAILGW_SUBJECT_CONTENT_MATCH = 'never'
1341         self.assertNotEqual(self._handle_mail('''Content-Type: text/plain;
1342   charset="iso-8859-1"
1343 From: richard <richard@test.test>
1344 To: issue_tracker@your.tracker.email.domain.example
1345 Message-Id: <followup_dummy_id>
1346 Subject: Re: Testing...
1348 This is a followup
1349 '''), nodeid)
1351     def testFollowupTitleMatchNeverInterval(self):
1352         nodeid = self.doNewIssue()
1353         # force failure of the interval
1354         time.sleep(2)
1355         self.db.config.MAILGW_SUBJECT_CONTENT_MATCH = 'creation 00:00:01'
1356         self.assertNotEqual(self._handle_mail('''Content-Type: text/plain;
1357   charset="iso-8859-1"
1358 From: richard <richard@test.test>
1359 To: issue_tracker@your.tracker.email.domain.example
1360 Message-Id: <followup_dummy_id>
1361 Subject: Re: Testing...
1363 This is a followup
1364 '''), nodeid)
1367     def testFollowupTitleMatchInterval(self):
1368         nodeid = self.doNewIssue()
1369         self.db.config.MAILGW_SUBJECT_CONTENT_MATCH = 'creation +1d'
1370         self.assertEqual(self._handle_mail('''Content-Type: text/plain;
1371   charset="iso-8859-1"
1372 From: richard <richard@test.test>
1373 To: issue_tracker@your.tracker.email.domain.example
1374 Message-Id: <followup_dummy_id>
1375 Subject: Re: Testing...
1377 This is a followup
1378 '''), nodeid)
1381     def testFollowupNosyAuthor(self):
1382         self.doNewIssue()
1383         self.db.config.ADD_AUTHOR_TO_NOSY = 'yes'
1384         self._handle_mail('''Content-Type: text/plain;
1385   charset="iso-8859-1"
1386 From: john@test.test
1387 To: issue_tracker@your.tracker.email.domain.example
1388 Message-Id: <followup_dummy_id>
1389 In-Reply-To: <dummy_test_message_id>
1390 Subject: [issue1] Testing...
1392 This is a followup
1393 ''')
1395         self.compareMessages(self._get_mail(),
1396 '''FROM: roundup-admin@your.tracker.email.domain.example
1397 TO: chef@bork.bork.bork, richard@test.test
1398 Content-Type: text/plain; charset="utf-8"
1399 Subject: [issue1] Testing...
1400 To: chef@bork.bork.bork, richard@test.test
1401 From: John Doe <issue_tracker@your.tracker.email.domain.example>
1402 Reply-To: Roundup issue tracker
1403  <issue_tracker@your.tracker.email.domain.example>
1404 MIME-Version: 1.0
1405 Message-Id: <followup_dummy_id>
1406 In-Reply-To: <dummy_test_message_id>
1407 X-Roundup-Name: Roundup issue tracker
1408 X-Roundup-Loop: hello
1409 X-Roundup-Issue-Status: chatting
1410 Content-Transfer-Encoding: quoted-printable
1413 John Doe <john@test.test> added the comment:
1415 This is a followup
1417 ----------
1418 nosy: +john
1419 status: unread -> chatting
1421 _______________________________________________________________________
1422 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1423 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1424 _______________________________________________________________________
1426 ''')
1428     def testFollowupNosyRecipients(self):
1429         self.doNewIssue()
1430         self.db.config.ADD_RECIPIENTS_TO_NOSY = 'yes'
1431         self._handle_mail('''Content-Type: text/plain;
1432   charset="iso-8859-1"
1433 From: richard@test.test
1434 To: issue_tracker@your.tracker.email.domain.example
1435 Cc: john@test.test
1436 Message-Id: <followup_dummy_id>
1437 In-Reply-To: <dummy_test_message_id>
1438 Subject: [issue1] Testing...
1440 This is a followup
1441 ''')
1442         self.compareMessages(self._get_mail(),
1443 '''FROM: roundup-admin@your.tracker.email.domain.example
1444 TO: chef@bork.bork.bork
1445 Content-Type: text/plain; charset="utf-8"
1446 Subject: [issue1] Testing...
1447 To: chef@bork.bork.bork
1448 From: richard <issue_tracker@your.tracker.email.domain.example>
1449 Reply-To: Roundup issue tracker
1450  <issue_tracker@your.tracker.email.domain.example>
1451 MIME-Version: 1.0
1452 Message-Id: <followup_dummy_id>
1453 In-Reply-To: <dummy_test_message_id>
1454 X-Roundup-Name: Roundup issue tracker
1455 X-Roundup-Loop: hello
1456 X-Roundup-Issue-Status: chatting
1457 Content-Transfer-Encoding: quoted-printable
1460 richard <richard@test.test> added the comment:
1462 This is a followup
1464 ----------
1465 nosy: +john
1466 status: unread -> chatting
1468 _______________________________________________________________________
1469 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1470 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1471 _______________________________________________________________________
1473 ''')
1475     def testFollowupNosyAuthorAndCopy(self):
1476         self.doNewIssue()
1477         self.db.config.ADD_AUTHOR_TO_NOSY = 'yes'
1478         self.db.config.MESSAGES_TO_AUTHOR = 'yes'
1479         self._handle_mail('''Content-Type: text/plain;
1480   charset="iso-8859-1"
1481 From: john@test.test
1482 To: issue_tracker@your.tracker.email.domain.example
1483 Message-Id: <followup_dummy_id>
1484 In-Reply-To: <dummy_test_message_id>
1485 Subject: [issue1] Testing...
1487 This is a followup
1488 ''')
1489         self.compareMessages(self._get_mail(),
1490 '''FROM: roundup-admin@your.tracker.email.domain.example
1491 TO: chef@bork.bork.bork, john@test.test, richard@test.test
1492 Content-Type: text/plain; charset="utf-8"
1493 Subject: [issue1] Testing...
1494 To: chef@bork.bork.bork, john@test.test, richard@test.test
1495 From: John Doe <issue_tracker@your.tracker.email.domain.example>
1496 Reply-To: Roundup issue tracker
1497  <issue_tracker@your.tracker.email.domain.example>
1498 MIME-Version: 1.0
1499 Message-Id: <followup_dummy_id>
1500 In-Reply-To: <dummy_test_message_id>
1501 X-Roundup-Name: Roundup issue tracker
1502 X-Roundup-Loop: hello
1503 X-Roundup-Issue-Status: chatting
1504 Content-Transfer-Encoding: quoted-printable
1507 John Doe <john@test.test> added the comment:
1509 This is a followup
1511 ----------
1512 nosy: +john
1513 status: unread -> chatting
1515 _______________________________________________________________________
1516 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1517 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1518 _______________________________________________________________________
1520 ''')
1522     def testFollowupNoNosyAuthor(self):
1523         self.doNewIssue()
1524         self.instance.config.ADD_AUTHOR_TO_NOSY = 'no'
1525         self._handle_mail('''Content-Type: text/plain;
1526   charset="iso-8859-1"
1527 From: john@test.test
1528 To: issue_tracker@your.tracker.email.domain.example
1529 Message-Id: <followup_dummy_id>
1530 In-Reply-To: <dummy_test_message_id>
1531 Subject: [issue1] Testing...
1533 This is a followup
1534 ''')
1535         self.compareMessages(self._get_mail(),
1536 '''FROM: roundup-admin@your.tracker.email.domain.example
1537 TO: chef@bork.bork.bork, richard@test.test
1538 Content-Type: text/plain; charset="utf-8"
1539 Subject: [issue1] Testing...
1540 To: chef@bork.bork.bork, richard@test.test
1541 From: John Doe <issue_tracker@your.tracker.email.domain.example>
1542 Reply-To: Roundup issue tracker
1543  <issue_tracker@your.tracker.email.domain.example>
1544 MIME-Version: 1.0
1545 Message-Id: <followup_dummy_id>
1546 In-Reply-To: <dummy_test_message_id>
1547 X-Roundup-Name: Roundup issue tracker
1548 X-Roundup-Loop: hello
1549 X-Roundup-Issue-Status: chatting
1550 Content-Transfer-Encoding: quoted-printable
1553 John Doe <john@test.test> added the comment:
1555 This is a followup
1557 ----------
1558 status: unread -> chatting
1560 _______________________________________________________________________
1561 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1562 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1563 _______________________________________________________________________
1565 ''')
1567     def testFollowupNoNosyRecipients(self):
1568         self.doNewIssue()
1569         self.instance.config.ADD_RECIPIENTS_TO_NOSY = 'no'
1570         self._handle_mail('''Content-Type: text/plain;
1571   charset="iso-8859-1"
1572 From: richard@test.test
1573 To: issue_tracker@your.tracker.email.domain.example
1574 Cc: john@test.test
1575 Message-Id: <followup_dummy_id>
1576 In-Reply-To: <dummy_test_message_id>
1577 Subject: [issue1] Testing...
1579 This is a followup
1580 ''')
1581         self.compareMessages(self._get_mail(),
1582 '''FROM: roundup-admin@your.tracker.email.domain.example
1583 TO: chef@bork.bork.bork
1584 Content-Type: text/plain; charset="utf-8"
1585 Subject: [issue1] Testing...
1586 To: chef@bork.bork.bork
1587 From: richard <issue_tracker@your.tracker.email.domain.example>
1588 Reply-To: Roundup issue tracker
1589  <issue_tracker@your.tracker.email.domain.example>
1590 MIME-Version: 1.0
1591 Message-Id: <followup_dummy_id>
1592 In-Reply-To: <dummy_test_message_id>
1593 X-Roundup-Name: Roundup issue tracker
1594 X-Roundup-Loop: hello
1595 X-Roundup-Issue-Status: chatting
1596 Content-Transfer-Encoding: quoted-printable
1599 richard <richard@test.test> added the comment:
1601 This is a followup
1603 ----------
1604 status: unread -> chatting
1606 _______________________________________________________________________
1607 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1608 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1609 _______________________________________________________________________
1611 ''')
1613     def testFollowupEmptyMessage(self):
1614         self.doNewIssue()
1616         self._handle_mail('''Content-Type: text/plain;
1617   charset="iso-8859-1"
1618 From: richard <richard@test.test>
1619 To: issue_tracker@your.tracker.email.domain.example
1620 Message-Id: <followup_dummy_id>
1621 In-Reply-To: <dummy_test_message_id>
1622 Subject: [issue1] Testing... [assignedto=mary; nosy=+john]
1624 ''')
1625         l = self.db.issue.get('1', 'nosy')
1626         l.sort()
1627         self.assertEqual(l, [self.chef_id, self.richard_id, self.mary_id,
1628             self.john_id])
1630         # should be no file created (ie. no message)
1631         assert not os.path.exists(SENDMAILDEBUG)
1633     def testFollowupEmptyMessageNoSubject(self):
1634         self.doNewIssue()
1636         self._handle_mail('''Content-Type: text/plain;
1637   charset="iso-8859-1"
1638 From: richard <richard@test.test>
1639 To: issue_tracker@your.tracker.email.domain.example
1640 Message-Id: <followup_dummy_id>
1641 In-Reply-To: <dummy_test_message_id>
1642 Subject: [issue1] [assignedto=mary; nosy=+john]
1644 ''')
1645         l = self.db.issue.get('1', 'nosy')
1646         l.sort()
1647         self.assertEqual(l, [self.chef_id, self.richard_id, self.mary_id,
1648             self.john_id])
1650         # should be no file created (ie. no message)
1651         assert not os.path.exists(SENDMAILDEBUG)
1653     def testNosyRemove(self):
1654         self.doNewIssue()
1656         self._handle_mail('''Content-Type: text/plain;
1657   charset="iso-8859-1"
1658 From: richard <richard@test.test>
1659 To: issue_tracker@your.tracker.email.domain.example
1660 Message-Id: <followup_dummy_id>
1661 In-Reply-To: <dummy_test_message_id>
1662 Subject: [issue1] Testing... [nosy=-richard]
1664 ''')
1665         l = self.db.issue.get('1', 'nosy')
1666         l.sort()
1667         self.assertEqual(l, [self.chef_id])
1669         # NO NOSY MESSAGE SHOULD BE SENT!
1670         assert not os.path.exists(SENDMAILDEBUG)
1672     def testNewUserAuthor(self):
1673         self.db.commit()
1674         l = self.db.user.list()
1675         l.sort()
1676         message = '''Content-Type: text/plain;
1677   charset="iso-8859-1"
1678 From: fubar <fubar@bork.bork.bork>
1679 To: issue_tracker@your.tracker.email.domain.example
1680 Message-Id: <dummy_test_message_id>
1681 Subject: [issue] Testing...
1683 This is a test submission of a new issue.
1684 '''
1685         self.db.security.role['anonymous'].permissions=[]
1686         anonid = self.db.user.lookup('anonymous')
1687         self.db.user.set(anonid, roles='Anonymous')
1688         try:
1689             self._handle_mail(message)
1690         except Unauthorized, value:
1691             body_diff = self.compareMessages(str(value), """
1692 You are not a registered user.
1694 Unknown address: fubar@bork.bork.bork
1695 """)
1696             assert not body_diff, body_diff
1697         else:
1698             raise AssertionError, "Unathorized not raised when handling mail"
1700         # Add Web Access role to anonymous, and try again to make sure
1701         # we get a "please register at:" message this time.
1702         p = [
1703             self.db.security.getPermission('Register', 'user'),
1704             self.db.security.getPermission('Web Access', None),
1705         ]
1706         self.db.security.role['anonymous'].permissions=p
1707         try:
1708             self._handle_mail(message)
1709         except Unauthorized, value:
1710             body_diff = self.compareMessages(str(value), """
1711 You are not a registered user. Please register at:
1713 http://tracker.example/cgi-bin/roundup.cgi/bugs/user?template=register
1715 ...before sending mail to the tracker.
1717 Unknown address: fubar@bork.bork.bork
1718 """)
1719             assert not body_diff, body_diff
1720         else:
1721             raise AssertionError, "Unathorized not raised when handling mail"
1723         # Make sure list of users is the same as before.
1724         m = self.db.user.list()
1725         m.sort()
1726         self.assertEqual(l, m)
1728         # now with the permission
1729         p = [
1730             self.db.security.getPermission('Register', 'user'),
1731             self.db.security.getPermission('Email Access', None),
1732         ]
1733         self.db.security.role['anonymous'].permissions=p
1734         self._handle_mail(message)
1735         m = self.db.user.list()
1736         m.sort()
1737         self.assertNotEqual(l, m)
1739     def testNewUserAuthorEncodedName(self):
1740         l = set(self.db.user.list())
1741         # From: name has Euro symbol in it
1742         message = '''Content-Type: text/plain;
1743   charset="iso-8859-1"
1744 From: =?utf8?b?SOKCrGxsbw==?= <fubar@bork.bork.bork>
1745 To: issue_tracker@your.tracker.email.domain.example
1746 Message-Id: <dummy_test_message_id>
1747 Subject: [issue] Testing...
1749 This is a test submission of a new issue.
1750 '''
1751         p = [
1752             self.db.security.getPermission('Register', 'user'),
1753             self.db.security.getPermission('Email Access', None),
1754             self.db.security.getPermission('Create', 'issue'),
1755             self.db.security.getPermission('Create', 'msg'),
1756         ]
1757         self.db.security.role['anonymous'].permissions = p
1758         self._handle_mail(message)
1759         m = set(self.db.user.list())
1760         new = list(m - l)[0]
1761         name = self.db.user.get(new, 'realname')
1762         self.assertEquals(name, 'H€llo')
1764     def testUnknownUser(self):
1765         l = set(self.db.user.list())
1766         message = '''Content-Type: text/plain;
1767   charset="iso-8859-1"
1768 From: Nonexisting User <nonexisting@bork.bork.bork>
1769 To: issue_tracker@your.tracker.email.domain.example
1770 Message-Id: <dummy_test_message_id>
1771 Subject: [issue] Testing nonexisting user...
1773 This is a test submission of a new issue.
1774 '''
1775         handler = self._create_mailgw(message)
1776         # we want a bounce message:
1777         handler.trapExceptions = 1
1778         ret = handler.main(StringIO(message))
1779         self.compareMessages(self._get_mail(),
1780 '''FROM: Roundup issue tracker <roundup-admin@your.tracker.email.domain.example>
1781 TO: nonexisting@bork.bork.bork
1782 From nobody Tue Jul 14 12:04:11 2009
1783 Content-Type: multipart/mixed; boundary="===============0639262320=="
1784 MIME-Version: 1.0
1785 Subject: Failed issue tracker submission
1786 To: nonexisting@bork.bork.bork
1787 From: Roundup issue tracker <roundup-admin@your.tracker.email.domain.example>
1788 Date: Tue, 14 Jul 2009 12:04:11 +0000
1789 Precedence: bulk
1790 X-Roundup-Name: Roundup issue tracker
1791 X-Roundup-Loop: hello
1792 X-Roundup-Version: 1.4.8
1793 MIME-Version: 1.0
1795 --===============0639262320==
1796 Content-Type: text/plain; charset="us-ascii"
1797 MIME-Version: 1.0
1798 Content-Transfer-Encoding: 7bit
1802 You are not a registered user. Please register at:
1804 http://tracker.example/cgi-bin/roundup.cgi/bugs/user?template=register
1806 ...before sending mail to the tracker.
1808 Unknown address: nonexisting@bork.bork.bork
1810 --===============0639262320==
1811 Content-Type: text/plain; charset="us-ascii"
1812 MIME-Version: 1.0
1813 Content-Transfer-Encoding: 7bit
1815 Content-Type: text/plain;
1816   charset="iso-8859-1"
1817 From: Nonexisting User <nonexisting@bork.bork.bork>
1818 To: issue_tracker@your.tracker.email.domain.example
1819 Message-Id: <dummy_test_message_id>
1820 Subject: [issue] Testing nonexisting user...
1822 This is a test submission of a new issue.
1824 --===============0639262320==--
1825 ''')
1827     def testEnc01(self):
1828         self.db.user.set(self.mary_id,
1829             realname='\xe4\xf6\xfc\xc4\xd6\xdc\xdf, Mary'.decode
1830             ('latin-1').encode('utf-8'))
1831         self.doNewIssue()
1832         self._handle_mail('''Content-Type: text/plain;
1833   charset="iso-8859-1"
1834 From: mary <mary@test.test>
1835 To: issue_tracker@your.tracker.email.domain.example
1836 Message-Id: <followup_dummy_id>
1837 In-Reply-To: <dummy_test_message_id>
1838 Subject: [issue1] Testing...
1839 Content-Type: text/plain;
1840         charset="iso-8859-1"
1841 Content-Transfer-Encoding: quoted-printable
1843 A message with encoding (encoded oe =F6)
1845 ''')
1846         self.compareMessages(self._get_mail(),
1847 '''FROM: roundup-admin@your.tracker.email.domain.example
1848 TO: chef@bork.bork.bork, richard@test.test
1849 Content-Type: text/plain; charset="utf-8"
1850 Subject: [issue1] Testing...
1851 To: chef@bork.bork.bork, richard@test.test
1852 From: =?utf-8?b?w6TDtsO8w4TDlsOcw58sIE1hcnk=?=
1853  <issue_tracker@your.tracker.email.domain.example>
1854 Reply-To: Roundup issue tracker
1855  <issue_tracker@your.tracker.email.domain.example>
1856 MIME-Version: 1.0
1857 Message-Id: <followup_dummy_id>
1858 In-Reply-To: <dummy_test_message_id>
1859 X-Roundup-Name: Roundup issue tracker
1860 X-Roundup-Loop: hello
1861 X-Roundup-Issue-Status: chatting
1862 Content-Transfer-Encoding: quoted-printable
1865 =C3=A4=C3=B6=C3=BC=C3=84=C3=96=C3=9C=C3=9F, Mary <mary@test.test> added the=
1866  comment:
1868 A message with encoding (encoded oe =C3=B6)
1870 ----------
1871 status: unread -> chatting
1873 _______________________________________________________________________
1874 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1875 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1876 _______________________________________________________________________
1877 ''')
1879     def testEncNonUTF8(self):
1880         self.doNewIssue()
1881         self.instance.config.EMAIL_CHARSET = 'iso-8859-1'
1882         self._handle_mail('''Content-Type: text/plain;
1883   charset="iso-8859-1"
1884 From: mary <mary@test.test>
1885 To: issue_tracker@your.tracker.email.domain.example
1886 Message-Id: <followup_dummy_id>
1887 In-Reply-To: <dummy_test_message_id>
1888 Subject: [issue1] Testing...
1889 Content-Type: text/plain;
1890         charset="iso-8859-1"
1891 Content-Transfer-Encoding: quoted-printable
1893 A message with encoding (encoded oe =F6)
1895 ''')
1896         self.compareMessages(self._get_mail(),
1897 '''FROM: roundup-admin@your.tracker.email.domain.example
1898 TO: chef@bork.bork.bork, richard@test.test
1899 Content-Type: text/plain; charset="iso-8859-1"
1900 Subject: [issue1] Testing...
1901 To: chef@bork.bork.bork, richard@test.test
1902 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
1903 Reply-To: Roundup issue tracker
1904  <issue_tracker@your.tracker.email.domain.example>
1905 MIME-Version: 1.0
1906 Message-Id: <followup_dummy_id>
1907 In-Reply-To: <dummy_test_message_id>
1908 X-Roundup-Name: Roundup issue tracker
1909 X-Roundup-Loop: hello
1910 X-Roundup-Issue-Status: chatting
1911 Content-Transfer-Encoding: quoted-printable
1914 Contrary, Mary <mary@test.test> added the comment:
1916 A message with encoding (encoded oe =F6)
1918 ----------
1919 status: unread -> chatting
1921 _______________________________________________________________________
1922 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1923 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1924 _______________________________________________________________________
1925 ''')
1928     def testMultipartEnc01(self):
1929         self.doNewIssue()
1930         self._handle_mail('''Content-Type: text/plain;
1931   charset="iso-8859-1"
1932 From: mary <mary@test.test>
1933 To: issue_tracker@your.tracker.email.domain.example
1934 Message-Id: <followup_dummy_id>
1935 In-Reply-To: <dummy_test_message_id>
1936 Subject: [issue1] Testing...
1937 Content-Type: multipart/mixed;
1938         boundary="----_=_NextPart_000_01"
1940 This message is in MIME format. Since your mail reader does not understand
1941 this format, some or all of this message may not be legible.
1943 ------_=_NextPart_000_01
1944 Content-Type: text/plain;
1945         charset="iso-8859-1"
1946 Content-Transfer-Encoding: quoted-printable
1948 A message with first part encoded (encoded oe =F6)
1950 ''')
1951         self.compareMessages(self._get_mail(),
1952 '''FROM: roundup-admin@your.tracker.email.domain.example
1953 TO: chef@bork.bork.bork, richard@test.test
1954 Content-Type: text/plain; charset="utf-8"
1955 Subject: [issue1] Testing...
1956 To: chef@bork.bork.bork, richard@test.test
1957 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
1958 Reply-To: Roundup issue tracker
1959  <issue_tracker@your.tracker.email.domain.example>
1960 MIME-Version: 1.0
1961 Message-Id: <followup_dummy_id>
1962 In-Reply-To: <dummy_test_message_id>
1963 X-Roundup-Name: Roundup issue tracker
1964 X-Roundup-Loop: hello
1965 X-Roundup-Issue-Status: chatting
1966 Content-Transfer-Encoding: quoted-printable
1969 Contrary, Mary <mary@test.test> added the comment:
1971 A message with first part encoded (encoded oe =C3=B6)
1973 ----------
1974 status: unread -> chatting
1976 _______________________________________________________________________
1977 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1978 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1979 _______________________________________________________________________
1980 ''')
1982     def testContentDisposition(self):
1983         self.doNewIssue()
1984         self._handle_mail('''Content-Type: text/plain;
1985   charset="iso-8859-1"
1986 From: mary <mary@test.test>
1987 To: issue_tracker@your.tracker.email.domain.example
1988 Message-Id: <followup_dummy_id>
1989 In-Reply-To: <dummy_test_message_id>
1990 Subject: [issue1] Testing...
1991 Content-Type: multipart/mixed; boundary="bCsyhTFzCvuiizWE"
1992 Content-Disposition: inline
1995 --bCsyhTFzCvuiizWE
1996 Content-Type: text/plain; charset=us-ascii
1997 Content-Disposition: inline
1999 test attachment binary
2001 --bCsyhTFzCvuiizWE
2002 Content-Type: application/octet-stream
2003 Content-Disposition: attachment; filename="main.dvi"
2004 Content-Transfer-Encoding: base64
2006 SnVzdCBhIHRlc3QgAQo=
2008 --bCsyhTFzCvuiizWE--
2009 ''')
2010         messages = self.db.issue.get('1', 'messages')
2011         messages.sort()
2012         file = self.db.file.getnode (self.db.msg.get(messages[-1], 'files')[0])
2013         self.assertEqual(file.name, 'main.dvi')
2014         self.assertEqual(file.content, 'Just a test \001\n')
2016     def testFollowupStupidQuoting(self):
2017         self.doNewIssue()
2019         self._handle_mail('''Content-Type: text/plain;
2020   charset="iso-8859-1"
2021 From: richard <richard@test.test>
2022 To: issue_tracker@your.tracker.email.domain.example
2023 Message-Id: <followup_dummy_id>
2024 In-Reply-To: <dummy_test_message_id>
2025 Subject: Re: "[issue1] Testing... "
2027 This is a followup
2028 ''')
2029         self.compareMessages(self._get_mail(),
2030 '''FROM: roundup-admin@your.tracker.email.domain.example
2031 TO: chef@bork.bork.bork
2032 Content-Type: text/plain; charset="utf-8"
2033 Subject: [issue1] Testing...
2034 To: chef@bork.bork.bork
2035 From: richard <issue_tracker@your.tracker.email.domain.example>
2036 Reply-To: Roundup issue tracker
2037  <issue_tracker@your.tracker.email.domain.example>
2038 MIME-Version: 1.0
2039 Message-Id: <followup_dummy_id>
2040 In-Reply-To: <dummy_test_message_id>
2041 X-Roundup-Name: Roundup issue tracker
2042 X-Roundup-Loop: hello
2043 X-Roundup-Issue-Status: chatting
2044 Content-Transfer-Encoding: quoted-printable
2047 richard <richard@test.test> added the comment:
2049 This is a followup
2051 ----------
2052 status: unread -> chatting
2054 _______________________________________________________________________
2055 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
2056 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
2057 _______________________________________________________________________
2058 ''')
2060     def testEmailQuoting(self):
2061         self.instance.config.EMAIL_KEEP_QUOTED_TEXT = 'no'
2062         self.innerTestQuoting('''This is a followup
2063 ''')
2065     def testEmailQuotingRemove(self):
2066         self.instance.config.EMAIL_KEEP_QUOTED_TEXT = 'yes'
2067         self.innerTestQuoting('''Blah blah wrote:
2068 > Blah bklaskdfj sdf asdf jlaskdf skj sdkfjl asdf
2069 >  skdjlkjsdfalsdkfjasdlfkj dlfksdfalksd fj
2072 This is a followup
2073 ''')
2075     def innerTestQuoting(self, expect):
2076         nodeid = self.doNewIssue()
2078         messages = self.db.issue.get(nodeid, 'messages')
2080         self._handle_mail('''Content-Type: text/plain;
2081   charset="iso-8859-1"
2082 From: richard <richard@test.test>
2083 To: issue_tracker@your.tracker.email.domain.example
2084 Message-Id: <followup_dummy_id>
2085 In-Reply-To: <dummy_test_message_id>
2086 Subject: Re: [issue1] Testing...
2088 Blah blah wrote:
2089 > Blah bklaskdfj sdf asdf jlaskdf skj sdkfjl asdf
2090 >  skdjlkjsdfalsdkfjasdlfkj dlfksdfalksd fj
2093 This is a followup
2094 ''')
2095         # figure the new message id
2096         newmessages = self.db.issue.get(nodeid, 'messages')
2097         for msg in messages:
2098             newmessages.remove(msg)
2099         messageid = newmessages[0]
2101         self.compareMessages(self.db.msg.get(messageid, 'content'), expect)
2103     def testUserLookup(self):
2104         i = self.db.user.create(username='user1', address='user1@foo.com')
2105         self.assertEqual(uidFromAddress(self.db, ('', 'user1@foo.com'), 0), i)
2106         self.assertEqual(uidFromAddress(self.db, ('', 'USER1@foo.com'), 0), i)
2107         i = self.db.user.create(username='user2', address='USER2@foo.com')
2108         self.assertEqual(uidFromAddress(self.db, ('', 'USER2@foo.com'), 0), i)
2109         self.assertEqual(uidFromAddress(self.db, ('', 'user2@foo.com'), 0), i)
2111     def testUserAlternateLookup(self):
2112         i = self.db.user.create(username='user1', address='user1@foo.com',
2113                                 alternate_addresses='user1@bar.com')
2114         self.assertEqual(uidFromAddress(self.db, ('', 'user1@bar.com'), 0), i)
2115         self.assertEqual(uidFromAddress(self.db, ('', 'USER1@bar.com'), 0), i)
2117     def testUserCreate(self):
2118         i = uidFromAddress(self.db, ('', 'user@foo.com'), 1)
2119         self.assertNotEqual(uidFromAddress(self.db, ('', 'user@bar.com'), 1), i)
2121     def testRFC2822(self):
2122         ascii_header = "[issue243] This is a \"test\" - with 'quotation' marks"
2123         unicode_header = '[issue244] \xd0\xb0\xd0\xbd\xd0\xb4\xd1\x80\xd0\xb5\xd0\xb9'
2124         unicode_encoded = '=?utf-8?q?[issue244]_=D0=B0=D0=BD=D0=B4=D1=80=D0=B5=D0=B9?='
2125         self.assertEqual(rfc2822.encode_header(ascii_header), ascii_header)
2126         self.assertEqual(rfc2822.encode_header(unicode_header), unicode_encoded)
2128     def testRegistrationConfirmation(self):
2129         otk = "Aj4euk4LZSAdwePohj90SME5SpopLETL"
2130         self.db.getOTKManager().set(otk, username='johannes')
2131         self._handle_mail('''Content-Type: text/plain;
2132   charset="iso-8859-1"
2133 From: Chef <chef@bork.bork.bork>
2134 To: issue_tracker@your.tracker.email.domain.example
2135 Cc: richard@test.test
2136 Message-Id: <dummy_test_message_id>
2137 Subject: Re: Complete your registration to Roundup issue tracker
2138  -- key %s
2140 This is a test confirmation of registration.
2141 ''' % otk)
2142         self.db.user.lookup('johannes')
2144     def testFollowupOnNonIssue(self):
2145         self.db.keyword.create(name='Foo')
2146         self._handle_mail('''Content-Type: text/plain;
2147   charset="iso-8859-1"
2148 From: richard <richard@test.test>
2149 To: issue_tracker@your.tracker.email.domain.example
2150 Message-Id: <followup_dummy_id>
2151 In-Reply-To: <dummy_test_message_id>
2152 Subject: [keyword1] Testing... [name=Bar]
2154 ''')
2155         self.assertEqual(self.db.keyword.get('1', 'name'), 'Bar')
2157     def testResentFrom(self):
2158         nodeid = self._handle_mail('''Content-Type: text/plain;
2159   charset="iso-8859-1"
2160 From: Chef <chef@bork.bork.bork>
2161 Resent-From: mary <mary@test.test>
2162 To: issue_tracker@your.tracker.email.domain.example
2163 Cc: richard@test.test
2164 Message-Id: <dummy_test_message_id>
2165 Subject: [issue] Testing...
2167 This is a test submission of a new issue.
2168 ''')
2169         assert not os.path.exists(SENDMAILDEBUG)
2170         l = self.db.issue.get(nodeid, 'nosy')
2171         l.sort()
2172         self.assertEqual(l, [self.richard_id, self.mary_id])
2173         return nodeid
2175     def testDejaVu(self):
2176         self.assertRaises(IgnoreLoop, self._handle_mail,
2177             '''Content-Type: text/plain;
2178   charset="iso-8859-1"
2179 From: Chef <chef@bork.bork.bork>
2180 X-Roundup-Loop: hello
2181 To: issue_tracker@your.tracker.email.domain.example
2182 Cc: richard@test.test
2183 Message-Id: <dummy_test_message_id>
2184 Subject: Re: [issue] Testing...
2186 Hi, I've been mis-configured to loop messages back to myself.
2187 ''')
2189     def testItsBulkStupid(self):
2190         self.assertRaises(IgnoreBulk, self._handle_mail,
2191             '''Content-Type: text/plain;
2192   charset="iso-8859-1"
2193 From: Chef <chef@bork.bork.bork>
2194 Precedence: bulk
2195 To: issue_tracker@your.tracker.email.domain.example
2196 Cc: richard@test.test
2197 Message-Id: <dummy_test_message_id>
2198 Subject: Re: [issue] Testing...
2200 Hi, I'm on holidays, and this is a dumb auto-responder.
2201 ''')
2203     def testAutoReplyEmailsAreIgnored(self):
2204         self.assertRaises(IgnoreBulk, self._handle_mail,
2205             '''Content-Type: text/plain;
2206   charset="iso-8859-1"
2207 From: Chef <chef@bork.bork.bork>
2208 To: issue_tracker@your.tracker.email.domain.example
2209 Cc: richard@test.test
2210 Message-Id: <dummy_test_message_id>
2211 Subject: Re: [issue] Out of office AutoReply: Back next week
2213 Hi, I am back in the office next week
2214 ''')
2216     def testNoSubject(self):
2217         self.assertRaises(MailUsageError, self._handle_mail,
2218             '''Content-Type: text/plain;
2219   charset="iso-8859-1"
2220 From: Chef <chef@bork.bork.bork>
2221 To: issue_tracker@your.tracker.email.domain.example
2222 Cc: richard@test.test
2223 Reply-To: chef@bork.bork.bork
2224 Message-Id: <dummy_test_message_id>
2226 ''')
2228     #
2229     # TEST FOR INVALID DESIGNATOR HANDLING
2230     #
2231     def testInvalidDesignator(self):
2232         self.assertRaises(MailUsageError, self._handle_mail,
2233             '''Content-Type: text/plain;
2234   charset="iso-8859-1"
2235 From: Chef <chef@bork.bork.bork>
2236 To: issue_tracker@your.tracker.email.domain.example
2237 Subject: [frobulated] testing
2238 Cc: richard@test.test
2239 Reply-To: chef@bork.bork.bork
2240 Message-Id: <dummy_test_message_id>
2242 ''')
2243         self.assertRaises(MailUsageError, self._handle_mail,
2244             '''Content-Type: text/plain;
2245   charset="iso-8859-1"
2246 From: Chef <chef@bork.bork.bork>
2247 To: issue_tracker@your.tracker.email.domain.example
2248 Subject: [issue12345] testing
2249 Cc: richard@test.test
2250 Reply-To: chef@bork.bork.bork
2251 Message-Id: <dummy_test_message_id>
2253 ''')
2255     def testInvalidClassLoose(self):
2256         self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'loose'
2257         nodeid = self._handle_mail('''Content-Type: text/plain;
2258   charset="iso-8859-1"
2259 From: Chef <chef@bork.bork.bork>
2260 To: issue_tracker@your.tracker.email.domain.example
2261 Subject: [frobulated] testing
2262 Cc: richard@test.test
2263 Reply-To: chef@bork.bork.bork
2264 Message-Id: <dummy_test_message_id>
2266 ''')
2267         assert not os.path.exists(SENDMAILDEBUG)
2268         self.assertEqual(self.db.issue.get(nodeid, 'title'),
2269             '[frobulated] testing')
2271     def testInvalidClassLooseReply(self):
2272         self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'loose'
2273         nodeid = self._handle_mail('''Content-Type: text/plain;
2274   charset="iso-8859-1"
2275 From: Chef <chef@bork.bork.bork>
2276 To: issue_tracker@your.tracker.email.domain.example
2277 Subject: Re: [frobulated] testing
2278 Cc: richard@test.test
2279 Reply-To: chef@bork.bork.bork
2280 Message-Id: <dummy_test_message_id>
2282 ''')
2283         assert not os.path.exists(SENDMAILDEBUG)
2284         self.assertEqual(self.db.issue.get(nodeid, 'title'),
2285             '[frobulated] testing')
2287     def testInvalidClassLoose(self):
2288         self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'loose'
2289         nodeid = self._handle_mail('''Content-Type: text/plain;
2290   charset="iso-8859-1"
2291 From: Chef <chef@bork.bork.bork>
2292 To: issue_tracker@your.tracker.email.domain.example
2293 Subject: [issue1234] testing
2294 Cc: richard@test.test
2295 Reply-To: chef@bork.bork.bork
2296 Message-Id: <dummy_test_message_id>
2298 ''')
2299         assert not os.path.exists(SENDMAILDEBUG)
2300         self.assertEqual(self.db.issue.get(nodeid, 'title'),
2301             '[issue1234] testing')
2303     def testClassLooseOK(self):
2304         self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'loose'
2305         self.db.keyword.create(name='Foo')
2306         nodeid = self._handle_mail('''Content-Type: text/plain;
2307   charset="iso-8859-1"
2308 From: Chef <chef@bork.bork.bork>
2309 To: issue_tracker@your.tracker.email.domain.example
2310 Subject: [keyword1] Testing... [name=Bar]
2311 Cc: richard@test.test
2312 Reply-To: chef@bork.bork.bork
2313 Message-Id: <dummy_test_message_id>
2315 ''')
2316         assert not os.path.exists(SENDMAILDEBUG)
2317         self.assertEqual(self.db.keyword.get('1', 'name'), 'Bar')
2319     def testClassStrictInvalid(self):
2320         self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'strict'
2321         self.instance.config.MAILGW_DEFAULT_CLASS = ''
2323         message = '''Content-Type: text/plain;
2324   charset="iso-8859-1"
2325 From: Chef <chef@bork.bork.bork>
2326 To: issue_tracker@your.tracker.email.domain.example
2327 Subject: Testing...
2328 Cc: richard@test.test
2329 Reply-To: chef@bork.bork.bork
2330 Message-Id: <dummy_test_message_id>
2332 '''
2333         self.assertRaises(MailUsageError, self._handle_mail, message)
2335     def testClassStrictValid(self):
2336         self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'strict'
2337         self.instance.config.MAILGW_DEFAULT_CLASS = ''
2339         nodeid = self._handle_mail('''Content-Type: text/plain;
2340   charset="iso-8859-1"
2341 From: Chef <chef@bork.bork.bork>
2342 To: issue_tracker@your.tracker.email.domain.example
2343 Subject: [issue] Testing...
2344 Cc: richard@test.test
2345 Reply-To: chef@bork.bork.bork
2346 Message-Id: <dummy_test_message_id>
2348 ''')
2350         assert not os.path.exists(SENDMAILDEBUG)
2351         self.assertEqual(self.db.issue.get(nodeid, 'title'), 'Testing...')
2353     #
2354     # TEST FOR INVALID COMMANDS HANDLING
2355     #
2356     def testInvalidCommands(self):
2357         self.assertRaises(MailUsageError, self._handle_mail,
2358             '''Content-Type: text/plain;
2359   charset="iso-8859-1"
2360 From: Chef <chef@bork.bork.bork>
2361 To: issue_tracker@your.tracker.email.domain.example
2362 Subject: testing [frobulated]
2363 Cc: richard@test.test
2364 Reply-To: chef@bork.bork.bork
2365 Message-Id: <dummy_test_message_id>
2367 ''')
2369     def testInvalidCommandPassthrough(self):
2370         self.instance.config.MAILGW_SUBJECT_SUFFIX_PARSING = 'none'
2371         nodeid = self._handle_mail('''Content-Type: text/plain;
2372   charset="iso-8859-1"
2373 From: Chef <chef@bork.bork.bork>
2374 To: issue_tracker@your.tracker.email.domain.example
2375 Subject: testing [frobulated]
2376 Cc: richard@test.test
2377 Reply-To: chef@bork.bork.bork
2378 Message-Id: <dummy_test_message_id>
2380 ''')
2381         assert not os.path.exists(SENDMAILDEBUG)
2382         self.assertEqual(self.db.issue.get(nodeid, 'title'),
2383             'testing [frobulated]')
2385     def testInvalidCommandPassthroughLoose(self):
2386         self.instance.config.MAILGW_SUBJECT_SUFFIX_PARSING = 'loose'
2387         nodeid = self._handle_mail('''Content-Type: text/plain;
2388   charset="iso-8859-1"
2389 From: Chef <chef@bork.bork.bork>
2390 To: issue_tracker@your.tracker.email.domain.example
2391 Subject: testing [frobulated]
2392 Cc: richard@test.test
2393 Reply-To: chef@bork.bork.bork
2394 Message-Id: <dummy_test_message_id>
2396 ''')
2397         assert not os.path.exists(SENDMAILDEBUG)
2398         self.assertEqual(self.db.issue.get(nodeid, 'title'),
2399             'testing [frobulated]')
2401     def testInvalidCommandPassthroughLooseOK(self):
2402         self.instance.config.MAILGW_SUBJECT_SUFFIX_PARSING = 'loose'
2403         nodeid = self._handle_mail('''Content-Type: text/plain;
2404   charset="iso-8859-1"
2405 From: Chef <chef@bork.bork.bork>
2406 To: issue_tracker@your.tracker.email.domain.example
2407 Subject: testing [assignedto=mary]
2408 Cc: richard@test.test
2409 Reply-To: chef@bork.bork.bork
2410 Message-Id: <dummy_test_message_id>
2412 ''')
2413         assert not os.path.exists(SENDMAILDEBUG)
2414         self.assertEqual(self.db.issue.get(nodeid, 'title'), 'testing')
2415         self.assertEqual(self.db.issue.get(nodeid, 'assignedto'), self.mary_id)
2417     def testCommandDelimiters(self):
2418         self.instance.config.MAILGW_SUBJECT_SUFFIX_DELIMITERS = '{}'
2419         nodeid = self._handle_mail('''Content-Type: text/plain;
2420   charset="iso-8859-1"
2421 From: Chef <chef@bork.bork.bork>
2422 To: issue_tracker@your.tracker.email.domain.example
2423 Subject: testing {assignedto=mary}
2424 Cc: richard@test.test
2425 Reply-To: chef@bork.bork.bork
2426 Message-Id: <dummy_test_message_id>
2428 ''')
2429         assert not os.path.exists(SENDMAILDEBUG)
2430         self.assertEqual(self.db.issue.get(nodeid, 'title'), 'testing')
2431         self.assertEqual(self.db.issue.get(nodeid, 'assignedto'), self.mary_id)
2433     def testPrefixDelimiters(self):
2434         self.instance.config.MAILGW_SUBJECT_SUFFIX_DELIMITERS = '{}'
2435         self.db.keyword.create(name='Foo')
2436         self._handle_mail('''Content-Type: text/plain;
2437   charset="iso-8859-1"
2438 From: richard <richard@test.test>
2439 To: issue_tracker@your.tracker.email.domain.example
2440 Message-Id: <followup_dummy_id>
2441 In-Reply-To: <dummy_test_message_id>
2442 Subject: {keyword1} Testing... {name=Bar}
2444 ''')
2445         assert not os.path.exists(SENDMAILDEBUG)
2446         self.assertEqual(self.db.keyword.get('1', 'name'), 'Bar')
2448     def testCommandDelimitersIgnore(self):
2449         self.instance.config.MAILGW_SUBJECT_SUFFIX_DELIMITERS = '{}'
2450         nodeid = self._handle_mail('''Content-Type: text/plain;
2451   charset="iso-8859-1"
2452 From: Chef <chef@bork.bork.bork>
2453 To: issue_tracker@your.tracker.email.domain.example
2454 Subject: testing [assignedto=mary]
2455 Cc: richard@test.test
2456 Reply-To: chef@bork.bork.bork
2457 Message-Id: <dummy_test_message_id>
2459 ''')
2460         assert not os.path.exists(SENDMAILDEBUG)
2461         self.assertEqual(self.db.issue.get(nodeid, 'title'),
2462             'testing [assignedto=mary]')
2463         self.assertEqual(self.db.issue.get(nodeid, 'assignedto'), None)
2465     def testReplytoMatch(self):
2466         self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'loose'
2467         nodeid = self.doNewIssue()
2468         nodeid2 = self._handle_mail('''Content-Type: text/plain;
2469   charset="iso-8859-1"
2470 From: Chef <chef@bork.bork.bork>
2471 To: issue_tracker@your.tracker.email.domain.example
2472 Message-Id: <dummy_test_message_id2>
2473 In-Reply-To: <dummy_test_message_id>
2474 Subject: Testing...
2476 Followup message.
2477 ''')
2479         nodeid3 = self._handle_mail('''Content-Type: text/plain;
2480   charset="iso-8859-1"
2481 From: Chef <chef@bork.bork.bork>
2482 To: issue_tracker@your.tracker.email.domain.example
2483 Message-Id: <dummy_test_message_id3>
2484 In-Reply-To: <dummy_test_message_id2>
2485 Subject: Testing...
2487 Yet another message in the same thread/issue.
2488 ''')
2490         self.assertEqual(nodeid, nodeid2)
2491         self.assertEqual(nodeid, nodeid3)
2493     def testHelpSubject(self):
2494         message = '''Content-Type: text/plain;
2495   charset="iso-8859-1"
2496 From: Chef <chef@bork.bork.bork>
2497 To: issue_tracker@your.tracker.email.domain.example
2498 Message-Id: <dummy_test_message_id2>
2499 In-Reply-To: <dummy_test_message_id>
2500 Subject: hElp
2503 '''
2504         self.assertRaises(MailUsageHelp, self._handle_mail, message)
2506     def testMaillistSubject(self):
2507         self.instance.config.MAILGW_SUBJECT_SUFFIX_DELIMITERS = '[]'
2508         self.db.keyword.create(name='Foo')
2509         self._handle_mail('''Content-Type: text/plain;
2510   charset="iso-8859-1"
2511 From: Chef <chef@bork.bork.bork>
2512 To: issue_tracker@your.tracker.email.domain.example
2513 Subject: [mailinglist-name] [keyword1] Testing.. [name=Bar]
2514 Cc: richard@test.test
2515 Reply-To: chef@bork.bork.bork
2516 Message-Id: <dummy_test_message_id>
2518 ''')
2520         assert not os.path.exists(SENDMAILDEBUG)
2521         self.assertEqual(self.db.keyword.get('1', 'name'), 'Bar')
2523     def testUnknownPrefixSubject(self):
2524         self.db.keyword.create(name='Foo')
2525         self._handle_mail('''Content-Type: text/plain;
2526   charset="iso-8859-1"
2527 From: Chef <chef@bork.bork.bork>
2528 To: issue_tracker@your.tracker.email.domain.example
2529 Subject: VeryStrangeRe: [keyword1] Testing.. [name=Bar]
2530 Cc: richard@test.test
2531 Reply-To: chef@bork.bork.bork
2532 Message-Id: <dummy_test_message_id>
2534 ''')
2536         assert not os.path.exists(SENDMAILDEBUG)
2537         self.assertEqual(self.db.keyword.get('1', 'name'), 'Bar')
2539     def testOneCharSubject(self):
2540         message = '''Content-Type: text/plain;
2541   charset="iso-8859-1"
2542 From: Chef <chef@bork.bork.bork>
2543 To: issue_tracker@your.tracker.email.domain.example
2544 Subject: b
2545 Cc: richard@test.test
2546 Reply-To: chef@bork.bork.bork
2547 Message-Id: <dummy_test_message_id>
2549 '''
2550         try:
2551             self._handle_mail(message)
2552         except MailUsageError:
2553             self.fail('MailUsageError raised')
2555     def testIssueidLast(self):
2556         nodeid1 = self.doNewIssue()
2557         nodeid2 = self._handle_mail('''Content-Type: text/plain;
2558   charset="iso-8859-1"
2559 From: mary <mary@test.test>
2560 To: issue_tracker@your.tracker.email.domain.example
2561 Message-Id: <followup_dummy_id>
2562 In-Reply-To: <dummy_test_message_id>
2563 Subject: New title [issue1]
2565 This is a second followup
2566 ''')
2568         assert nodeid1 == nodeid2
2569         self.assertEqual(self.db.issue.get(nodeid2, 'title'), "Testing...")
2571     def testSecurityMessagePermissionContent(self):
2572         id = self.doNewIssue()
2573         issue = self.db.issue.getnode (id)
2574         self.db.security.addRole(name='Nomsg')
2575         self.db.security.addPermissionToRole('Nomsg', 'Email Access')
2576         for cl in 'issue', 'file', 'keyword':
2577             for p in 'View', 'Edit', 'Create':
2578                 self.db.security.addPermissionToRole('Nomsg', p, cl)
2579         self.db.user.set(self.mary_id, roles='Nomsg')
2580         nodeid = self._handle_mail('''Content-Type: text/plain;
2581   charset="iso-8859-1"
2582 From: Chef <chef@bork.bork.bork>
2583 To: issue_tracker@your.tracker.email.domain.example
2584 Message-Id: <dummy_test_message_id_2>
2585 Subject: [issue%(id)s] Testing... [nosy=+mary]
2587 Just a test reply
2588 '''%locals())
2589         assert os.path.exists(SENDMAILDEBUG)
2590         self.compareMessages(self._get_mail(),
2591 '''FROM: roundup-admin@your.tracker.email.domain.example
2592 TO: chef@bork.bork.bork, richard@test.test
2593 Content-Type: text/plain; charset="utf-8"
2594 Subject: [issue1] Testing...
2595 To: richard@test.test
2596 From: "Bork, Chef" <issue_tracker@your.tracker.email.domain.example>
2597 Reply-To: Roundup issue tracker
2598  <issue_tracker@your.tracker.email.domain.example>
2599 MIME-Version: 1.0
2600 Message-Id: <dummy_test_message_id_2>
2601 In-Reply-To: <dummy_test_message_id>
2602 X-Roundup-Name: Roundup issue tracker
2603 X-Roundup-Loop: hello
2604 X-Roundup-Issue-Status: chatting
2605 Content-Transfer-Encoding: quoted-printable
2608 Bork, Chef <chef@bork.bork.bork> added the comment:
2610 Just a test reply
2612 ----------
2613 nosy: +mary
2614 status: unread -> chatting
2616 _______________________________________________________________________
2617 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
2618 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
2619 _______________________________________________________________________
2620 ''')
2622     def testOutlookAttachment(self):
2623         message = '''X-MimeOLE: Produced By Microsoft Exchange V6.5
2624 Content-class: urn:content-classes:message
2625 MIME-Version: 1.0
2626 Content-Type: multipart/mixed;
2627         boundary="----_=_NextPart_001_01CACA65.40A51CBC"
2628 Subject: Example of a failed outlook attachment e-mail
2629 Date: Tue, 23 Mar 2010 01:43:44 -0700
2630 Message-ID: <CA37F17219784343816CA6613D2E339205E7D0F9@nrcwstexb1.nrc.ca>
2631 X-MS-Has-Attach: yes
2632 X-MS-TNEF-Correlator: 
2633 Thread-Topic: Example of a failed outlook attachment e-mail
2634 Thread-Index: AcrKJo/t3pUBBwTpSwWNE3LE67UBDQ==
2635 From: "Hugh" <richard@test.test>
2636 To: <richard@test.test>
2637 X-OriginalArrivalTime: 23 Mar 2010 08:45:57.0350 (UTC) FILETIME=[41893860:01CACA65]
2639 This is a multi-part message in MIME format.
2641 ------_=_NextPart_001_01CACA65.40A51CBC
2642 Content-Type: multipart/alternative;
2643         boundary="----_=_NextPart_002_01CACA65.40A51CBC"
2646 ------_=_NextPart_002_01CACA65.40A51CBC
2647 Content-Type: text/plain;
2648         charset="us-ascii"
2649 Content-Transfer-Encoding: quoted-printable
2652 Hi Richard,
2654 I suppose this isn't the exact message that was sent but is a resend of
2655 one of my trial messages that failed.  For your benefit I changed the
2656 subject line and am adding these words to the message body.  Should
2657 still be as problematic, but if you like I can resend an exact copy of a
2658 failed message changing nothing except putting your address instead of
2659 our tracker.
2661 Thanks very much for taking time to look into this.  Much appreciated.
2663  <<battery backup>>=20
2665 ------_=_NextPart_002_01CACA65.40A51CBC
2666 Content-Type: text/html;
2667         charset="us-ascii"
2668 Content-Transfer-Encoding: quoted-printable
2670 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
2671 <HTML>
2672 <HEAD>
2673 <META HTTP-EQUIV=3D"Content-Type" CONTENT=3D"text/html; =
2674 charset=3Dus-ascii">
2675 <META NAME=3D"Generator" CONTENT=3D"MS Exchange Server version =
2676 6.5.7654.12">
2677 <TITLE>Example of a failed outlook attachment e-mail</TITLE>
2678 </HEAD>
2679 <BODY>
2680 <!-- Converted from text/rtf format -->
2681 <BR>
2683 <P><FONT SIZE=3D2 FACE=3D"Arial">Hi Richard,</FONT>
2684 </P>
2686 <P><FONT SIZE=3D2 FACE=3D"Arial">I suppose this isn't the exact message =
2687 that was sent but is a resend of one of my trial messages that =
2688 failed.&nbsp; For your benefit I changed the subject line and am adding =
2689 these words to the message body.&nbsp; Should still be as problematic, =
2690 but if you like I can resend an exact copy of a failed message changing =
2691 nothing except putting your address instead of our tracker.</FONT></P>
2693 <P><FONT SIZE=3D2 FACE=3D"Arial">Thanks very much for taking time to =
2694 look into this.&nbsp; Much appreciated.</FONT>
2695 </P>
2696 <BR>
2698 <P><FONT FACE=3D"Arial" SIZE=3D2 COLOR=3D"#000000"> &lt;&lt;battery =
2699 backup&gt;&gt; </FONT>
2700 </P>
2702 </BODY>
2703 </HTML>
2704 ------_=_NextPart_002_01CACA65.40A51CBC--
2706 ------_=_NextPart_001_01CACA65.40A51CBC
2707 Content-Type: message/rfc822
2708 Content-Transfer-Encoding: 7bit
2710 X-MimeOLE: Produced By Microsoft Exchange V6.5
2711 MIME-Version: 1.0
2712 Content-Type: multipart/alternative;
2713         boundary="----_=_NextPart_003_01CAC15A.29717800"
2714 X-OriginalArrivalTime: 11 Mar 2010 20:33:51.0249 (UTC) FILETIME=[28FEE010:01CAC15A]
2715 Content-class: urn:content-classes:message
2716 Subject: battery backup
2717 Date: Thu, 11 Mar 2010 13:33:43 -0700
2718 Message-ID: <p06240809c7bf02f9624c@[128.114.22.203]>
2719 X-MS-Has-Attach: 
2720 X-MS-TNEF-Correlator: 
2721 Thread-Topic: battery backup
2722 Thread-Index: AcrBWimtulTrSvBdQ2CcfZ8lyQdxmQ==
2723 From: "Jerry" <jerry@test.test>
2724 To: "Hugh" <hugh@test.test>
2726 This is a multi-part message in MIME format.
2728 ------_=_NextPart_003_01CAC15A.29717800
2729 Content-Type: text/plain;
2730         charset="iso-8859-1"
2731 Content-Transfer-Encoding: quoted-printable
2733 Dear Hugh,
2734         A car batter has an energy capacity of ~ 500Wh.  A UPS=20
2735 battery is worse than this.
2737 if we need to provied 100kW for 30 minutes that will take 100 car=20
2738 batteries.  This seems like an awful lot of batteries.
2740 Of course I like your idea of making the time 1 minute, so we get to=20
2741 a more modest number of batteries
2743 Jerry
2746 ------_=_NextPart_003_01CAC15A.29717800
2747 Content-Type: text/html;
2748         charset="iso-8859-1"
2749 Content-Transfer-Encoding: quoted-printable
2751 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
2752 <HTML>
2753 <HEAD>
2754 <META HTTP-EQUIV=3D"Content-Type" CONTENT=3D"text/html; =
2755 charset=3Diso-8859-1">
2756 <META NAME=3D"Generator" CONTENT=3D"MS Exchange Server version =
2757 6.5.7654.12">
2758 <TITLE>battery backup</TITLE>
2759 </HEAD>
2760 <BODY>
2761 <!-- Converted from text/plain format -->
2763 <P><FONT SIZE=3D2>Dear Hugh,</FONT>
2765 <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <FONT SIZE=3D2>A car =
2766 batter has an energy capacity of ~ 500Wh.&nbsp; A UPS </FONT>
2768 <BR><FONT SIZE=3D2>battery is worse than this.</FONT>
2769 </P>
2771 <P><FONT SIZE=3D2>if we need to provied 100kW for 30 minutes that will =
2772 take 100 car </FONT>
2774 <BR><FONT SIZE=3D2>batteries.&nbsp; This seems like an awful lot of =
2775 batteries.</FONT>
2776 </P>
2778 <P><FONT SIZE=3D2>Of course I like your idea of making the time 1 =
2779 minute, so we get to </FONT>
2781 <BR><FONT SIZE=3D2>a more modest number of batteries</FONT>
2782 </P>
2784 <P><FONT SIZE=3D2>Jerry</FONT>
2785 </P>
2787 </BODY>
2788 </HTML>
2789 ------_=_NextPart_003_01CAC15A.29717800--
2791 ------_=_NextPart_001_01CACA65.40A51CBC--
2792 '''
2793         nodeid = self._handle_mail(message)
2794         assert not os.path.exists(SENDMAILDEBUG)
2795         msgid = self.db.issue.get(nodeid, 'messages')[0]
2796         self.assert_(self.db.msg.get(msgid, 'content').startswith('Hi Richard'))
2797         self.assertEqual(self.db.msg.get(msgid, 'files'), ['1', '2'])
2798         fileid = self.db.msg.get(msgid, 'files')[0]
2799         self.assertEqual(self.db.file.get(fileid, 'type'), 'text/html')
2800         fileid = self.db.msg.get(msgid, 'files')[1]
2801         self.assertEqual(self.db.file.get(fileid, 'type'), 'message/rfc822')
2803     def testForwardedMessageAttachment(self):
2804         message = '''Return-Path: <rgg@test.test>
2805 Received: from localhost(127.0.0.1), claiming to be "[115.130.26.69]"
2806 via SMTP by localhost, id smtpdAAApLaWrq; Tue Apr 13 23:10:05 2010
2807 Message-ID: <4BC4F9C7.50409@test.test>
2808 Date: Wed, 14 Apr 2010 09:09:59 +1000
2809 From: Rupert Goldie <rgg@test.test>
2810 User-Agent: Thunderbird 2.0.0.24 (Windows/20100228)
2811 MIME-Version: 1.0
2812 To: ekit issues <issues@test.test>
2813 Subject: [Fwd: PHP ERROR (fb)] post limit reached
2814 Content-Type: multipart/mixed; boundary="------------000807090608060304010403"
2816 This is a multi-part message in MIME format.
2817 --------------000807090608060304010403
2818 Content-Type: text/plain; charset=ISO-8859-1; format=flowed
2819 Content-Transfer-Encoding: 7bit
2821 Catch this exception and log it without emailing.
2823 --------------000807090608060304010403
2824 Content-Type: message/rfc822; name="PHP ERROR (fb).eml"
2825 Content-Transfer-Encoding: 7bit
2826 Content-Disposition: inline; filename="PHP ERROR (fb).eml"
2828 Return-Path: <ektravj@test.test>
2829 X-Sieve: CMU Sieve 2.2
2830 via SMTP by crown.off.ekorp.com, id smtpdAAA1JaW1o; Tue Apr 13 23:01:04 2010
2831 X-Virus-Scanned: by amavisd-new at ekit.com
2832 To: facebook-errors@test.test
2833 From: ektravj@test.test
2834 Subject: PHP ERROR (fb)
2835 Message-Id: <20100413230100.D601D27E84@mail2.elax3.ekorp.com>
2836 Date: Tue, 13 Apr 2010 23:01:00 +0000 (UTC)
2838 [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
2839 Stack trace:
2840 #0 /app/01/www/virtual/fb.ekit.com/htdocs/gateway/ekit/feed/index.php(178): fb_exceptions(Object(FacebookRestClientException))
2841 #1 {main}
2842  thrown in /app/01/www/virtual/fb.ekit.com/htdocs/includes/functions.php on line 280
2845 --------------000807090608060304010403--
2846 '''
2847         nodeid = self._handle_mail(message)
2848         assert not os.path.exists(SENDMAILDEBUG)
2849         msgid = self.db.issue.get(nodeid, 'messages')[0]
2850         self.assertEqual(self.db.msg.get(msgid, 'content'),
2851             'Catch this exception and log it without emailing.')
2852         self.assertEqual(self.db.msg.get(msgid, 'files'), ['1'])
2853         fileid = self.db.msg.get(msgid, 'files')[0]
2854         self.assertEqual(self.db.file.get(fileid, 'type'), 'message/rfc822')
2856 def test_suite():
2857     suite = unittest.TestSuite()
2858     suite.addTest(unittest.makeSuite(MailgwTestCase))
2859     return suite
2861 if __name__ == '__main__':
2862     runner = unittest.TextTestRunner()
2863     unittest.main(testRunner=runner)
2865 # vim: set filetype=python sts=4 sw=4 et si :