Code

Add config-option "nosy" to messages_to_author setting in [nosy] section
[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
17 import gpgmelib
18 from email.parser import FeedParser
21 try:
22     import pyme, pyme.core
23 except ImportError:
24     pyme = None
27 from cStringIO import StringIO
29 if not os.environ.has_key('SENDMAILDEBUG'):
30     os.environ['SENDMAILDEBUG'] = 'mail-test.log'
31 SENDMAILDEBUG = os.environ['SENDMAILDEBUG']
33 from roundup import mailgw, i18n, roundupdb
34 from roundup.mailgw import MailGW, Unauthorized, uidFromAddress, \
35     parseContent, IgnoreLoop, IgnoreBulk, MailUsageError, MailUsageHelp
36 from roundup import init, instance, password, rfc2822, __version__
37 from roundup.anypy.sets_ import set
39 #import db_test_base
40 import memorydb
42 class Message(rfc822.Message):
43     """String-based Message class with equivalence test."""
44     def __init__(self, s):
45         rfc822.Message.__init__(self, StringIO(s.strip()))
47     def __eq__(self, other):
48         return (self.dict == other.dict and
49                 self.fp.read() == other.fp.read())
51 class Tracker(object):
52     def open(self, journaltag):
53         return self.db
55 class DiffHelper:
56     def compareMessages(self, new, old):
57         """Compare messages for semantic equivalence."""
58         new, old = Message(new), Message(old)
60         # all Roundup-generated messages have "Precedence: bulk"
61         old['Precedence'] = 'bulk'
63         # don't try to compare the date
64         del new['date'], old['date']
66         if not new == old:
67             res = []
69             replace = {}
70             for key in new.keys():
71                 if key.startswith('from '):
72                     # skip the unix from line
73                     continue
74                 if key.lower() == 'x-roundup-version':
75                     # version changes constantly, so handle it specially
76                     if new[key] != __version__:
77                         res.append('  %s: %r != %r' % (key, __version__,
78                             new[key]))
79                 elif key.lower() == 'content-type' and 'boundary=' in new[key]:
80                     # handle mime messages
81                     newmime = new[key].split('=',1)[-1].strip('"')
82                     oldmime = old.get(key, '').split('=',1)[-1].strip('"')
83                     replace ['--' + newmime] = '--' + oldmime
84                     replace ['--' + newmime + '--'] = '--' + oldmime + '--'
85                 elif new.get(key, '') != old.get(key, ''):
86                     res.append('  %s: %r != %r' % (key, old.get(key, ''),
87                         new.get(key, '')))
89             body_diff = self.compareStrings(new.fp.read(), old.fp.read(),
90                 replace=replace)
91             if body_diff:
92                 res.append('')
93                 res.extend(body_diff)
95             if res:
96                 res.insert(0, 'Generated message not correct (diff follows, expected vs. actual):')
97                 raise AssertionError, '\n'.join(res)
99     def compareStrings(self, s2, s1, replace={}):
100         '''Note the reversal of s2 and s1 - difflib.SequenceMatcher wants
101            the first to be the "original" but in the calls in this file,
102            the second arg is the original. Ho hum.
103            Do replacements over the replace dict -- used for mime boundary
104         '''
105         l1 = s1.strip().split('\n')
106         l2 = [replace.get(i,i) for i in s2.strip().split('\n')]
107         if l1 == l2:
108             return
109         s = difflib.SequenceMatcher(None, l1, l2)
110         res = []
111         for value, s1s, s1e, s2s, s2e in s.get_opcodes():
112             if value == 'equal':
113                 for i in range(s1s, s1e):
114                     res.append('  %s'%l1[i])
115             elif value == 'delete':
116                 for i in range(s1s, s1e):
117                     res.append('- %s'%l1[i])
118             elif value == 'insert':
119                 for i in range(s2s, s2e):
120                     res.append('+ %s'%l2[i])
121             elif value == 'replace':
122                 for i, j in zip(range(s1s, s1e), range(s2s, s2e)):
123                     res.append('- %s'%l1[i])
124                     res.append('+ %s'%l2[j])
126         return res
128 class MailgwTestAbstractBase(unittest.TestCase, DiffHelper):
129     count = 0
130     schema = 'classic'
131     def setUp(self):
132         self.old_translate_ = mailgw._
133         roundupdb._ = mailgw._ = i18n.get_translation(language='C').gettext
134         self.__class__.count = self.__class__.count + 1
136         # and open the database / "instance"
137         self.db = memorydb.create('admin')
138         self.instance = Tracker()
139         self.instance.db = self.db
140         self.instance.config = self.db.config
141         self.instance.MailGW = MailGW
143         self.chef_id = self.db.user.create(username='Chef',
144             address='chef@bork.bork.bork', realname='Bork, Chef', roles='User')
145         self.richard_id = self.db.user.create(username='richard',
146             address='richard@test.test', roles='User')
147         self.mary_id = self.db.user.create(username='mary',
148             address='mary@test.test', roles='User', realname='Contrary, Mary')
149         self.john_id = self.db.user.create(username='john',
150             address='john@test.test', roles='User', realname='John Doe',
151             alternate_addresses='jondoe@test.test\njohn.doe@test.test')
152         self.rgg_id = self.db.user.create(username='rgg',
153             address='rgg@test.test', roles='User')
155     def tearDown(self):
156         roundupdb._ = mailgw._ = self.old_translate_
157         if os.path.exists(SENDMAILDEBUG):
158             os.remove(SENDMAILDEBUG)
159         self.db.close()
161     def _create_mailgw(self, message, args=()):
162         class MailGW(self.instance.MailGW):
163             def handle_message(self, message):
164                 return self._handle_message(message)
165         handler = MailGW(self.instance, args)
166         handler.db = self.db
167         return handler
169     def _handle_mail(self, message, args=(), trap_exc=0):
170         handler = self._create_mailgw(message, args)
171         handler.trapExceptions = trap_exc
172         return handler.main(StringIO(message))
174     def _get_mail(self):
175         f = open(SENDMAILDEBUG)
176         try:
177             return f.read()
178         finally:
179             f.close()
181     # Normal test-case used for both non-pgp test and a test while pgp
182     # is enabled, so this test is run in both test suites.
183     def testEmptyMessage(self):
184         nodeid = self._handle_mail('''Content-Type: text/plain;
185   charset="iso-8859-1"
186 From: Chef <chef@bork.bork.bork>
187 To: issue_tracker@your.tracker.email.domain.example
188 Cc: richard@test.test
189 Reply-To: chef@bork.bork.bork
190 Message-Id: <dummy_test_message_id>
191 Subject: [issue] Testing...
193 ''')
194         assert not os.path.exists(SENDMAILDEBUG)
195         self.assertEqual(self.db.issue.get(nodeid, 'title'), 'Testing...')
198 class MailgwTestCase(MailgwTestAbstractBase):
200     def testMessageWithFromInIt(self):
201         nodeid = self._handle_mail('''Content-Type: text/plain;
202   charset="iso-8859-1"
203 From: Chef <chef@bork.bork.bork>
204 To: issue_tracker@your.tracker.email.domain.example
205 Cc: richard@test.test
206 Reply-To: chef@bork.bork.bork
207 Message-Id: <dummy_test_message_id>
208 Subject: [issue] Testing...
210 From here to there!
211 ''')
212         assert not os.path.exists(SENDMAILDEBUG)
213         msgid = self.db.issue.get(nodeid, 'messages')[0]
214         self.assertEqual(self.db.msg.get(msgid, 'content'), 'From here to there!')
216     def testNoMessageId(self):
217         self.instance.config['MAIL_DOMAIN'] = 'example.com'
218         nodeid = self._handle_mail('''Content-Type: text/plain;
219   charset="iso-8859-1"
220 From: Chef <chef@bork.bork.bork>
221 To: issue_tracker@your.tracker.email.domain.example
222 Cc: richard@test.test
223 Reply-To: chef@bork.bork.bork
224 Subject: [issue] Testing...
226 Hi there!
227 ''')
228         assert not os.path.exists(SENDMAILDEBUG)
229         msgid = self.db.issue.get(nodeid, 'messages')[0]
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, 'issueNone')
235         nodeid = self._handle_mail('''Content-Type: text/plain;
236   charset="iso-8859-1"
237 From: Chef <chef@bork.bork.bork>
238 To: issue_tracker@your.tracker.email.domain.example
239 Subject: [issue%(nodeid)s] Testing...
241 Just a test reply
242 '''%locals())
243         msgid = self.db.issue.get(nodeid, 'messages')[-1]
244         messageid = self.db.msg.get(msgid, 'messageid')
245         x1, x2 = messageid.split('@')
246         self.assertEqual(x2, 'example.com>')
247         x = x1.split('.')[-1]
248         self.assertEqual(x, "issue%s"%nodeid)
250     def testOptions(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;priority=critical')))
261         self.assertEqual(self.db.issue.get(nodeid, 'status'), '3')
262         self.assertEqual(self.db.issue.get(nodeid, 'priority'), '1')
264     def testOptionsMulti(self):
265         nodeid = self._handle_mail('''Content-Type: text/plain;
266   charset="iso-8859-1"
267 From: Chef <chef@bork.bork.bork>
268 To: issue_tracker@your.tracker.email.domain.example
269 Message-Id: <dummy_test_message_id>
270 Reply-To: chef@bork.bork.bork
271 Subject: [issue] Testing...
273 Hi there!
274 ''', (('-C', 'issue'), ('-S', 'status=chatting'), ('-S', 'priority=critical')))
275         self.assertEqual(self.db.issue.get(nodeid, 'status'), '3')
276         self.assertEqual(self.db.issue.get(nodeid, 'priority'), '1')
278     def testOptionClass(self):
279         nodeid = self._handle_mail('''Content-Type: text/plain;
280   charset="iso-8859-1"
281 From: Chef <chef@bork.bork.bork>
282 To: issue_tracker@your.tracker.email.domain.example
283 Message-Id: <dummy_test_message_id>
284 Reply-To: chef@bork.bork.bork
285 Subject: [issue] Testing... [status=chatting;priority=critical]
287 Hi there!
288 ''', (('-c', 'issue'),))
289         self.assertEqual(self.db.issue.get(nodeid, 'title'), 'Testing...')
290         self.assertEqual(self.db.issue.get(nodeid, 'status'), '3')
291         self.assertEqual(self.db.issue.get(nodeid, 'priority'), '1')
293     newmsg = '''Content-Type: text/plain;
294   charset="iso-8859-1"
295 From: Chef <chef@bork.bork.bork>
296 To: issue_tracker@your.tracker.email.domain.example
297 Cc: richard@test.test
298 Message-Id: <dummy_test_message_id>
299 Subject: [issue] Testing...
301 This is a test submission of a new issue.
302 '''
304     def doNewIssue(self):
305         nodeid = self._handle_mail(self.newmsg)
306         assert not os.path.exists(SENDMAILDEBUG)
307         l = self.db.issue.get(nodeid, 'nosy')
308         l.sort()
309         self.assertEqual(l, [self.chef_id, self.richard_id])
310         return nodeid
312     def testNewIssue(self):
313         self.doNewIssue()
315     def testNewIssueNosy(self):
316         self.instance.config.ADD_AUTHOR_TO_NOSY = 'yes'
317         nodeid = self.doNewIssue()
318         m = self.db.issue.get(nodeid, 'messages')
319         self.assertEqual(len(m), 1)
320         recv = self.db.msg.get(m[0], 'recipients')
321         self.assertEqual(recv, [self.richard_id])
323     def testNewIssueNosyAuthor(self):
324         self.instance.config.ADD_AUTHOR_TO_NOSY = 'no'
325         self.instance.config.MESSAGES_TO_AUTHOR = 'nosy'
326         nodeid = self._handle_mail(self.newmsg)
327         assert not os.path.exists(SENDMAILDEBUG)
328         l = self.db.issue.get(nodeid, 'nosy')
329         l.sort()
330         self.assertEqual(l, [self.richard_id])
331         m = self.db.issue.get(nodeid, 'messages')
332         self.assertEqual(len(m), 1)
333         recv = self.db.msg.get(m[0], 'recipients')
334         recv.sort()
335         self.assertEqual(recv, [self.richard_id])
337     def testAlternateAddress(self):
338         self._handle_mail('''Content-Type: text/plain;
339   charset="iso-8859-1"
340 From: John Doe <john.doe@test.test>
341 To: issue_tracker@your.tracker.email.domain.example
342 Message-Id: <dummy_test_message_id>
343 Subject: [issue] Testing...
345 This is a test submission of a new issue.
346 ''')
347         userlist = self.db.user.list()
348         assert not os.path.exists(SENDMAILDEBUG)
349         self.assertEqual(userlist, self.db.user.list(),
350             "user created when it shouldn't have been")
352     def testNewIssueNoClass(self):
353         self._handle_mail('''Content-Type: text/plain;
354   charset="iso-8859-1"
355 From: Chef <chef@bork.bork.bork>
356 To: issue_tracker@your.tracker.email.domain.example
357 Cc: richard@test.test
358 Message-Id: <dummy_test_message_id>
359 Subject: Testing...
361 This is a test submission of a new issue.
362 ''')
363         assert not os.path.exists(SENDMAILDEBUG)
365     def testNewIssueAuthMsg(self):
366         self.db.config.MESSAGES_TO_AUTHOR = 'yes'
367         self._handle_mail('''Content-Type: text/plain;
368   charset="iso-8859-1"
369 From: Chef <chef@bork.bork.bork>
370 To: issue_tracker@your.tracker.email.domain.example
371 Message-Id: <dummy_test_message_id>
372 Subject: [issue] Testing... [nosy=mary; assignedto=richard]
374 This is a test submission of a new issue.
375 ''')
376         self.compareMessages(self._get_mail(),
377 '''FROM: roundup-admin@your.tracker.email.domain.example
378 TO: chef@bork.bork.bork, mary@test.test, richard@test.test
379 Content-Type: text/plain; charset="utf-8"
380 Subject: [issue1] Testing...
381 To: chef@bork.bork.bork, mary@test.test, richard@test.test
382 From: "Bork, Chef" <issue_tracker@your.tracker.email.domain.example>
383 Reply-To: Roundup issue tracker
384  <issue_tracker@your.tracker.email.domain.example>
385 MIME-Version: 1.0
386 Message-Id: <dummy_test_message_id>
387 X-Roundup-Name: Roundup issue tracker
388 X-Roundup-Loop: hello
389 X-Roundup-Issue-Status: unread
390 Content-Transfer-Encoding: quoted-printable
393 New submission from Bork, Chef <chef@bork.bork.bork>:
395 This is a test submission of a new issue.
397 ----------
398 assignedto: richard
399 messages: 1
400 nosy: Chef, mary, richard
401 status: unread
402 title: Testing...
404 _______________________________________________________________________
405 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
406 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
407 _______________________________________________________________________
408 ''')
410     def testNewIssueNoAuthorInfo(self):
411         self.db.config.MAIL_ADD_AUTHORINFO = 'no'
412         self._handle_mail('''Content-Type: text/plain;
413   charset="iso-8859-1"
414 From: Chef <chef@bork.bork.bork>
415 To: issue_tracker@your.tracker.email.domain.example
416 Message-Id: <dummy_test_message_id>
417 Subject: [issue] Testing... [nosy=mary; assignedto=richard]
419 This is a test submission of a new issue.
420 ''')
421         self.compareMessages(self._get_mail(),
422 '''FROM: roundup-admin@your.tracker.email.domain.example
423 TO: chef@bork.bork.bork, mary@test.test, richard@test.test
424 Content-Type: text/plain; charset="utf-8"
425 Subject: [issue1] Testing...
426 To: mary@test.test, richard@test.test
427 From: "Bork, Chef" <issue_tracker@your.tracker.email.domain.example>
428 Reply-To: Roundup issue tracker
429  <issue_tracker@your.tracker.email.domain.example>
430 MIME-Version: 1.0
431 Message-Id: <dummy_test_message_id>
432 X-Roundup-Name: Roundup issue tracker
433 X-Roundup-Loop: hello
434 X-Roundup-Issue-Status: unread
435 Content-Transfer-Encoding: quoted-printable
437 This is a test submission of a new issue.
439 ----------
440 assignedto: richard
441 messages: 1
442 nosy: Chef, mary, richard
443 status: unread
444 title: Testing...
446 _______________________________________________________________________
447 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
448 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
449 _______________________________________________________________________
450 ''')
452     def testNewIssueNoAuthorEmail(self):
453         self.db.config.MAIL_ADD_AUTHOREMAIL = 'no'
454         self._handle_mail('''Content-Type: text/plain;
455   charset="iso-8859-1"
456 From: Chef <chef@bork.bork.bork>
457 To: issue_tracker@your.tracker.email.domain.example
458 Message-Id: <dummy_test_message_id>
459 Subject: [issue] Testing... [nosy=mary; assignedto=richard]
461 This is a test submission of a new issue.
462 ''')
463         self.compareMessages(self._get_mail(),
464 '''FROM: roundup-admin@your.tracker.email.domain.example
465 TO: chef@bork.bork.bork, mary@test.test, richard@test.test
466 Content-Type: text/plain; charset="utf-8"
467 Subject: [issue1] Testing...
468 To: mary@test.test, richard@test.test
469 From: "Bork, Chef" <issue_tracker@your.tracker.email.domain.example>
470 Reply-To: Roundup issue tracker
471  <issue_tracker@your.tracker.email.domain.example>
472 MIME-Version: 1.0
473 Message-Id: <dummy_test_message_id>
474 X-Roundup-Name: Roundup issue tracker
475 X-Roundup-Loop: hello
476 X-Roundup-Issue-Status: unread
477 Content-Transfer-Encoding: quoted-printable
479 New submission from Bork, Chef:
481 This is a test submission of a new issue.
483 ----------
484 assignedto: richard
485 messages: 1
486 nosy: Chef, mary, richard
487 status: unread
488 title: Testing...
490 _______________________________________________________________________
491 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
492 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
493 _______________________________________________________________________
494 ''')
496     multipart_msg = '''From: mary <mary@test.test>
497 To: issue_tracker@your.tracker.email.domain.example
498 Message-Id: <followup_dummy_id>
499 In-Reply-To: <dummy_test_message_id>
500 Subject: [issue1] Testing...
501 Content-Type: multipart/mixed; boundary="bxyzzy"
502 Content-Disposition: inline
505 --bxyzzy
506 Content-Type: multipart/alternative; boundary="bCsyhTFzCvuiizWE"
507 Content-Disposition: inline
509 --bCsyhTFzCvuiizWE
510 Content-Type: text/plain; charset=us-ascii
511 Content-Disposition: inline
513 test attachment first text/plain
515 --bCsyhTFzCvuiizWE
516 Content-Type: application/octet-stream
517 Content-Disposition: attachment; filename="first.dvi"
518 Content-Transfer-Encoding: base64
520 SnVzdCBhIHRlc3QgAQo=
522 --bCsyhTFzCvuiizWE
523 Content-Type: text/plain; charset=us-ascii
524 Content-Disposition: inline
526 test attachment second text/plain
528 --bCsyhTFzCvuiizWE
529 Content-Type: text/html
530 Content-Disposition: inline
532 <html>
533 to be ignored.
534 </html>
536 --bCsyhTFzCvuiizWE--
538 --bxyzzy
539 Content-Type: multipart/alternative; boundary="bCsyhTFzCvuiizWF"
540 Content-Disposition: inline
542 --bCsyhTFzCvuiizWF
543 Content-Type: text/plain; charset=us-ascii
544 Content-Disposition: inline
546 test attachment third text/plain
548 --bCsyhTFzCvuiizWF
549 Content-Type: application/octet-stream
550 Content-Disposition: attachment; filename="second.dvi"
551 Content-Transfer-Encoding: base64
553 SnVzdCBhIHRlc3QK
555 --bCsyhTFzCvuiizWF--
557 --bxyzzy--
558 '''
560     multipart_msg_latin1 = '''From: mary <mary@test.test>
561 To: issue_tracker@your.tracker.email.domain.example
562 Message-Id: <followup_dummy_id>
563 In-Reply-To: <dummy_test_message_id>
564 Subject: [issue1] Testing...
565 Content-Type: multipart/alternative; boundary=001485f339f8f361fb049188dbba
568 --001485f339f8f361fb049188dbba
569 Content-Type: text/plain; charset=ISO-8859-1
570 Content-Transfer-Encoding: quoted-printable
572 umlaut =E4=F6=FC=C4=D6=DC=DF
574 --001485f339f8f361fb049188dbba
575 Content-Type: text/html; charset=ISO-8859-1
576 Content-Transfer-Encoding: quoted-printable
578 <html>umlaut =E4=F6=FC=C4=D6=DC=DF</html>
580 --001485f339f8f361fb049188dbba--
581 '''
583     multipart_msg_rfc822 = '''From: mary <mary@test.test>
584 To: issue_tracker@your.tracker.email.domain.example
585 Message-Id: <followup_dummy_id>
586 In-Reply-To: <dummy_test_message_id>
587 Subject: [issue1] Testing...
588 Content-Type: multipart/mixed; boundary=001485f339f8f361fb049188dbba
590 This is a multi-part message in MIME format.
591 --001485f339f8f361fb049188dbba
592 Content-Type: text/plain; charset=ISO-8859-15
593 Content-Transfer-Encoding: 7bit
595 First part: Text
597 --001485f339f8f361fb049188dbba
598 Content-Type: message/rfc822; name="Fwd: Original email subject.eml"
599 Content-Transfer-Encoding: 7bit
600 Content-Disposition: attachment; filename="Fwd: Original email subject.eml"
602 Message-Id: <followup_dummy_id_2>
603 In-Reply-To: <dummy_test_message_id_2>
604 MIME-Version: 1.0
605 Subject: Fwd: Original email subject
606 Date: Mon, 23 Aug 2010 08:23:33 +0200
607 Content-Type: multipart/alternative; boundary="090500050101020406060002"
609 This is a multi-part message in MIME format.
610 --090500050101020406060002
611 Content-Type: text/plain; charset=ISO-8859-15; format=flowed
612 Content-Transfer-Encoding: 7bit
614 some text in inner email
615 ========================
617 --090500050101020406060002
618 Content-Type: text/html; charset=ISO-8859-15
619 Content-Transfer-Encoding: 7bit
621 <html>
622 some text in inner email
623 ========================
624 </html>
626 --090500050101020406060002--
628 --001485f339f8f361fb049188dbba--
629 '''
631     def testMultipartKeepAlternatives(self):
632         self.doNewIssue()
633         self._handle_mail(self.multipart_msg)
634         messages = self.db.issue.get('1', 'messages')
635         messages.sort()
636         msg = self.db.msg.getnode (messages[-1])
637         assert(len(msg.files) == 5)
638         names = {0 : 'first.dvi', 4 : 'second.dvi'}
639         content = {3 : 'test attachment third text/plain\n',
640                    4 : 'Just a test\n'}
641         for n, id in enumerate (msg.files):
642             f = self.db.file.getnode (id)
643             self.assertEqual(f.name, names.get (n, 'unnamed'))
644             if n in content :
645                 self.assertEqual(f.content, content [n])
646         self.assertEqual(msg.content, 'test attachment second text/plain')
648     def testMultipartSeveralAttachmentMessages(self):
649         self.doNewIssue()
650         self._handle_mail(self.multipart_msg)
651         messages = self.db.issue.get('1', 'messages')
652         messages.sort()
653         self.assertEqual(messages[-1], '2')
654         msg = self.db.msg.getnode (messages[-1])
655         self.assertEqual(len(msg.files), 5)
656         issue = self.db.issue.getnode ('1')
657         self.assertEqual(len(issue.files), 5)
658         names = {0 : 'first.dvi', 4 : 'second.dvi'}
659         content = {3 : 'test attachment third text/plain\n',
660                    4 : 'Just a test\n'}
661         for n, id in enumerate (msg.files):
662             f = self.db.file.getnode (id)
663             self.assertEqual(f.name, names.get (n, 'unnamed'))
664             if n in content :
665                 self.assertEqual(f.content, content [n])
666         self.assertEqual(msg.content, 'test attachment second text/plain')
667         self.assertEqual(msg.files, ['1', '2', '3', '4', '5'])
668         self.assertEqual(issue.files, ['1', '2', '3', '4', '5'])
670         self._handle_mail(self.multipart_msg)
671         issue = self.db.issue.getnode ('1')
672         self.assertEqual(len(issue.files), 10)
673         messages = self.db.issue.get('1', 'messages')
674         messages.sort()
675         self.assertEqual(messages[-1], '3')
676         msg = self.db.msg.getnode (messages[-1])
677         self.assertEqual(issue.files, [str(i+1) for i in range(10)])
678         self.assertEqual(msg.files, ['6', '7', '8', '9', '10'])
680     def testMultipartKeepFiles(self):
681         self.doNewIssue()
682         self._handle_mail(self.multipart_msg)
683         messages = self.db.issue.get('1', 'messages')
684         messages.sort()
685         msg = self.db.msg.getnode (messages[-1])
686         self.assertEqual(len(msg.files), 5)
687         issue = self.db.issue.getnode ('1')
688         self.assertEqual(len(issue.files), 5)
689         names = {0 : 'first.dvi', 4 : 'second.dvi'}
690         content = {3 : 'test attachment third text/plain\n',
691                    4 : 'Just a test\n'}
692         for n, id in enumerate (msg.files):
693             f = self.db.file.getnode (id)
694             self.assertEqual(f.name, names.get (n, 'unnamed'))
695             if n in content :
696                 self.assertEqual(f.content, content [n])
697         self.assertEqual(msg.content, 'test attachment second text/plain')
698         self._handle_mail('''From: mary <mary@test.test>
699 To: issue_tracker@your.tracker.email.domain.example
700 Message-Id: <followup_dummy_id2>
701 In-Reply-To: <dummy_test_message_id>
702 Subject: [issue1] Testing...
704 This ist a message without attachment
705 ''')
706         issue = self.db.issue.getnode ('1')
707         self.assertEqual(len(issue.files), 5)
708         self.assertEqual(issue.files, ['1', '2', '3', '4', '5'])
710     def testMultipartDropAlternatives(self):
711         self.doNewIssue()
712         self.db.config.MAILGW_IGNORE_ALTERNATIVES = True
713         self._handle_mail(self.multipart_msg)
714         messages = self.db.issue.get('1', 'messages')
715         messages.sort()
716         msg = self.db.msg.getnode (messages[-1])
717         self.assertEqual(len(msg.files), 2)
718         names = {1 : 'second.dvi'}
719         content = {0 : 'test attachment third text/plain\n',
720                    1 : 'Just a test\n'}
721         for n, id in enumerate (msg.files):
722             f = self.db.file.getnode (id)
723             self.assertEqual(f.name, names.get (n, 'unnamed'))
724             if n in content :
725                 self.assertEqual(f.content, content [n])
726         self.assertEqual(msg.content, 'test attachment second text/plain')
728     def testMultipartCharsetUTF8NoAttach(self):
729         c = 'umlaut \xc3\xa4\xc3\xb6\xc3\xbc\xc3\x84\xc3\x96\xc3\x9c\xc3\x9f'
730         self.doNewIssue()
731         self.db.config.NOSY_MAX_ATTACHMENT_SIZE = 0
732         self._handle_mail(self.multipart_msg_latin1)
733         messages = self.db.issue.get('1', 'messages')
734         messages.sort()
735         msg = self.db.msg.getnode (messages[-1])
736         self.assertEqual(len(msg.files), 1)
737         name = 'unnamed'
738         content = '<html>' + c + '</html>\n'
739         for n, id in enumerate (msg.files):
740             f = self.db.file.getnode (id)
741             self.assertEqual(f.name, name)
742             self.assertEqual(f.content, content)
743         self.assertEqual(msg.content, c)
744         self.compareMessages(self._get_mail(),
745 '''FROM: roundup-admin@your.tracker.email.domain.example
746 TO: chef@bork.bork.bork, richard@test.test
747 Content-Type: text/plain; charset="utf-8"
748 Subject: [issue1] Testing...
749 To: chef@bork.bork.bork, richard@test.test
750 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
751 Reply-To: Roundup issue tracker
752  <issue_tracker@your.tracker.email.domain.example>
753 MIME-Version: 1.0
754 Message-Id: <followup_dummy_id>
755 In-Reply-To: <dummy_test_message_id>
756 X-Roundup-Name: Roundup issue tracker
757 X-Roundup-Loop: hello
758 X-Roundup-Issue-Status: chatting
759 X-Roundup-Issue-Files: unnamed
760 Content-Transfer-Encoding: quoted-printable
763 Contrary, Mary <mary@test.test> added the comment:
765 umlaut =C3=A4=C3=B6=C3=BC=C3=84=C3=96=C3=9C=C3=9F
766 File 'unnamed' not attached - you can download it from http://tracker.examp=
767 le/cgi-bin/roundup.cgi/bugs/file1.
769 ----------
770 status: unread -> chatting
772 _______________________________________________________________________
773 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
774 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
775 _______________________________________________________________________
776 ''')
778     def testMultipartCharsetLatin1NoAttach(self):
779         c = 'umlaut \xc3\xa4\xc3\xb6\xc3\xbc\xc3\x84\xc3\x96\xc3\x9c\xc3\x9f'
780         self.doNewIssue()
781         self.db.config.NOSY_MAX_ATTACHMENT_SIZE = 0
782         self.db.config.MAIL_CHARSET = 'iso-8859-1'
783         self._handle_mail(self.multipart_msg_latin1)
784         messages = self.db.issue.get('1', 'messages')
785         messages.sort()
786         msg = self.db.msg.getnode (messages[-1])
787         self.assertEqual(len(msg.files), 1)
788         name = 'unnamed'
789         content = '<html>' + c + '</html>\n'
790         for n, id in enumerate (msg.files):
791             f = self.db.file.getnode (id)
792             self.assertEqual(f.name, name)
793             self.assertEqual(f.content, content)
794         self.assertEqual(msg.content, c)
795         self.compareMessages(self._get_mail(),
796 '''FROM: roundup-admin@your.tracker.email.domain.example
797 TO: chef@bork.bork.bork, richard@test.test
798 Content-Type: text/plain; charset="iso-8859-1"
799 Subject: [issue1] Testing...
800 To: chef@bork.bork.bork, richard@test.test
801 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
802 Reply-To: Roundup issue tracker
803  <issue_tracker@your.tracker.email.domain.example>
804 MIME-Version: 1.0
805 Message-Id: <followup_dummy_id>
806 In-Reply-To: <dummy_test_message_id>
807 X-Roundup-Name: Roundup issue tracker
808 X-Roundup-Loop: hello
809 X-Roundup-Issue-Status: chatting
810 X-Roundup-Issue-Files: unnamed
811 Content-Transfer-Encoding: quoted-printable
814 Contrary, Mary <mary@test.test> added the comment:
816 umlaut =E4=F6=FC=C4=D6=DC=DF
817 File 'unnamed' not attached - you can download it from http://tracker.examp=
818 le/cgi-bin/roundup.cgi/bugs/file1.
820 ----------
821 status: unread -> chatting
823 _______________________________________________________________________
824 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
825 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
826 _______________________________________________________________________
827 ''')
829     def testMultipartCharsetUTF8AttachFile(self):
830         c = 'umlaut \xc3\xa4\xc3\xb6\xc3\xbc\xc3\x84\xc3\x96\xc3\x9c\xc3\x9f'
831         self.doNewIssue()
832         self._handle_mail(self.multipart_msg_latin1)
833         messages = self.db.issue.get('1', 'messages')
834         messages.sort()
835         msg = self.db.msg.getnode (messages[-1])
836         self.assertEqual(len(msg.files), 1)
837         name = 'unnamed'
838         content = '<html>' + c + '</html>\n'
839         for n, id in enumerate (msg.files):
840             f = self.db.file.getnode (id)
841             self.assertEqual(f.name, name)
842             self.assertEqual(f.content, content)
843         self.assertEqual(msg.content, c)
844         self.compareMessages(self._get_mail(),
845 '''FROM: roundup-admin@your.tracker.email.domain.example
846 TO: chef@bork.bork.bork, richard@test.test
847 Content-Type: multipart/mixed; boundary="utf-8"
848 Subject: [issue1] Testing...
849 To: chef@bork.bork.bork, richard@test.test
850 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
851 Reply-To: Roundup issue tracker
852  <issue_tracker@your.tracker.email.domain.example>
853 MIME-Version: 1.0
854 Message-Id: <followup_dummy_id>
855 In-Reply-To: <dummy_test_message_id>
856 X-Roundup-Name: Roundup issue tracker
857 X-Roundup-Loop: hello
858 X-Roundup-Issue-Status: chatting
859 X-Roundup-Issue-Files: unnamed
860 Content-Transfer-Encoding: quoted-printable
863 --utf-8
864 MIME-Version: 1.0
865 Content-Type: text/plain; charset="utf-8"
866 Content-Transfer-Encoding: quoted-printable
869 Contrary, Mary <mary@test.test> added the comment:
871 umlaut =C3=A4=C3=B6=C3=BC=C3=84=C3=96=C3=9C=C3=9F
873 ----------
874 status: unread -> chatting
876 _______________________________________________________________________
877 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
878 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
879 _______________________________________________________________________
880 --utf-8
881 Content-Type: text/html
882 MIME-Version: 1.0
883 Content-Transfer-Encoding: base64
884 Content-Disposition: attachment;
885  filename="unnamed"
887 PGh0bWw+dW1sYXV0IMOkw7bDvMOEw5bDnMOfPC9odG1sPgo=
889 --utf-8--
890 ''')
892     def testMultipartCharsetLatin1AttachFile(self):
893         c = 'umlaut \xc3\xa4\xc3\xb6\xc3\xbc\xc3\x84\xc3\x96\xc3\x9c\xc3\x9f'
894         self.doNewIssue()
895         self.db.config.MAIL_CHARSET = 'iso-8859-1'
896         self._handle_mail(self.multipart_msg_latin1)
897         messages = self.db.issue.get('1', 'messages')
898         messages.sort()
899         msg = self.db.msg.getnode (messages[-1])
900         self.assertEqual(len(msg.files), 1)
901         name = 'unnamed'
902         content = '<html>' + c + '</html>\n'
903         for n, id in enumerate (msg.files):
904             f = self.db.file.getnode (id)
905             self.assertEqual(f.name, name)
906             self.assertEqual(f.content, content)
907         self.assertEqual(msg.content, c)
908         self.compareMessages(self._get_mail(),
909 '''FROM: roundup-admin@your.tracker.email.domain.example
910 TO: chef@bork.bork.bork, richard@test.test
911 Content-Type: multipart/mixed; boundary="utf-8"
912 Subject: [issue1] Testing...
913 To: chef@bork.bork.bork, richard@test.test
914 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
915 Reply-To: Roundup issue tracker
916  <issue_tracker@your.tracker.email.domain.example>
917 MIME-Version: 1.0
918 Message-Id: <followup_dummy_id>
919 In-Reply-To: <dummy_test_message_id>
920 X-Roundup-Name: Roundup issue tracker
921 X-Roundup-Loop: hello
922 X-Roundup-Issue-Status: chatting
923 X-Roundup-Issue-Files: unnamed
924 Content-Transfer-Encoding: quoted-printable
927 --utf-8
928 MIME-Version: 1.0
929 Content-Type: text/plain; charset="iso-8859-1"
930 Content-Transfer-Encoding: quoted-printable
933 Contrary, Mary <mary@test.test> added the comment:
935 umlaut =E4=F6=FC=C4=D6=DC=DF
937 ----------
938 status: unread -> chatting
940 _______________________________________________________________________
941 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
942 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
943 _______________________________________________________________________
944 --utf-8
945 Content-Type: text/html
946 MIME-Version: 1.0
947 Content-Transfer-Encoding: base64
948 Content-Disposition: attachment;
949  filename="unnamed"
951 PGh0bWw+dW1sYXV0IMOkw7bDvMOEw5bDnMOfPC9odG1sPgo=
953 --utf-8--
954 ''')
956     def testMultipartRFC822(self):
957         self.doNewIssue()
958         self._handle_mail(self.multipart_msg_rfc822)
959         messages = self.db.issue.get('1', 'messages')
960         messages.sort()
961         msg = self.db.msg.getnode (messages[-1])
962         self.assertEqual(len(msg.files), 1)
963         name = "Fwd: Original email subject.eml"
964         for n, id in enumerate (msg.files):
965             f = self.db.file.getnode (id)
966             self.assertEqual(f.name, name)
967         self.assertEqual(msg.content, 'First part: Text')
968         self.compareMessages(self._get_mail(),
969 '''TO: chef@bork.bork.bork, richard@test.test
970 Content-Type: text/plain; charset="utf-8"
971 Subject: [issue1] Testing...
972 To: chef@bork.bork.bork, richard@test.test
973 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
974 Reply-To: Roundup issue tracker
975  <issue_tracker@your.tracker.email.domain.example>
976 MIME-Version: 1.0
977 Message-Id: <followup_dummy_id>
978 In-Reply-To: <dummy_test_message_id>
979 X-Roundup-Name: Roundup issue tracker
980 X-Roundup-Loop: hello
981 X-Roundup-Issue-Status: chatting
982 X-Roundup-Issue-Files: Fwd: Original email subject.eml
983 Content-Transfer-Encoding: quoted-printable
986 --utf-8
987 MIME-Version: 1.0
988 Content-Type: text/plain; charset="utf-8"
989 Content-Transfer-Encoding: quoted-printable
992 Contrary, Mary <mary@test.test> added the comment:
994 First part: Text
996 ----------
997 status: unread -> chatting
999 _______________________________________________________________________
1000 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1001 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1002 _______________________________________________________________________
1003 --utf-8
1004 Content-Type: message/rfc822
1005 MIME-Version: 1.0
1006 Content-Disposition: attachment;
1007  filename="Fwd: Original email subject.eml"
1009 Message-Id: <followup_dummy_id_2>
1010 In-Reply-To: <dummy_test_message_id_2>
1011 MIME-Version: 1.0
1012 Subject: Fwd: Original email subject
1013 Date: Mon, 23 Aug 2010 08:23:33 +0200
1014 Content-Type: multipart/alternative; boundary="090500050101020406060002"
1016 This is a multi-part message in MIME format.
1017 --090500050101020406060002
1018 Content-Type: text/plain; charset=ISO-8859-15; format=flowed
1019 Content-Transfer-Encoding: 7bit
1021 some text in inner email
1022 ========================
1024 --090500050101020406060002
1025 Content-Type: text/html; charset=ISO-8859-15
1026 Content-Transfer-Encoding: 7bit
1028 <html>
1029 some text in inner email
1030 ========================
1031 </html>
1033 --090500050101020406060002--
1035 --utf-8--
1036 ''')
1038     def testMultipartRFC822Unpack(self):
1039         self.doNewIssue()
1040         self.db.config.MAILGW_UNPACK_RFC822 = True
1041         self._handle_mail(self.multipart_msg_rfc822)
1042         messages = self.db.issue.get('1', 'messages')
1043         messages.sort()
1044         msg = self.db.msg.getnode (messages[-1])
1045         self.assertEqual(len(msg.files), 2)
1046         t = 'some text in inner email\n========================\n'
1047         content = {0 : t, 1 : '<html>\n' + t + '</html>\n'}
1048         for n, id in enumerate (msg.files):
1049             f = self.db.file.getnode (id)
1050             self.assertEqual(f.name, 'unnamed')
1051             if n in content :
1052                 self.assertEqual(f.content, content [n])
1053         self.assertEqual(msg.content, 'First part: Text')
1055     def testSimpleFollowup(self):
1056         self.doNewIssue()
1057         self._handle_mail('''Content-Type: text/plain;
1058   charset="iso-8859-1"
1059 From: mary <mary@test.test>
1060 To: issue_tracker@your.tracker.email.domain.example
1061 Message-Id: <followup_dummy_id>
1062 In-Reply-To: <dummy_test_message_id>
1063 Subject: [issue1] Testing...
1065 This is a second followup
1066 ''')
1067         self.compareMessages(self._get_mail(),
1068 '''FROM: roundup-admin@your.tracker.email.domain.example
1069 TO: chef@bork.bork.bork, richard@test.test
1070 Content-Type: text/plain; charset="utf-8"
1071 Subject: [issue1] Testing...
1072 To: chef@bork.bork.bork, richard@test.test
1073 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
1074 Reply-To: Roundup issue tracker
1075  <issue_tracker@your.tracker.email.domain.example>
1076 MIME-Version: 1.0
1077 Message-Id: <followup_dummy_id>
1078 In-Reply-To: <dummy_test_message_id>
1079 X-Roundup-Name: Roundup issue tracker
1080 X-Roundup-Loop: hello
1081 X-Roundup-Issue-Status: chatting
1082 Content-Transfer-Encoding: quoted-printable
1085 Contrary, Mary <mary@test.test> added the comment:
1087 This is a second followup
1089 ----------
1090 status: unread -> chatting
1092 _______________________________________________________________________
1093 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1094 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1095 _______________________________________________________________________
1096 ''')
1098     def testFollowup(self):
1099         self.doNewIssue()
1101         self._handle_mail('''Content-Type: text/plain;
1102   charset="iso-8859-1"
1103 From: richard <richard@test.test>
1104 To: issue_tracker@your.tracker.email.domain.example
1105 Message-Id: <followup_dummy_id>
1106 In-Reply-To: <dummy_test_message_id>
1107 Subject: [issue1] Testing... [assignedto=mary; nosy=+john]
1109 This is a followup
1110 ''')
1111         l = self.db.issue.get('1', 'nosy')
1112         l.sort()
1113         self.assertEqual(l, [self.chef_id, self.richard_id, self.mary_id,
1114             self.john_id])
1116         self.compareMessages(self._get_mail(),
1117 '''FROM: roundup-admin@your.tracker.email.domain.example
1118 TO: chef@bork.bork.bork, john@test.test, mary@test.test
1119 Content-Type: text/plain; charset="utf-8"
1120 Subject: [issue1] Testing...
1121 To: chef@bork.bork.bork, john@test.test, mary@test.test
1122 From: richard <issue_tracker@your.tracker.email.domain.example>
1123 Reply-To: Roundup issue tracker
1124  <issue_tracker@your.tracker.email.domain.example>
1125 MIME-Version: 1.0
1126 Message-Id: <followup_dummy_id>
1127 In-Reply-To: <dummy_test_message_id>
1128 X-Roundup-Name: Roundup issue tracker
1129 X-Roundup-Loop: hello
1130 X-Roundup-Issue-Status: chatting
1131 Content-Transfer-Encoding: quoted-printable
1134 richard <richard@test.test> added the comment:
1136 This is a followup
1138 ----------
1139 assignedto:  -> mary
1140 nosy: +john, mary
1141 status: unread -> chatting
1143 _______________________________________________________________________
1144 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1145 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1146 _______________________________________________________________________
1147 ''')
1149     def testFollowupNoSubjectChange(self):
1150         self.db.config.MAILGW_SUBJECT_UPDATES_TITLE = 'no'
1151         self.doNewIssue()
1153         self._handle_mail('''Content-Type: text/plain;
1154   charset="iso-8859-1"
1155 From: richard <richard@test.test>
1156 To: issue_tracker@your.tracker.email.domain.example
1157 Message-Id: <followup_dummy_id>
1158 In-Reply-To: <dummy_test_message_id>
1159 Subject: [issue1] Wrzlbrmft... [assignedto=mary; nosy=+john]
1161 This is a followup
1162 ''')
1163         l = self.db.issue.get('1', 'nosy')
1164         l.sort()
1165         self.assertEqual(l, [self.chef_id, self.richard_id, self.mary_id,
1166             self.john_id])
1168         self.compareMessages(self._get_mail(),
1169 '''FROM: roundup-admin@your.tracker.email.domain.example
1170 TO: chef@bork.bork.bork, john@test.test, mary@test.test
1171 Content-Type: text/plain; charset="utf-8"
1172 Subject: [issue1] Testing...
1173 To: chef@bork.bork.bork, john@test.test, mary@test.test
1174 From: richard <issue_tracker@your.tracker.email.domain.example>
1175 Reply-To: Roundup issue tracker
1176  <issue_tracker@your.tracker.email.domain.example>
1177 MIME-Version: 1.0
1178 Message-Id: <followup_dummy_id>
1179 In-Reply-To: <dummy_test_message_id>
1180 X-Roundup-Name: Roundup issue tracker
1181 X-Roundup-Loop: hello
1182 X-Roundup-Issue-Status: chatting
1183 Content-Transfer-Encoding: quoted-printable
1186 richard <richard@test.test> added the comment:
1188 This is a followup
1190 ----------
1191 assignedto:  -> mary
1192 nosy: +john, mary
1193 status: unread -> chatting
1195 _______________________________________________________________________
1196 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1197 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1198 _______________________________________________________________________
1199 ''')
1200         self.assertEqual(self.db.issue.get('1','title'), 'Testing...')
1202     def testFollowupExplicitSubjectChange(self):
1203         self.doNewIssue()
1205         self._handle_mail('''Content-Type: text/plain;
1206   charset="iso-8859-1"
1207 From: richard <richard@test.test>
1208 To: issue_tracker@your.tracker.email.domain.example
1209 Message-Id: <followup_dummy_id>
1210 In-Reply-To: <dummy_test_message_id>
1211 Subject: [issue1] Wrzlbrmft... [assignedto=mary; nosy=+john; title=new title]
1213 This is a followup
1214 ''')
1215         l = self.db.issue.get('1', 'nosy')
1216         l.sort()
1217         self.assertEqual(l, [self.chef_id, self.richard_id, self.mary_id,
1218             self.john_id])
1220         self.compareMessages(self._get_mail(),
1221 '''FROM: roundup-admin@your.tracker.email.domain.example
1222 TO: chef@bork.bork.bork, john@test.test, mary@test.test
1223 Content-Type: text/plain; charset="utf-8"
1224 Subject: [issue1] new title
1225 To: chef@bork.bork.bork, john@test.test, mary@test.test
1226 From: richard <issue_tracker@your.tracker.email.domain.example>
1227 Reply-To: Roundup issue tracker
1228  <issue_tracker@your.tracker.email.domain.example>
1229 MIME-Version: 1.0
1230 Message-Id: <followup_dummy_id>
1231 In-Reply-To: <dummy_test_message_id>
1232 X-Roundup-Name: Roundup issue tracker
1233 X-Roundup-Loop: hello
1234 X-Roundup-Issue-Status: chatting
1235 Content-Transfer-Encoding: quoted-printable
1238 richard <richard@test.test> added the comment:
1240 This is a followup
1242 ----------
1243 assignedto:  -> mary
1244 nosy: +john, mary
1245 status: unread -> chatting
1246 title: Testing... -> new title
1248 _______________________________________________________________________
1249 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1250 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1251 _______________________________________________________________________
1252 ''')
1254     def testNosyGeneration(self):
1255         self.db.issue.create(title='test')
1257         # create a nosy message
1258         msg = self.db.msg.create(content='This is a test',
1259             author=self.richard_id, messageid='<dummy_test_message_id>')
1260         self.db.journaltag = 'richard'
1261         l = self.db.issue.create(title='test', messages=[msg],
1262             nosy=[self.chef_id, self.mary_id, self.john_id])
1264         self.compareMessages(self._get_mail(),
1265 '''FROM: roundup-admin@your.tracker.email.domain.example
1266 TO: chef@bork.bork.bork, john@test.test, mary@test.test
1267 Content-Type: text/plain; charset="utf-8"
1268 Subject: [issue2] test
1269 To: chef@bork.bork.bork, john@test.test, mary@test.test
1270 From: richard <issue_tracker@your.tracker.email.domain.example>
1271 Reply-To: Roundup issue tracker
1272  <issue_tracker@your.tracker.email.domain.example>
1273 MIME-Version: 1.0
1274 Message-Id: <dummy_test_message_id>
1275 X-Roundup-Name: Roundup issue tracker
1276 X-Roundup-Loop: hello
1277 X-Roundup-Issue-Status: unread
1278 Content-Transfer-Encoding: quoted-printable
1281 New submission from richard <richard@test.test>:
1283 This is a test
1285 ----------
1286 messages: 1
1287 nosy: Chef, john, mary, richard
1288 status: unread
1289 title: test
1291 _______________________________________________________________________
1292 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1293 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue2>
1294 _______________________________________________________________________
1295 ''')
1297     def testPropertyChangeOnly(self):
1298         self.doNewIssue()
1299         oldvalues = self.db.getnode('issue', '1').copy()
1300         oldvalues['assignedto'] = None
1301         # reconstruct old behaviour: This would reuse the
1302         # database-handle from the doNewIssue above which has committed
1303         # as user "Chef". So we close and reopen the db as that user.
1304         #self.db.close() actually don't close 'cos this empties memorydb
1305         self.db = self.instance.open('Chef')
1306         self.db.issue.set('1', assignedto=self.chef_id)
1307         self.db.commit()
1308         self.db.issue.nosymessage('1', None, oldvalues)
1310         new_mail = ""
1311         for line in self._get_mail().split("\n"):
1312             if "Message-Id: " in line:
1313                 continue
1314             if "Date: " in line:
1315                 continue
1316             new_mail += line+"\n"
1318         self.compareMessages(new_mail, """
1319 FROM: roundup-admin@your.tracker.email.domain.example
1320 TO: chef@bork.bork.bork, richard@test.test
1321 Content-Type: text/plain; charset="utf-8"
1322 Subject: [issue1] Testing...
1323 To: chef@bork.bork.bork, richard@test.test
1324 From: "Bork, Chef" <issue_tracker@your.tracker.email.domain.example>
1325 X-Roundup-Name: Roundup issue tracker
1326 X-Roundup-Loop: hello
1327 X-Roundup-Issue-Status: unread
1328 X-Roundup-Version: 1.3.3
1329 In-Reply-To: <dummy_test_message_id>
1330 MIME-Version: 1.0
1331 Reply-To: Roundup issue tracker
1332  <issue_tracker@your.tracker.email.domain.example>
1333 Content-Transfer-Encoding: quoted-printable
1336 Change by Bork, Chef <chef@bork.bork.bork>:
1339 ----------
1340 assignedto:  -> Chef
1342 _______________________________________________________________________
1343 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1344 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1345 _______________________________________________________________________
1346 """)
1349     #
1350     # FOLLOWUP TITLE MATCH
1351     #
1352     def testFollowupTitleMatch(self):
1353         self.doNewIssue()
1354         self._handle_mail('''Content-Type: text/plain;
1355   charset="iso-8859-1"
1356 From: richard <richard@test.test>
1357 To: issue_tracker@your.tracker.email.domain.example
1358 Message-Id: <followup_dummy_id>
1359 Subject: Re: Testing... [assignedto=mary; nosy=+john]
1361 This is a followup
1362 ''')
1363         self.compareMessages(self._get_mail(),
1364 '''FROM: roundup-admin@your.tracker.email.domain.example
1365 TO: chef@bork.bork.bork, john@test.test, mary@test.test
1366 Content-Type: text/plain; charset="utf-8"
1367 Subject: [issue1] Testing...
1368 To: chef@bork.bork.bork, john@test.test, mary@test.test
1369 From: richard <issue_tracker@your.tracker.email.domain.example>
1370 Reply-To: Roundup issue tracker
1371  <issue_tracker@your.tracker.email.domain.example>
1372 MIME-Version: 1.0
1373 Message-Id: <followup_dummy_id>
1374 In-Reply-To: <dummy_test_message_id>
1375 X-Roundup-Name: Roundup issue tracker
1376 X-Roundup-Loop: hello
1377 X-Roundup-Issue-Status: chatting
1378 Content-Transfer-Encoding: quoted-printable
1381 richard <richard@test.test> added the comment:
1383 This is a followup
1385 ----------
1386 assignedto:  -> mary
1387 nosy: +john, mary
1388 status: unread -> chatting
1390 _______________________________________________________________________
1391 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1392 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1393 _______________________________________________________________________
1394 ''')
1396     def testFollowupTitleMatchMultiRe(self):
1397         nodeid1 = self.doNewIssue()
1398         nodeid2 = self._handle_mail('''Content-Type: text/plain;
1399   charset="iso-8859-1"
1400 From: richard <richard@test.test>
1401 To: issue_tracker@your.tracker.email.domain.example
1402 Message-Id: <followup_dummy_id>
1403 Subject: Re: Testing... [assignedto=mary; nosy=+john]
1405 This is a followup
1406 ''')
1408         nodeid3 = self._handle_mail('''Content-Type: text/plain;
1409   charset="iso-8859-1"
1410 From: richard <richard@test.test>
1411 To: issue_tracker@your.tracker.email.domain.example
1412 Message-Id: <followup2_dummy_id>
1413 Subject: Ang: Re: Testing...
1415 This is a followup
1416 ''')
1417         self.assertEqual(nodeid1, nodeid2)
1418         self.assertEqual(nodeid1, nodeid3)
1420     def testFollowupTitleMatchNever(self):
1421         nodeid = self.doNewIssue()
1422         self.db.config.MAILGW_SUBJECT_CONTENT_MATCH = 'never'
1423         self.assertNotEqual(self._handle_mail('''Content-Type: text/plain;
1424   charset="iso-8859-1"
1425 From: richard <richard@test.test>
1426 To: issue_tracker@your.tracker.email.domain.example
1427 Message-Id: <followup_dummy_id>
1428 Subject: Re: Testing...
1430 This is a followup
1431 '''), nodeid)
1433     def testFollowupTitleMatchNeverInterval(self):
1434         nodeid = self.doNewIssue()
1435         # force failure of the interval
1436         time.sleep(2)
1437         self.db.config.MAILGW_SUBJECT_CONTENT_MATCH = 'creation 00:00:01'
1438         self.assertNotEqual(self._handle_mail('''Content-Type: text/plain;
1439   charset="iso-8859-1"
1440 From: richard <richard@test.test>
1441 To: issue_tracker@your.tracker.email.domain.example
1442 Message-Id: <followup_dummy_id>
1443 Subject: Re: Testing...
1445 This is a followup
1446 '''), nodeid)
1449     def testFollowupTitleMatchInterval(self):
1450         nodeid = self.doNewIssue()
1451         self.db.config.MAILGW_SUBJECT_CONTENT_MATCH = 'creation +1d'
1452         self.assertEqual(self._handle_mail('''Content-Type: text/plain;
1453   charset="iso-8859-1"
1454 From: richard <richard@test.test>
1455 To: issue_tracker@your.tracker.email.domain.example
1456 Message-Id: <followup_dummy_id>
1457 Subject: Re: Testing...
1459 This is a followup
1460 '''), nodeid)
1462     simple_followup = '''Content-Type: text/plain;
1463   charset="iso-8859-1"
1464 From: john@test.test
1465 To: issue_tracker@your.tracker.email.domain.example
1466 Message-Id: <followup_dummy_id>
1467 In-Reply-To: <dummy_test_message_id>
1468 Subject: [issue1] Testing...
1470 This is a followup
1471 '''
1473     def testFollowupNosyAuthor(self):
1474         self.doNewIssue()
1475         self.db.config.ADD_AUTHOR_TO_NOSY = 'yes'
1476         self._handle_mail(self.simple_followup)
1477         self.compareMessages(self._get_mail(),
1478 '''FROM: roundup-admin@your.tracker.email.domain.example
1479 TO: chef@bork.bork.bork, richard@test.test
1480 Content-Type: text/plain; charset="utf-8"
1481 Subject: [issue1] Testing...
1482 To: chef@bork.bork.bork, richard@test.test
1483 From: John Doe <issue_tracker@your.tracker.email.domain.example>
1484 Reply-To: Roundup issue tracker
1485  <issue_tracker@your.tracker.email.domain.example>
1486 MIME-Version: 1.0
1487 Message-Id: <followup_dummy_id>
1488 In-Reply-To: <dummy_test_message_id>
1489 X-Roundup-Name: Roundup issue tracker
1490 X-Roundup-Loop: hello
1491 X-Roundup-Issue-Status: chatting
1492 Content-Transfer-Encoding: quoted-printable
1495 John Doe <john@test.test> added the comment:
1497 This is a followup
1499 ----------
1500 nosy: +john
1501 status: unread -> chatting
1503 _______________________________________________________________________
1504 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1505 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1506 _______________________________________________________________________
1508 ''')
1510     def testFollowupNosyRecipients(self):
1511         self.doNewIssue()
1512         self.db.config.ADD_RECIPIENTS_TO_NOSY = 'yes'
1513         self._handle_mail('''Content-Type: text/plain;
1514  charset="iso-8859-1"
1515 From: richard@test.test
1516 To: issue_tracker@your.tracker.email.domain.example
1517 Cc: john@test.test
1518 Message-Id: <followup_dummy_id>
1519 In-Reply-To: <dummy_test_message_id>
1520 Subject: [issue1] Testing...
1522 This is a followup
1523 ''')
1524         self.compareMessages(self._get_mail(),
1525 '''FROM: roundup-admin@your.tracker.email.domain.example
1526 TO: chef@bork.bork.bork
1527 Content-Type: text/plain; charset="utf-8"
1528 Subject: [issue1] Testing...
1529 To: chef@bork.bork.bork
1530 From: richard <issue_tracker@your.tracker.email.domain.example>
1531 Reply-To: Roundup issue tracker
1532  <issue_tracker@your.tracker.email.domain.example>
1533 MIME-Version: 1.0
1534 Message-Id: <followup_dummy_id>
1535 In-Reply-To: <dummy_test_message_id>
1536 X-Roundup-Name: Roundup issue tracker
1537 X-Roundup-Loop: hello
1538 X-Roundup-Issue-Status: chatting
1539 Content-Transfer-Encoding: quoted-printable
1542 richard <richard@test.test> added the comment:
1544 This is a followup
1546 ----------
1547 nosy: +john
1548 status: unread -> chatting
1550 _______________________________________________________________________
1551 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1552 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1553 _______________________________________________________________________
1555 ''')
1557     def testFollowupNosyAuthorAndCopy(self):
1558         self.doNewIssue()
1559         self.db.config.ADD_AUTHOR_TO_NOSY = 'yes'
1560         self.db.config.MESSAGES_TO_AUTHOR = 'yes'
1561         self._handle_mail(self.simple_followup)
1562         self.compareMessages(self._get_mail(),
1563 '''FROM: roundup-admin@your.tracker.email.domain.example
1564 TO: chef@bork.bork.bork, john@test.test, richard@test.test
1565 Content-Type: text/plain; charset="utf-8"
1566 Subject: [issue1] Testing...
1567 To: chef@bork.bork.bork, john@test.test, richard@test.test
1568 From: John Doe <issue_tracker@your.tracker.email.domain.example>
1569 Reply-To: Roundup issue tracker
1570  <issue_tracker@your.tracker.email.domain.example>
1571 MIME-Version: 1.0
1572 Message-Id: <followup_dummy_id>
1573 In-Reply-To: <dummy_test_message_id>
1574 X-Roundup-Name: Roundup issue tracker
1575 X-Roundup-Loop: hello
1576 X-Roundup-Issue-Status: chatting
1577 Content-Transfer-Encoding: quoted-printable
1580 John Doe <john@test.test> added the comment:
1582 This is a followup
1584 ----------
1585 nosy: +john
1586 status: unread -> chatting
1588 _______________________________________________________________________
1589 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1590 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1591 _______________________________________________________________________
1593 ''')
1595     def testFollowupNosyAuthorNosyCopy(self):
1596         self.doNewIssue()
1597         self.db.config.ADD_AUTHOR_TO_NOSY = 'yes'
1598         self.db.config.MESSAGES_TO_AUTHOR = 'nosy'
1599         self._handle_mail(self.simple_followup)
1600         self.compareMessages(self._get_mail(),
1601 '''FROM: roundup-admin@your.tracker.email.domain.example
1602 TO: chef@bork.bork.bork, john@test.test, richard@test.test
1603 Content-Type: text/plain; charset="utf-8"
1604 Subject: [issue1] Testing...
1605 To: chef@bork.bork.bork, john@test.test, richard@test.test
1606 From: John Doe <issue_tracker@your.tracker.email.domain.example>
1607 Reply-To: Roundup issue tracker
1608  <issue_tracker@your.tracker.email.domain.example>
1609 MIME-Version: 1.0
1610 Message-Id: <followup_dummy_id>
1611 In-Reply-To: <dummy_test_message_id>
1612 X-Roundup-Name: Roundup issue tracker
1613 X-Roundup-Loop: hello
1614 X-Roundup-Issue-Status: chatting
1615 Content-Transfer-Encoding: quoted-printable
1618 John Doe <john@test.test> added the comment:
1620 This is a followup
1622 ----------
1623 nosy: +john
1624 status: unread -> chatting
1626 _______________________________________________________________________
1627 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1628 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1629 _______________________________________________________________________
1631 ''')
1633     def testFollowupNoNosyAuthor(self):
1634         self.doNewIssue()
1635         self.instance.config.ADD_AUTHOR_TO_NOSY = 'no'
1636         self._handle_mail(self.simple_followup)
1637         self.compareMessages(self._get_mail(),
1638 '''FROM: roundup-admin@your.tracker.email.domain.example
1639 TO: chef@bork.bork.bork, richard@test.test
1640 Content-Type: text/plain; charset="utf-8"
1641 Subject: [issue1] Testing...
1642 To: chef@bork.bork.bork, richard@test.test
1643 From: John Doe <issue_tracker@your.tracker.email.domain.example>
1644 Reply-To: Roundup issue tracker
1645  <issue_tracker@your.tracker.email.domain.example>
1646 MIME-Version: 1.0
1647 Message-Id: <followup_dummy_id>
1648 In-Reply-To: <dummy_test_message_id>
1649 X-Roundup-Name: Roundup issue tracker
1650 X-Roundup-Loop: hello
1651 X-Roundup-Issue-Status: chatting
1652 Content-Transfer-Encoding: quoted-printable
1655 John Doe <john@test.test> added the comment:
1657 This is a followup
1659 ----------
1660 status: unread -> chatting
1662 _______________________________________________________________________
1663 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1664 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1665 _______________________________________________________________________
1667 ''')
1669     def testFollowupNoNosyAuthorNoCopy(self):
1670         self.doNewIssue()
1671         self.instance.config.ADD_AUTHOR_TO_NOSY = 'no'
1672         self.instance.config.MESSAGES_TO_AUTHOR = 'nosy'
1673         self._handle_mail(self.simple_followup)
1674         self.compareMessages(self._get_mail(),
1675 '''FROM: roundup-admin@your.tracker.email.domain.example
1676 TO: chef@bork.bork.bork, richard@test.test
1677 Content-Type: text/plain; charset="utf-8"
1678 Subject: [issue1] Testing...
1679 To: chef@bork.bork.bork, richard@test.test
1680 From: John Doe <issue_tracker@your.tracker.email.domain.example>
1681 Reply-To: Roundup issue tracker
1682  <issue_tracker@your.tracker.email.domain.example>
1683 MIME-Version: 1.0
1684 Message-Id: <followup_dummy_id>
1685 In-Reply-To: <dummy_test_message_id>
1686 X-Roundup-Name: Roundup issue tracker
1687 X-Roundup-Loop: hello
1688 X-Roundup-Issue-Status: chatting
1689 Content-Transfer-Encoding: quoted-printable
1692 John Doe <john@test.test> added the comment:
1694 This is a followup
1696 ----------
1697 status: unread -> chatting
1699 _______________________________________________________________________
1700 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1701 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1702 _______________________________________________________________________
1704 ''')
1706     # this is a pathological case where the author is *not* on the nosy
1707     # list but gets the message; test documents existing behaviour
1708     def testFollowupNoNosyAuthorButCopy(self):
1709         self.doNewIssue()
1710         self.instance.config.ADD_AUTHOR_TO_NOSY = 'no'
1711         self.instance.config.MESSAGES_TO_AUTHOR = 'yes'
1712         self._handle_mail(self.simple_followup)
1713         self.compareMessages(self._get_mail(),
1714 '''FROM: roundup-admin@your.tracker.email.domain.example
1715 TO: chef@bork.bork.bork, john@test.test, richard@test.test
1716 Content-Type: text/plain; charset="utf-8"
1717 Subject: [issue1] Testing...
1718 To: chef@bork.bork.bork, john@test.test, richard@test.test
1719 From: John Doe <issue_tracker@your.tracker.email.domain.example>
1720 Reply-To: Roundup issue tracker
1721  <issue_tracker@your.tracker.email.domain.example>
1722 MIME-Version: 1.0
1723 Message-Id: <followup_dummy_id>
1724 In-Reply-To: <dummy_test_message_id>
1725 X-Roundup-Name: Roundup issue tracker
1726 X-Roundup-Loop: hello
1727 X-Roundup-Issue-Status: chatting
1728 Content-Transfer-Encoding: quoted-printable
1731 John Doe <john@test.test> added the comment:
1733 This is a followup
1735 ----------
1736 status: unread -> chatting
1738 _______________________________________________________________________
1739 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1740 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1741 _______________________________________________________________________
1743 ''')
1745     def testFollowupNoNosyRecipients(self):
1746         self.doNewIssue()
1747         self.instance.config.ADD_RECIPIENTS_TO_NOSY = 'no'
1748         self._handle_mail('''Content-Type: text/plain;
1749   charset="iso-8859-1"
1750 From: richard@test.test
1751 To: issue_tracker@your.tracker.email.domain.example
1752 Cc: john@test.test
1753 Message-Id: <followup_dummy_id>
1754 In-Reply-To: <dummy_test_message_id>
1755 Subject: [issue1] Testing...
1757 This is a followup
1758 ''')
1759         self.compareMessages(self._get_mail(),
1760 '''FROM: roundup-admin@your.tracker.email.domain.example
1761 TO: chef@bork.bork.bork
1762 Content-Type: text/plain; charset="utf-8"
1763 Subject: [issue1] Testing...
1764 To: chef@bork.bork.bork
1765 From: richard <issue_tracker@your.tracker.email.domain.example>
1766 Reply-To: Roundup issue tracker
1767  <issue_tracker@your.tracker.email.domain.example>
1768 MIME-Version: 1.0
1769 Message-Id: <followup_dummy_id>
1770 In-Reply-To: <dummy_test_message_id>
1771 X-Roundup-Name: Roundup issue tracker
1772 X-Roundup-Loop: hello
1773 X-Roundup-Issue-Status: chatting
1774 Content-Transfer-Encoding: quoted-printable
1777 richard <richard@test.test> added the comment:
1779 This is a followup
1781 ----------
1782 status: unread -> chatting
1784 _______________________________________________________________________
1785 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1786 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1787 _______________________________________________________________________
1789 ''')
1791     def testFollowupEmptyMessage(self):
1792         self.doNewIssue()
1794         self._handle_mail('''Content-Type: text/plain;
1795   charset="iso-8859-1"
1796 From: richard <richard@test.test>
1797 To: issue_tracker@your.tracker.email.domain.example
1798 Message-Id: <followup_dummy_id>
1799 In-Reply-To: <dummy_test_message_id>
1800 Subject: [issue1] Testing... [assignedto=mary; nosy=+john]
1802 ''')
1803         l = self.db.issue.get('1', 'nosy')
1804         l.sort()
1805         self.assertEqual(l, [self.chef_id, self.richard_id, self.mary_id,
1806             self.john_id])
1808         # should be no file created (ie. no message)
1809         assert not os.path.exists(SENDMAILDEBUG)
1811     def testFollowupEmptyMessageNoSubject(self):
1812         self.doNewIssue()
1814         self._handle_mail('''Content-Type: text/plain;
1815   charset="iso-8859-1"
1816 From: richard <richard@test.test>
1817 To: issue_tracker@your.tracker.email.domain.example
1818 Message-Id: <followup_dummy_id>
1819 In-Reply-To: <dummy_test_message_id>
1820 Subject: [issue1] [assignedto=mary; nosy=+john]
1822 ''')
1823         l = self.db.issue.get('1', 'nosy')
1824         l.sort()
1825         self.assertEqual(l, [self.chef_id, self.richard_id, self.mary_id,
1826             self.john_id])
1828         # should be no file created (ie. no message)
1829         assert not os.path.exists(SENDMAILDEBUG)
1831     def testNosyRemove(self):
1832         self.doNewIssue()
1834         self._handle_mail('''Content-Type: text/plain;
1835   charset="iso-8859-1"
1836 From: richard <richard@test.test>
1837 To: issue_tracker@your.tracker.email.domain.example
1838 Message-Id: <followup_dummy_id>
1839 In-Reply-To: <dummy_test_message_id>
1840 Subject: [issue1] Testing... [nosy=-richard]
1842 ''')
1843         l = self.db.issue.get('1', 'nosy')
1844         l.sort()
1845         self.assertEqual(l, [self.chef_id])
1847         # NO NOSY MESSAGE SHOULD BE SENT!
1848         assert not os.path.exists(SENDMAILDEBUG)
1850     def testNewUserAuthor(self):
1851         self.db.commit()
1852         l = self.db.user.list()
1853         l.sort()
1854         message = '''Content-Type: text/plain;
1855   charset="iso-8859-1"
1856 From: fubar <fubar@bork.bork.bork>
1857 To: issue_tracker@your.tracker.email.domain.example
1858 Message-Id: <dummy_test_message_id>
1859 Subject: [issue] Testing...
1861 This is a test submission of a new issue.
1862 '''
1863         self.db.security.role['anonymous'].permissions=[]
1864         anonid = self.db.user.lookup('anonymous')
1865         self.db.user.set(anonid, roles='Anonymous')
1866         try:
1867             self._handle_mail(message)
1868         except Unauthorized, value:
1869             body_diff = self.compareMessages(str(value), """
1870 You are not a registered user.
1872 Unknown address: fubar@bork.bork.bork
1873 """)
1874             assert not body_diff, body_diff
1875         else:
1876             raise AssertionError, "Unathorized not raised when handling mail"
1878         # Add Web Access role to anonymous, and try again to make sure
1879         # we get a "please register at:" message this time.
1880         p = [
1881             self.db.security.getPermission('Register', 'user'),
1882             self.db.security.getPermission('Web Access', None),
1883         ]
1884         self.db.security.role['anonymous'].permissions=p
1885         try:
1886             self._handle_mail(message)
1887         except Unauthorized, value:
1888             body_diff = self.compareMessages(str(value), """
1889 You are not a registered user. Please register at:
1891 http://tracker.example/cgi-bin/roundup.cgi/bugs/user?template=register
1893 ...before sending mail to the tracker.
1895 Unknown address: fubar@bork.bork.bork
1896 """)
1897             assert not body_diff, body_diff
1898         else:
1899             raise AssertionError, "Unauthorized not raised when handling mail"
1901         # Make sure list of users is the same as before.
1902         m = self.db.user.list()
1903         m.sort()
1904         self.assertEqual(l, m)
1906         # now with the permission
1907         p = [
1908             self.db.security.getPermission('Register', 'user'),
1909             self.db.security.getPermission('Email Access', None),
1910         ]
1911         self.db.security.role['anonymous'].permissions=p
1912         self._handle_mail(message)
1913         m = self.db.user.list()
1914         m.sort()
1915         self.assertNotEqual(l, m)
1917     def testNewUserAuthorEncodedName(self):
1918         l = set(self.db.user.list())
1919         # From: name has Euro symbol in it
1920         message = '''Content-Type: text/plain;
1921   charset="iso-8859-1"
1922 From: =?utf8?b?SOKCrGxsbw==?= <fubar@bork.bork.bork>
1923 To: issue_tracker@your.tracker.email.domain.example
1924 Message-Id: <dummy_test_message_id>
1925 Subject: [issue] Testing...
1927 This is a test submission of a new issue.
1928 '''
1929         p = [
1930             self.db.security.getPermission('Register', 'user'),
1931             self.db.security.getPermission('Email Access', None),
1932             self.db.security.getPermission('Create', 'issue'),
1933             self.db.security.getPermission('Create', 'msg'),
1934         ]
1935         self.db.security.role['anonymous'].permissions = p
1936         self._handle_mail(message)
1937         m = set(self.db.user.list())
1938         new = list(m - l)[0]
1939         name = self.db.user.get(new, 'realname')
1940         self.assertEquals(name, 'H€llo')
1942     def testNewUserAuthorMixedEncodedName(self):
1943         l = set(self.db.user.list())
1944         # From: name has Euro symbol in it
1945         message = '''Content-Type: text/plain;
1946   charset="iso-8859-1"
1947 From: Firstname =?utf-8?b?w6TDtsOf?= Last <fubar@bork.bork.bork>
1948 To: issue_tracker@your.tracker.email.domain.example
1949 Message-Id: <dummy_test_message_id>
1950 Subject: [issue] Test =?utf-8?b?w4TDlsOc?= umlauts
1951  X1
1952  X2
1954 This is a test submission of a new issue.
1955 '''
1956         p = [
1957             self.db.security.getPermission('Register', 'user'),
1958             self.db.security.getPermission('Email Access', None),
1959             self.db.security.getPermission('Create', 'issue'),
1960             self.db.security.getPermission('Create', 'msg'),
1961         ]
1962         self.db.security.role['anonymous'].permissions = p
1963         self._handle_mail(message)
1964         title = self.db.issue.get('1', 'title')
1965         self.assertEquals(title, 'Test \xc3\x84\xc3\x96\xc3\x9c umlauts X1 X2')
1966         m = set(self.db.user.list())
1967         new = list(m - l)[0]
1968         name = self.db.user.get(new, 'realname')
1969         self.assertEquals(name, 'Firstname \xc3\xa4\xc3\xb6\xc3\x9f Last')
1971     def testUnknownUser(self):
1972         l = set(self.db.user.list())
1973         message = '''Content-Type: text/plain;
1974   charset="iso-8859-1"
1975 From: Nonexisting User <nonexisting@bork.bork.bork>
1976 To: issue_tracker@your.tracker.email.domain.example
1977 Message-Id: <dummy_test_message_id>
1978 Subject: [issue] Testing nonexisting user...
1980 This is a test submission of a new issue.
1981 '''
1982         # trap_exc=1: we want a bounce message:
1983         ret = self._handle_mail(message, trap_exc=1)
1984         self.compareMessages(self._get_mail(),
1985 '''FROM: Roundup issue tracker <roundup-admin@your.tracker.email.domain.example>
1986 TO: nonexisting@bork.bork.bork
1987 From nobody Tue Jul 14 12:04:11 2009
1988 Content-Type: multipart/mixed; boundary="===============0639262320=="
1989 MIME-Version: 1.0
1990 Subject: Failed issue tracker submission
1991 To: nonexisting@bork.bork.bork
1992 From: Roundup issue tracker <roundup-admin@your.tracker.email.domain.example>
1993 Date: Tue, 14 Jul 2009 12:04:11 +0000
1994 Precedence: bulk
1995 X-Roundup-Name: Roundup issue tracker
1996 X-Roundup-Loop: hello
1997 X-Roundup-Version: 1.4.8
1998 MIME-Version: 1.0
2000 --===============0639262320==
2001 Content-Type: text/plain; charset="us-ascii"
2002 MIME-Version: 1.0
2003 Content-Transfer-Encoding: 7bit
2007 You are not a registered user. Please register at:
2009 http://tracker.example/cgi-bin/roundup.cgi/bugs/user?template=register
2011 ...before sending mail to the tracker.
2013 Unknown address: nonexisting@bork.bork.bork
2015 --===============0639262320==
2016 Content-Type: text/plain; charset="us-ascii"
2017 MIME-Version: 1.0
2018 Content-Transfer-Encoding: 7bit
2020 Content-Type: text/plain;
2021   charset="iso-8859-1"
2022 From: Nonexisting User <nonexisting@bork.bork.bork>
2023 To: issue_tracker@your.tracker.email.domain.example
2024 Message-Id: <dummy_test_message_id>
2025 Subject: [issue] Testing nonexisting user...
2027 This is a test submission of a new issue.
2029 --===============0639262320==--
2030 ''')
2032     def testEnc01(self):
2033         self.db.user.set(self.mary_id,
2034             realname='\xe4\xf6\xfc\xc4\xd6\xdc\xdf, Mary'.decode
2035             ('latin-1').encode('utf-8'))
2036         self.doNewIssue()
2037         self._handle_mail('''Content-Type: text/plain;
2038   charset="iso-8859-1"
2039 From: mary <mary@test.test>
2040 To: issue_tracker@your.tracker.email.domain.example
2041 Message-Id: <followup_dummy_id>
2042 In-Reply-To: <dummy_test_message_id>
2043 Subject: [issue1] Testing...
2044 Content-Type: text/plain;
2045         charset="iso-8859-1"
2046 Content-Transfer-Encoding: quoted-printable
2048 A message with encoding (encoded oe =F6)
2050 ''')
2051         self.compareMessages(self._get_mail(),
2052 '''FROM: roundup-admin@your.tracker.email.domain.example
2053 TO: chef@bork.bork.bork, richard@test.test
2054 Content-Type: text/plain; charset="utf-8"
2055 Subject: [issue1] Testing...
2056 To: chef@bork.bork.bork, richard@test.test
2057 From: =?utf-8?b?w6TDtsO8w4TDlsOcw58sIE1hcnk=?=
2058  <issue_tracker@your.tracker.email.domain.example>
2059 Reply-To: Roundup issue tracker
2060  <issue_tracker@your.tracker.email.domain.example>
2061 MIME-Version: 1.0
2062 Message-Id: <followup_dummy_id>
2063 In-Reply-To: <dummy_test_message_id>
2064 X-Roundup-Name: Roundup issue tracker
2065 X-Roundup-Loop: hello
2066 X-Roundup-Issue-Status: chatting
2067 Content-Transfer-Encoding: quoted-printable
2070 =C3=A4=C3=B6=C3=BC=C3=84=C3=96=C3=9C=C3=9F, Mary <mary@test.test> added the=
2071  comment:
2073 A message with encoding (encoded oe =C3=B6)
2075 ----------
2076 status: unread -> chatting
2078 _______________________________________________________________________
2079 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
2080 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
2081 _______________________________________________________________________
2082 ''')
2084     def testEncNonUTF8(self):
2085         self.doNewIssue()
2086         self.instance.config.EMAIL_CHARSET = 'iso-8859-1'
2087         self._handle_mail('''Content-Type: text/plain;
2088   charset="iso-8859-1"
2089 From: mary <mary@test.test>
2090 To: issue_tracker@your.tracker.email.domain.example
2091 Message-Id: <followup_dummy_id>
2092 In-Reply-To: <dummy_test_message_id>
2093 Subject: [issue1] Testing...
2094 Content-Type: text/plain;
2095         charset="iso-8859-1"
2096 Content-Transfer-Encoding: quoted-printable
2098 A message with encoding (encoded oe =F6)
2100 ''')
2101         self.compareMessages(self._get_mail(),
2102 '''FROM: roundup-admin@your.tracker.email.domain.example
2103 TO: chef@bork.bork.bork, richard@test.test
2104 Content-Type: text/plain; charset="iso-8859-1"
2105 Subject: [issue1] Testing...
2106 To: chef@bork.bork.bork, richard@test.test
2107 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
2108 Reply-To: Roundup issue tracker
2109  <issue_tracker@your.tracker.email.domain.example>
2110 MIME-Version: 1.0
2111 Message-Id: <followup_dummy_id>
2112 In-Reply-To: <dummy_test_message_id>
2113 X-Roundup-Name: Roundup issue tracker
2114 X-Roundup-Loop: hello
2115 X-Roundup-Issue-Status: chatting
2116 Content-Transfer-Encoding: quoted-printable
2119 Contrary, Mary <mary@test.test> added the comment:
2121 A message with encoding (encoded oe =F6)
2123 ----------
2124 status: unread -> chatting
2126 _______________________________________________________________________
2127 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
2128 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
2129 _______________________________________________________________________
2130 ''')
2133     def testMultipartEnc01(self):
2134         self.doNewIssue()
2135         self._handle_mail('''Content-Type: text/plain;
2136   charset="iso-8859-1"
2137 From: mary <mary@test.test>
2138 To: issue_tracker@your.tracker.email.domain.example
2139 Message-Id: <followup_dummy_id>
2140 In-Reply-To: <dummy_test_message_id>
2141 Subject: [issue1] Testing...
2142 Content-Type: multipart/mixed;
2143         boundary="----_=_NextPart_000_01"
2145 This message is in MIME format. Since your mail reader does not understand
2146 this format, some or all of this message may not be legible.
2148 ------_=_NextPart_000_01
2149 Content-Type: text/plain;
2150         charset="iso-8859-1"
2151 Content-Transfer-Encoding: quoted-printable
2153 A message with first part encoded (encoded oe =F6)
2155 ''')
2156         self.compareMessages(self._get_mail(),
2157 '''FROM: roundup-admin@your.tracker.email.domain.example
2158 TO: chef@bork.bork.bork, richard@test.test
2159 Content-Type: text/plain; charset="utf-8"
2160 Subject: [issue1] Testing...
2161 To: chef@bork.bork.bork, richard@test.test
2162 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
2163 Reply-To: Roundup issue tracker
2164  <issue_tracker@your.tracker.email.domain.example>
2165 MIME-Version: 1.0
2166 Message-Id: <followup_dummy_id>
2167 In-Reply-To: <dummy_test_message_id>
2168 X-Roundup-Name: Roundup issue tracker
2169 X-Roundup-Loop: hello
2170 X-Roundup-Issue-Status: chatting
2171 Content-Transfer-Encoding: quoted-printable
2174 Contrary, Mary <mary@test.test> added the comment:
2176 A message with first part encoded (encoded oe =C3=B6)
2178 ----------
2179 status: unread -> chatting
2181 _______________________________________________________________________
2182 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
2183 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
2184 _______________________________________________________________________
2185 ''')
2187     def testContentDisposition(self):
2188         self.doNewIssue()
2189         self._handle_mail('''Content-Type: text/plain;
2190   charset="iso-8859-1"
2191 From: mary <mary@test.test>
2192 To: issue_tracker@your.tracker.email.domain.example
2193 Message-Id: <followup_dummy_id>
2194 In-Reply-To: <dummy_test_message_id>
2195 Subject: [issue1] Testing...
2196 Content-Type: multipart/mixed; boundary="bCsyhTFzCvuiizWE"
2197 Content-Disposition: inline
2200 --bCsyhTFzCvuiizWE
2201 Content-Type: text/plain; charset=us-ascii
2202 Content-Disposition: inline
2204 test attachment binary
2206 --bCsyhTFzCvuiizWE
2207 Content-Type: application/octet-stream
2208 Content-Disposition: attachment; filename="main.dvi"
2209 Content-Transfer-Encoding: base64
2211 SnVzdCBhIHRlc3QgAQo=
2213 --bCsyhTFzCvuiizWE--
2214 ''')
2215         messages = self.db.issue.get('1', 'messages')
2216         messages.sort()
2217         file = self.db.file.getnode (self.db.msg.get(messages[-1], 'files')[0])
2218         self.assertEqual(file.name, 'main.dvi')
2219         self.assertEqual(file.content, 'Just a test \001\n')
2221     def testFollowupStupidQuoting(self):
2222         self.doNewIssue()
2224         self._handle_mail('''Content-Type: text/plain;
2225   charset="iso-8859-1"
2226 From: richard <richard@test.test>
2227 To: issue_tracker@your.tracker.email.domain.example
2228 Message-Id: <followup_dummy_id>
2229 In-Reply-To: <dummy_test_message_id>
2230 Subject: Re: "[issue1] Testing... "
2232 This is a followup
2233 ''')
2234         self.compareMessages(self._get_mail(),
2235 '''FROM: roundup-admin@your.tracker.email.domain.example
2236 TO: chef@bork.bork.bork
2237 Content-Type: text/plain; charset="utf-8"
2238 Subject: [issue1] Testing...
2239 To: chef@bork.bork.bork
2240 From: richard <issue_tracker@your.tracker.email.domain.example>
2241 Reply-To: Roundup issue tracker
2242  <issue_tracker@your.tracker.email.domain.example>
2243 MIME-Version: 1.0
2244 Message-Id: <followup_dummy_id>
2245 In-Reply-To: <dummy_test_message_id>
2246 X-Roundup-Name: Roundup issue tracker
2247 X-Roundup-Loop: hello
2248 X-Roundup-Issue-Status: chatting
2249 Content-Transfer-Encoding: quoted-printable
2252 richard <richard@test.test> added the comment:
2254 This is a followup
2256 ----------
2257 status: unread -> chatting
2259 _______________________________________________________________________
2260 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
2261 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
2262 _______________________________________________________________________
2263 ''')
2265     def testEmailQuoting(self):
2266         self.instance.config.EMAIL_KEEP_QUOTED_TEXT = 'no'
2267         self.innerTestQuoting('''This is a followup
2268 ''')
2270     def testEmailQuotingRemove(self):
2271         self.instance.config.EMAIL_KEEP_QUOTED_TEXT = 'yes'
2272         self.innerTestQuoting('''Blah blah wrote:
2273 > Blah bklaskdfj sdf asdf jlaskdf skj sdkfjl asdf
2274 >  skdjlkjsdfalsdkfjasdlfkj dlfksdfalksd fj
2277 This is a followup
2278 ''')
2280     def innerTestQuoting(self, expect):
2281         nodeid = self.doNewIssue()
2283         messages = self.db.issue.get(nodeid, 'messages')
2285         self._handle_mail('''Content-Type: text/plain;
2286   charset="iso-8859-1"
2287 From: richard <richard@test.test>
2288 To: issue_tracker@your.tracker.email.domain.example
2289 Message-Id: <followup_dummy_id>
2290 In-Reply-To: <dummy_test_message_id>
2291 Subject: Re: [issue1] Testing...
2293 Blah blah wrote:
2294 > Blah bklaskdfj sdf asdf jlaskdf skj sdkfjl asdf
2295 >  skdjlkjsdfalsdkfjasdlfkj dlfksdfalksd fj
2298 This is a followup
2299 ''')
2300         # figure the new message id
2301         newmessages = self.db.issue.get(nodeid, 'messages')
2302         for msg in messages:
2303             newmessages.remove(msg)
2304         messageid = newmessages[0]
2306         self.compareMessages(self.db.msg.get(messageid, 'content'), expect)
2308     def testUserLookup(self):
2309         i = self.db.user.create(username='user1', address='user1@foo.com')
2310         self.assertEqual(uidFromAddress(self.db, ('', 'user1@foo.com'), 0), i)
2311         self.assertEqual(uidFromAddress(self.db, ('', 'USER1@foo.com'), 0), i)
2312         i = self.db.user.create(username='user2', address='USER2@foo.com')
2313         self.assertEqual(uidFromAddress(self.db, ('', 'USER2@foo.com'), 0), i)
2314         self.assertEqual(uidFromAddress(self.db, ('', 'user2@foo.com'), 0), i)
2316     def testUserAlternateLookup(self):
2317         i = self.db.user.create(username='user1', address='user1@foo.com',
2318                                 alternate_addresses='user1@bar.com')
2319         self.assertEqual(uidFromAddress(self.db, ('', 'user1@bar.com'), 0), i)
2320         self.assertEqual(uidFromAddress(self.db, ('', 'USER1@bar.com'), 0), i)
2322     def testUserAlternateSubstringNomatch(self):
2323         i = self.db.user.create(username='user1', address='user1@foo.com',
2324                                 alternate_addresses='x-user1@bar.com')
2325         self.assertEqual(uidFromAddress(self.db, ('', 'user1@bar.com'), 0), 0)
2326         self.assertEqual(uidFromAddress(self.db, ('', 'USER1@bar.com'), 0), 0)
2328     def testUserCreate(self):
2329         i = uidFromAddress(self.db, ('', 'user@foo.com'), 1)
2330         self.assertNotEqual(uidFromAddress(self.db, ('', 'user@bar.com'), 1), i)
2332     def testRFC2822(self):
2333         ascii_header = "[issue243] This is a \"test\" - with 'quotation' marks"
2334         unicode_header = '[issue244] \xd0\xb0\xd0\xbd\xd0\xb4\xd1\x80\xd0\xb5\xd0\xb9'
2335         unicode_encoded = '=?utf-8?q?[issue244]_=D0=B0=D0=BD=D0=B4=D1=80=D0=B5=D0=B9?='
2336         self.assertEqual(rfc2822.encode_header(ascii_header), ascii_header)
2337         self.assertEqual(rfc2822.encode_header(unicode_header), unicode_encoded)
2339     def testRegistrationConfirmation(self):
2340         otk = "Aj4euk4LZSAdwePohj90SME5SpopLETL"
2341         self.db.getOTKManager().set(otk, username='johannes')
2342         self._handle_mail('''Content-Type: text/plain;
2343   charset="iso-8859-1"
2344 From: Chef <chef@bork.bork.bork>
2345 To: issue_tracker@your.tracker.email.domain.example
2346 Cc: richard@test.test
2347 Message-Id: <dummy_test_message_id>
2348 Subject: Re: Complete your registration to Roundup issue tracker
2349  -- key %s
2351 This is a test confirmation of registration.
2352 ''' % otk)
2353         self.db.user.lookup('johannes')
2355     def testFollowupOnNonIssue(self):
2356         self.db.keyword.create(name='Foo')
2357         self._handle_mail('''Content-Type: text/plain;
2358   charset="iso-8859-1"
2359 From: richard <richard@test.test>
2360 To: issue_tracker@your.tracker.email.domain.example
2361 Message-Id: <followup_dummy_id>
2362 In-Reply-To: <dummy_test_message_id>
2363 Subject: [keyword1] Testing... [name=Bar]
2365 ''')
2366         self.assertEqual(self.db.keyword.get('1', 'name'), 'Bar')
2368     def testResentFrom(self):
2369         nodeid = self._handle_mail('''Content-Type: text/plain;
2370   charset="iso-8859-1"
2371 From: Chef <chef@bork.bork.bork>
2372 Resent-From: mary <mary@test.test>
2373 To: issue_tracker@your.tracker.email.domain.example
2374 Cc: richard@test.test
2375 Message-Id: <dummy_test_message_id>
2376 Subject: [issue] Testing...
2378 This is a test submission of a new issue.
2379 ''')
2380         assert not os.path.exists(SENDMAILDEBUG)
2381         l = self.db.issue.get(nodeid, 'nosy')
2382         l.sort()
2383         self.assertEqual(l, [self.richard_id, self.mary_id])
2384         return nodeid
2386     def testDejaVu(self):
2387         self.assertRaises(IgnoreLoop, self._handle_mail,
2388             '''Content-Type: text/plain;
2389   charset="iso-8859-1"
2390 From: Chef <chef@bork.bork.bork>
2391 X-Roundup-Loop: hello
2392 To: issue_tracker@your.tracker.email.domain.example
2393 Cc: richard@test.test
2394 Message-Id: <dummy_test_message_id>
2395 Subject: Re: [issue] Testing...
2397 Hi, I've been mis-configured to loop messages back to myself.
2398 ''')
2400     def testItsBulkStupid(self):
2401         self.assertRaises(IgnoreBulk, self._handle_mail,
2402             '''Content-Type: text/plain;
2403   charset="iso-8859-1"
2404 From: Chef <chef@bork.bork.bork>
2405 Precedence: bulk
2406 To: issue_tracker@your.tracker.email.domain.example
2407 Cc: richard@test.test
2408 Message-Id: <dummy_test_message_id>
2409 Subject: Re: [issue] Testing...
2411 Hi, I'm on holidays, and this is a dumb auto-responder.
2412 ''')
2414     def testAutoReplyEmailsAreIgnored(self):
2415         self.assertRaises(IgnoreBulk, self._handle_mail,
2416             '''Content-Type: text/plain;
2417   charset="iso-8859-1"
2418 From: Chef <chef@bork.bork.bork>
2419 To: issue_tracker@your.tracker.email.domain.example
2420 Cc: richard@test.test
2421 Message-Id: <dummy_test_message_id>
2422 Subject: Re: [issue] Out of office AutoReply: Back next week
2424 Hi, I am back in the office next week
2425 ''')
2427     def testNoSubject(self):
2428         self.assertRaises(MailUsageError, self._handle_mail,
2429             '''Content-Type: text/plain;
2430   charset="iso-8859-1"
2431 From: Chef <chef@bork.bork.bork>
2432 To: issue_tracker@your.tracker.email.domain.example
2433 Cc: richard@test.test
2434 Reply-To: chef@bork.bork.bork
2435 Message-Id: <dummy_test_message_id>
2437 ''')
2439     #
2440     # TEST FOR INVALID DESIGNATOR HANDLING
2441     #
2442     def testInvalidDesignator(self):
2443         self.assertRaises(MailUsageError, self._handle_mail,
2444             '''Content-Type: text/plain;
2445   charset="iso-8859-1"
2446 From: Chef <chef@bork.bork.bork>
2447 To: issue_tracker@your.tracker.email.domain.example
2448 Subject: [frobulated] testing
2449 Cc: richard@test.test
2450 Reply-To: chef@bork.bork.bork
2451 Message-Id: <dummy_test_message_id>
2453 ''')
2454         self.assertRaises(MailUsageError, self._handle_mail,
2455             '''Content-Type: text/plain;
2456   charset="iso-8859-1"
2457 From: Chef <chef@bork.bork.bork>
2458 To: issue_tracker@your.tracker.email.domain.example
2459 Subject: [issue12345] testing
2460 Cc: richard@test.test
2461 Reply-To: chef@bork.bork.bork
2462 Message-Id: <dummy_test_message_id>
2464 ''')
2466     def testInvalidClassLoose(self):
2467         self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'loose'
2468         nodeid = 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 Subject: [frobulated] testing
2473 Cc: richard@test.test
2474 Reply-To: chef@bork.bork.bork
2475 Message-Id: <dummy_test_message_id>
2477 ''')
2478         assert not os.path.exists(SENDMAILDEBUG)
2479         self.assertEqual(self.db.issue.get(nodeid, 'title'),
2480             '[frobulated] testing')
2482     def testInvalidClassLooseReply(self):
2483         self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'loose'
2484         nodeid = self._handle_mail('''Content-Type: text/plain;
2485   charset="iso-8859-1"
2486 From: Chef <chef@bork.bork.bork>
2487 To: issue_tracker@your.tracker.email.domain.example
2488 Subject: Re: [frobulated] testing
2489 Cc: richard@test.test
2490 Reply-To: chef@bork.bork.bork
2491 Message-Id: <dummy_test_message_id>
2493 ''')
2494         assert not os.path.exists(SENDMAILDEBUG)
2495         self.assertEqual(self.db.issue.get(nodeid, 'title'),
2496             '[frobulated] testing')
2498     def testInvalidClassLoose(self):
2499         self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'loose'
2500         nodeid = self._handle_mail('''Content-Type: text/plain;
2501   charset="iso-8859-1"
2502 From: Chef <chef@bork.bork.bork>
2503 To: issue_tracker@your.tracker.email.domain.example
2504 Subject: [issue1234] testing
2505 Cc: richard@test.test
2506 Reply-To: chef@bork.bork.bork
2507 Message-Id: <dummy_test_message_id>
2509 ''')
2510         assert not os.path.exists(SENDMAILDEBUG)
2511         self.assertEqual(self.db.issue.get(nodeid, 'title'),
2512             '[issue1234] testing')
2514     def testClassLooseOK(self):
2515         self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'loose'
2516         self.db.keyword.create(name='Foo')
2517         nodeid = self._handle_mail('''Content-Type: text/plain;
2518   charset="iso-8859-1"
2519 From: Chef <chef@bork.bork.bork>
2520 To: issue_tracker@your.tracker.email.domain.example
2521 Subject: [keyword1] Testing... [name=Bar]
2522 Cc: richard@test.test
2523 Reply-To: chef@bork.bork.bork
2524 Message-Id: <dummy_test_message_id>
2526 ''')
2527         assert not os.path.exists(SENDMAILDEBUG)
2528         self.assertEqual(self.db.keyword.get('1', 'name'), 'Bar')
2530     def testClassStrictInvalid(self):
2531         self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'strict'
2532         self.instance.config.MAILGW_DEFAULT_CLASS = ''
2534         message = '''Content-Type: text/plain;
2535   charset="iso-8859-1"
2536 From: Chef <chef@bork.bork.bork>
2537 To: issue_tracker@your.tracker.email.domain.example
2538 Subject: Testing...
2539 Cc: richard@test.test
2540 Reply-To: chef@bork.bork.bork
2541 Message-Id: <dummy_test_message_id>
2543 '''
2544         self.assertRaises(MailUsageError, self._handle_mail, message)
2546     def testClassStrictValid(self):
2547         self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'strict'
2548         self.instance.config.MAILGW_DEFAULT_CLASS = ''
2550         nodeid = self._handle_mail('''Content-Type: text/plain;
2551   charset="iso-8859-1"
2552 From: Chef <chef@bork.bork.bork>
2553 To: issue_tracker@your.tracker.email.domain.example
2554 Subject: [issue] Testing...
2555 Cc: richard@test.test
2556 Reply-To: chef@bork.bork.bork
2557 Message-Id: <dummy_test_message_id>
2559 ''')
2561         assert not os.path.exists(SENDMAILDEBUG)
2562         self.assertEqual(self.db.issue.get(nodeid, 'title'), 'Testing...')
2564     #
2565     # TEST FOR INVALID COMMANDS HANDLING
2566     #
2567     def testInvalidCommands(self):
2568         self.assertRaises(MailUsageError, self._handle_mail,
2569             '''Content-Type: text/plain;
2570   charset="iso-8859-1"
2571 From: Chef <chef@bork.bork.bork>
2572 To: issue_tracker@your.tracker.email.domain.example
2573 Subject: testing [frobulated]
2574 Cc: richard@test.test
2575 Reply-To: chef@bork.bork.bork
2576 Message-Id: <dummy_test_message_id>
2578 ''')
2580     def testInvalidCommandPassthrough(self):
2581         self.instance.config.MAILGW_SUBJECT_SUFFIX_PARSING = 'none'
2582         nodeid = self._handle_mail('''Content-Type: text/plain;
2583   charset="iso-8859-1"
2584 From: Chef <chef@bork.bork.bork>
2585 To: issue_tracker@your.tracker.email.domain.example
2586 Subject: testing [frobulated]
2587 Cc: richard@test.test
2588 Reply-To: chef@bork.bork.bork
2589 Message-Id: <dummy_test_message_id>
2591 ''')
2592         assert not os.path.exists(SENDMAILDEBUG)
2593         self.assertEqual(self.db.issue.get(nodeid, 'title'),
2594             'testing [frobulated]')
2596     def testInvalidCommandPassthroughLoose(self):
2597         self.instance.config.MAILGW_SUBJECT_SUFFIX_PARSING = 'loose'
2598         nodeid = self._handle_mail('''Content-Type: text/plain;
2599   charset="iso-8859-1"
2600 From: Chef <chef@bork.bork.bork>
2601 To: issue_tracker@your.tracker.email.domain.example
2602 Subject: testing [frobulated]
2603 Cc: richard@test.test
2604 Reply-To: chef@bork.bork.bork
2605 Message-Id: <dummy_test_message_id>
2607 ''')
2608         assert not os.path.exists(SENDMAILDEBUG)
2609         self.assertEqual(self.db.issue.get(nodeid, 'title'),
2610             'testing [frobulated]')
2612     def testInvalidCommandPassthroughLooseOK(self):
2613         self.instance.config.MAILGW_SUBJECT_SUFFIX_PARSING = 'loose'
2614         nodeid = self._handle_mail('''Content-Type: text/plain;
2615   charset="iso-8859-1"
2616 From: Chef <chef@bork.bork.bork>
2617 To: issue_tracker@your.tracker.email.domain.example
2618 Subject: testing [assignedto=mary]
2619 Cc: richard@test.test
2620 Reply-To: chef@bork.bork.bork
2621 Message-Id: <dummy_test_message_id>
2623 ''')
2624         assert not os.path.exists(SENDMAILDEBUG)
2625         self.assertEqual(self.db.issue.get(nodeid, 'title'), 'testing')
2626         self.assertEqual(self.db.issue.get(nodeid, 'assignedto'), self.mary_id)
2628     def testCommandDelimiters(self):
2629         self.instance.config.MAILGW_SUBJECT_SUFFIX_DELIMITERS = '{}'
2630         nodeid = self._handle_mail('''Content-Type: text/plain;
2631   charset="iso-8859-1"
2632 From: Chef <chef@bork.bork.bork>
2633 To: issue_tracker@your.tracker.email.domain.example
2634 Subject: testing {assignedto=mary}
2635 Cc: richard@test.test
2636 Reply-To: chef@bork.bork.bork
2637 Message-Id: <dummy_test_message_id>
2639 ''')
2640         assert not os.path.exists(SENDMAILDEBUG)
2641         self.assertEqual(self.db.issue.get(nodeid, 'title'), 'testing')
2642         self.assertEqual(self.db.issue.get(nodeid, 'assignedto'), self.mary_id)
2644     def testPrefixDelimiters(self):
2645         self.instance.config.MAILGW_SUBJECT_SUFFIX_DELIMITERS = '{}'
2646         self.db.keyword.create(name='Foo')
2647         self._handle_mail('''Content-Type: text/plain;
2648   charset="iso-8859-1"
2649 From: richard <richard@test.test>
2650 To: issue_tracker@your.tracker.email.domain.example
2651 Message-Id: <followup_dummy_id>
2652 In-Reply-To: <dummy_test_message_id>
2653 Subject: {keyword1} Testing... {name=Bar}
2655 ''')
2656         assert not os.path.exists(SENDMAILDEBUG)
2657         self.assertEqual(self.db.keyword.get('1', 'name'), 'Bar')
2659     def testCommandDelimitersIgnore(self):
2660         self.instance.config.MAILGW_SUBJECT_SUFFIX_DELIMITERS = '{}'
2661         nodeid = self._handle_mail('''Content-Type: text/plain;
2662   charset="iso-8859-1"
2663 From: Chef <chef@bork.bork.bork>
2664 To: issue_tracker@your.tracker.email.domain.example
2665 Subject: testing [assignedto=mary]
2666 Cc: richard@test.test
2667 Reply-To: chef@bork.bork.bork
2668 Message-Id: <dummy_test_message_id>
2670 ''')
2671         assert not os.path.exists(SENDMAILDEBUG)
2672         self.assertEqual(self.db.issue.get(nodeid, 'title'),
2673             'testing [assignedto=mary]')
2674         self.assertEqual(self.db.issue.get(nodeid, 'assignedto'), None)
2676     def testReplytoMatch(self):
2677         self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'loose'
2678         nodeid = self.doNewIssue()
2679         nodeid2 = self._handle_mail('''Content-Type: text/plain;
2680   charset="iso-8859-1"
2681 From: Chef <chef@bork.bork.bork>
2682 To: issue_tracker@your.tracker.email.domain.example
2683 Message-Id: <dummy_test_message_id2>
2684 In-Reply-To: <dummy_test_message_id>
2685 Subject: Testing...
2687 Followup message.
2688 ''')
2690         nodeid3 = self._handle_mail('''Content-Type: text/plain;
2691   charset="iso-8859-1"
2692 From: Chef <chef@bork.bork.bork>
2693 To: issue_tracker@your.tracker.email.domain.example
2694 Message-Id: <dummy_test_message_id3>
2695 In-Reply-To: <dummy_test_message_id2>
2696 Subject: Testing...
2698 Yet another message in the same thread/issue.
2699 ''')
2701         self.assertEqual(nodeid, nodeid2)
2702         self.assertEqual(nodeid, nodeid3)
2704     def testHelpSubject(self):
2705         message = '''Content-Type: text/plain;
2706   charset="iso-8859-1"
2707 From: Chef <chef@bork.bork.bork>
2708 To: issue_tracker@your.tracker.email.domain.example
2709 Message-Id: <dummy_test_message_id2>
2710 In-Reply-To: <dummy_test_message_id>
2711 Subject: hElp
2714 '''
2715         self.assertRaises(MailUsageHelp, self._handle_mail, message)
2717     def testMaillistSubject(self):
2718         self.instance.config.MAILGW_SUBJECT_SUFFIX_DELIMITERS = '[]'
2719         self.db.keyword.create(name='Foo')
2720         self._handle_mail('''Content-Type: text/plain;
2721   charset="iso-8859-1"
2722 From: Chef <chef@bork.bork.bork>
2723 To: issue_tracker@your.tracker.email.domain.example
2724 Subject: [mailinglist-name] [keyword1] Testing.. [name=Bar]
2725 Cc: richard@test.test
2726 Reply-To: chef@bork.bork.bork
2727 Message-Id: <dummy_test_message_id>
2729 ''')
2731         assert not os.path.exists(SENDMAILDEBUG)
2732         self.assertEqual(self.db.keyword.get('1', 'name'), 'Bar')
2734     def testUnknownPrefixSubject(self):
2735         self.db.keyword.create(name='Foo')
2736         self._handle_mail('''Content-Type: text/plain;
2737   charset="iso-8859-1"
2738 From: Chef <chef@bork.bork.bork>
2739 To: issue_tracker@your.tracker.email.domain.example
2740 Subject: VeryStrangeRe: [keyword1] Testing.. [name=Bar]
2741 Cc: richard@test.test
2742 Reply-To: chef@bork.bork.bork
2743 Message-Id: <dummy_test_message_id>
2745 ''')
2747         assert not os.path.exists(SENDMAILDEBUG)
2748         self.assertEqual(self.db.keyword.get('1', 'name'), 'Bar')
2750     def testOneCharSubject(self):
2751         message = '''Content-Type: text/plain;
2752   charset="iso-8859-1"
2753 From: Chef <chef@bork.bork.bork>
2754 To: issue_tracker@your.tracker.email.domain.example
2755 Subject: b
2756 Cc: richard@test.test
2757 Reply-To: chef@bork.bork.bork
2758 Message-Id: <dummy_test_message_id>
2760 '''
2761         try:
2762             self._handle_mail(message)
2763         except MailUsageError:
2764             self.fail('MailUsageError raised')
2766     def testIssueidLast(self):
2767         nodeid1 = self.doNewIssue()
2768         nodeid2 = self._handle_mail('''Content-Type: text/plain;
2769   charset="iso-8859-1"
2770 From: mary <mary@test.test>
2771 To: issue_tracker@your.tracker.email.domain.example
2772 Message-Id: <followup_dummy_id>
2773 In-Reply-To: <dummy_test_message_id>
2774 Subject: New title [issue1]
2776 This is a second followup
2777 ''')
2779         assert nodeid1 == nodeid2
2780         self.assertEqual(self.db.issue.get(nodeid2, 'title'), "Testing...")
2782     def testSecurityMessagePermissionContent(self):
2783         id = self.doNewIssue()
2784         issue = self.db.issue.getnode (id)
2785         self.db.security.addRole(name='Nomsg')
2786         self.db.security.addPermissionToRole('Nomsg', 'Email Access')
2787         for cl in 'issue', 'file', 'keyword':
2788             for p in 'View', 'Edit', 'Create':
2789                 self.db.security.addPermissionToRole('Nomsg', p, cl)
2790         self.db.user.set(self.mary_id, roles='Nomsg')
2791         nodeid = self._handle_mail('''Content-Type: text/plain;
2792   charset="iso-8859-1"
2793 From: Chef <chef@bork.bork.bork>
2794 To: issue_tracker@your.tracker.email.domain.example
2795 Message-Id: <dummy_test_message_id_2>
2796 Subject: [issue%(id)s] Testing... [nosy=+mary]
2798 Just a test reply
2799 '''%locals())
2800         assert os.path.exists(SENDMAILDEBUG)
2801         self.compareMessages(self._get_mail(),
2802 '''FROM: roundup-admin@your.tracker.email.domain.example
2803 TO: chef@bork.bork.bork, richard@test.test
2804 Content-Type: text/plain; charset="utf-8"
2805 Subject: [issue1] Testing...
2806 To: richard@test.test
2807 From: "Bork, Chef" <issue_tracker@your.tracker.email.domain.example>
2808 Reply-To: Roundup issue tracker
2809  <issue_tracker@your.tracker.email.domain.example>
2810 MIME-Version: 1.0
2811 Message-Id: <dummy_test_message_id_2>
2812 In-Reply-To: <dummy_test_message_id>
2813 X-Roundup-Name: Roundup issue tracker
2814 X-Roundup-Loop: hello
2815 X-Roundup-Issue-Status: chatting
2816 Content-Transfer-Encoding: quoted-printable
2819 Bork, Chef <chef@bork.bork.bork> added the comment:
2821 Just a test reply
2823 ----------
2824 nosy: +mary
2825 status: unread -> chatting
2827 _______________________________________________________________________
2828 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
2829 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
2830 _______________________________________________________________________
2831 ''')
2833     def testOutlookAttachment(self):
2834         message = '''X-MimeOLE: Produced By Microsoft Exchange V6.5
2835 Content-class: urn:content-classes:message
2836 MIME-Version: 1.0
2837 Content-Type: multipart/mixed;
2838         boundary="----_=_NextPart_001_01CACA65.40A51CBC"
2839 Subject: Example of a failed outlook attachment e-mail
2840 Date: Tue, 23 Mar 2010 01:43:44 -0700
2841 Message-ID: <CA37F17219784343816CA6613D2E339205E7D0F9@nrcwstexb1.nrc.ca>
2842 X-MS-Has-Attach: yes
2843 X-MS-TNEF-Correlator: 
2844 Thread-Topic: Example of a failed outlook attachment e-mail
2845 Thread-Index: AcrKJo/t3pUBBwTpSwWNE3LE67UBDQ==
2846 From: "Hugh" <richard@test.test>
2847 To: <richard@test.test>
2848 X-OriginalArrivalTime: 23 Mar 2010 08:45:57.0350 (UTC) FILETIME=[41893860:01CACA65]
2850 This is a multi-part message in MIME format.
2852 ------_=_NextPart_001_01CACA65.40A51CBC
2853 Content-Type: multipart/alternative;
2854         boundary="----_=_NextPart_002_01CACA65.40A51CBC"
2857 ------_=_NextPart_002_01CACA65.40A51CBC
2858 Content-Type: text/plain;
2859         charset="us-ascii"
2860 Content-Transfer-Encoding: quoted-printable
2863 Hi Richard,
2865 I suppose this isn't the exact message that was sent but is a resend of
2866 one of my trial messages that failed.  For your benefit I changed the
2867 subject line and am adding these words to the message body.  Should
2868 still be as problematic, but if you like I can resend an exact copy of a
2869 failed message changing nothing except putting your address instead of
2870 our tracker.
2872 Thanks very much for taking time to look into this.  Much appreciated.
2874  <<battery backup>>=20
2876 ------_=_NextPart_002_01CACA65.40A51CBC
2877 Content-Type: text/html;
2878         charset="us-ascii"
2879 Content-Transfer-Encoding: quoted-printable
2881 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
2882 <HTML>
2883 <HEAD>
2884 <META HTTP-EQUIV=3D"Content-Type" CONTENT=3D"text/html; =
2885 charset=3Dus-ascii">
2886 <META NAME=3D"Generator" CONTENT=3D"MS Exchange Server version =
2887 6.5.7654.12">
2888 <TITLE>Example of a failed outlook attachment e-mail</TITLE>
2889 </HEAD>
2890 <BODY>
2891 <!-- Converted from text/rtf format -->
2892 <BR>
2894 <P><FONT SIZE=3D2 FACE=3D"Arial">Hi Richard,</FONT>
2895 </P>
2897 <P><FONT SIZE=3D2 FACE=3D"Arial">I suppose this isn't the exact message =
2898 that was sent but is a resend of one of my trial messages that =
2899 failed.&nbsp; For your benefit I changed the subject line and am adding =
2900 these words to the message body.&nbsp; Should still be as problematic, =
2901 but if you like I can resend an exact copy of a failed message changing =
2902 nothing except putting your address instead of our tracker.</FONT></P>
2904 <P><FONT SIZE=3D2 FACE=3D"Arial">Thanks very much for taking time to =
2905 look into this.&nbsp; Much appreciated.</FONT>
2906 </P>
2907 <BR>
2909 <P><FONT FACE=3D"Arial" SIZE=3D2 COLOR=3D"#000000"> &lt;&lt;battery =
2910 backup&gt;&gt; </FONT>
2911 </P>
2913 </BODY>
2914 </HTML>
2915 ------_=_NextPart_002_01CACA65.40A51CBC--
2917 ------_=_NextPart_001_01CACA65.40A51CBC
2918 Content-Type: message/rfc822
2919 Content-Transfer-Encoding: 7bit
2921 X-MimeOLE: Produced By Microsoft Exchange V6.5
2922 MIME-Version: 1.0
2923 Content-Type: multipart/alternative;
2924         boundary="----_=_NextPart_003_01CAC15A.29717800"
2925 X-OriginalArrivalTime: 11 Mar 2010 20:33:51.0249 (UTC) FILETIME=[28FEE010:01CAC15A]
2926 Content-class: urn:content-classes:message
2927 Subject: battery backup
2928 Date: Thu, 11 Mar 2010 13:33:43 -0700
2929 Message-ID: <p06240809c7bf02f9624c@[128.114.22.203]>
2930 X-MS-Has-Attach: 
2931 X-MS-TNEF-Correlator: 
2932 Thread-Topic: battery backup
2933 Thread-Index: AcrBWimtulTrSvBdQ2CcfZ8lyQdxmQ==
2934 From: "Jerry" <jerry@test.test>
2935 To: "Hugh" <hugh@test.test>
2937 This is a multi-part message in MIME format.
2939 ------_=_NextPart_003_01CAC15A.29717800
2940 Content-Type: text/plain;
2941         charset="iso-8859-1"
2942 Content-Transfer-Encoding: quoted-printable
2944 Dear Hugh,
2945         A car batter has an energy capacity of ~ 500Wh.  A UPS=20
2946 battery is worse than this.
2948 if we need to provied 100kW for 30 minutes that will take 100 car=20
2949 batteries.  This seems like an awful lot of batteries.
2951 Of course I like your idea of making the time 1 minute, so we get to=20
2952 a more modest number of batteries
2954 Jerry
2957 ------_=_NextPart_003_01CAC15A.29717800
2958 Content-Type: text/html;
2959         charset="iso-8859-1"
2960 Content-Transfer-Encoding: quoted-printable
2962 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
2963 <HTML>
2964 <HEAD>
2965 <META HTTP-EQUIV=3D"Content-Type" CONTENT=3D"text/html; =
2966 charset=3Diso-8859-1">
2967 <META NAME=3D"Generator" CONTENT=3D"MS Exchange Server version =
2968 6.5.7654.12">
2969 <TITLE>battery backup</TITLE>
2970 </HEAD>
2971 <BODY>
2972 <!-- Converted from text/plain format -->
2974 <P><FONT SIZE=3D2>Dear Hugh,</FONT>
2976 <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <FONT SIZE=3D2>A car =
2977 batter has an energy capacity of ~ 500Wh.&nbsp; A UPS </FONT>
2979 <BR><FONT SIZE=3D2>battery is worse than this.</FONT>
2980 </P>
2982 <P><FONT SIZE=3D2>if we need to provied 100kW for 30 minutes that will =
2983 take 100 car </FONT>
2985 <BR><FONT SIZE=3D2>batteries.&nbsp; This seems like an awful lot of =
2986 batteries.</FONT>
2987 </P>
2989 <P><FONT SIZE=3D2>Of course I like your idea of making the time 1 =
2990 minute, so we get to </FONT>
2992 <BR><FONT SIZE=3D2>a more modest number of batteries</FONT>
2993 </P>
2995 <P><FONT SIZE=3D2>Jerry</FONT>
2996 </P>
2998 </BODY>
2999 </HTML>
3000 ------_=_NextPart_003_01CAC15A.29717800--
3002 ------_=_NextPart_001_01CACA65.40A51CBC--
3003 '''
3004         nodeid = self._handle_mail(message)
3005         assert not os.path.exists(SENDMAILDEBUG)
3006         msgid = self.db.issue.get(nodeid, 'messages')[0]
3007         self.assert_(self.db.msg.get(msgid, 'content').startswith('Hi Richard'))
3008         self.assertEqual(self.db.msg.get(msgid, 'files'), ['1', '2'])
3009         fileid = self.db.msg.get(msgid, 'files')[0]
3010         self.assertEqual(self.db.file.get(fileid, 'type'), 'text/html')
3011         fileid = self.db.msg.get(msgid, 'files')[1]
3012         self.assertEqual(self.db.file.get(fileid, 'type'), 'message/rfc822')
3014     def testForwardedMessageAttachment(self):
3015         message = '''Return-Path: <rgg@test.test>
3016 Received: from localhost(127.0.0.1), claiming to be "[115.130.26.69]"
3017 via SMTP by localhost, id smtpdAAApLaWrq; Tue Apr 13 23:10:05 2010
3018 Message-ID: <4BC4F9C7.50409@test.test>
3019 Date: Wed, 14 Apr 2010 09:09:59 +1000
3020 From: Rupert Goldie <rgg@test.test>
3021 User-Agent: Thunderbird 2.0.0.24 (Windows/20100228)
3022 MIME-Version: 1.0
3023 To: ekit issues <issues@test.test>
3024 Subject: [Fwd: PHP ERROR (fb)] post limit reached
3025 Content-Type: multipart/mixed; boundary="------------000807090608060304010403"
3027 This is a multi-part message in MIME format.
3028 --------------000807090608060304010403
3029 Content-Type: text/plain; charset=ISO-8859-1; format=flowed
3030 Content-Transfer-Encoding: 7bit
3032 Catch this exception and log it without emailing.
3034 --------------000807090608060304010403
3035 Content-Type: message/rfc822; name="PHP ERROR (fb).eml"
3036 Content-Transfer-Encoding: 7bit
3037 Content-Disposition: inline; filename="PHP ERROR (fb).eml"
3039 Return-Path: <ektravj@test.test>
3040 X-Sieve: CMU Sieve 2.2
3041 via SMTP by crown.off.ekorp.com, id smtpdAAA1JaW1o; Tue Apr 13 23:01:04 2010
3042 X-Virus-Scanned: by amavisd-new at ekit.com
3043 To: facebook-errors@test.test
3044 From: ektravj@test.test
3045 Subject: PHP ERROR (fb)
3046 Message-Id: <20100413230100.D601D27E84@mail2.elax3.ekorp.com>
3047 Date: Tue, 13 Apr 2010 23:01:00 +0000 (UTC)
3049 [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
3050 Stack trace:
3051 #0 /app/01/www/virtual/fb.ekit.com/htdocs/gateway/ekit/feed/index.php(178): fb_exceptions(Object(FacebookRestClientException))
3052 #1 {main}
3053  thrown in /app/01/www/virtual/fb.ekit.com/htdocs/includes/functions.php on line 280
3056 --------------000807090608060304010403--
3057 '''
3058         nodeid = self._handle_mail(message)
3059         assert not os.path.exists(SENDMAILDEBUG)
3060         msgid = self.db.issue.get(nodeid, 'messages')[0]
3061         self.assertEqual(self.db.msg.get(msgid, 'content'),
3062             'Catch this exception and log it without emailing.')
3063         self.assertEqual(self.db.msg.get(msgid, 'files'), ['1'])
3064         fileid = self.db.msg.get(msgid, 'files')[0]
3065         self.assertEqual(self.db.file.get(fileid, 'type'), 'message/rfc822')
3067 pgp_test_key = """
3068 -----BEGIN PGP PRIVATE KEY BLOCK-----
3069 Version: GnuPG v1.4.10 (GNU/Linux)
3071 lQOYBE6NqtsBCADG3UUMYxjwUOpDDVvr0Y8qkvKsgdF79en1zfHtRYlmZc+EJxg8
3072 53CCFGReQWJwOjyP3/SLJwJqfiPR7MAYAqJsm/4U2lxF7sIlEnlrRpFuvB625KOQ
3073 oedCkI4nLa+4QAXHxVX2qLx7es3r2JAoitZLX7ZtUB7qGSRh98DmdAgCY3CFN7iZ
3074 w6xpvIU+LNbsHSo1sf8VP6z7NHQFacgrVvLyRJ4C5lTPU42iM5E6HKxYFExNV3Rn
3075 +2G0bsuiifHV6nJQD73onjwcC6tU97W779dllHlhG3SSP0KlnwmCCvPMlQvROk0A
3076 rLyzKWcUpZwK1aLRYByjFMH9WYXRkhf08bkDABEBAAEAB/9dcmSb6YUyiBNM5t4m
3077 9hZcXykBvw79PRVvmBLy+BYUtArLgsN0+xx3Q7XWRMtJCVSkFw0GxpHwEM4sOyAZ
3078 KEPC3ZqLmgB6LDO2z/OWYVa9vlCAiPgDYtEVCnCCIInN/ue4dBZtDeVj8NUK2n0D
3079 UBpa2OMUgu3D+4SJNK7EnAmXdOaP6yfe6SXwcQfti8UoSFMJRkQkbY1rm/6iPfON
3080 t2RBAc7jW4eRzdciWCfvJfMSj9cqxTBQWz5vVadeY9Bm/IKw1HiKNBrJratq2v+D
3081 VGr0EkE9oOa5zbgZt2CFvknE4YhGmv81xFdK5GXr8L7nluZrePMblWbkI2ICTbV0
3082 RKLhBADYLvyDFX3cCoFzWmCl5L32G6LLfTt0yU0eUHcAzXd7QjOZN289HWYEmdVi
3083 kpxQPDxhWz+m8qt0HJGFl2+BKpZJBaT/L5AcqTBODxarxCSBTIVhCjD/46XvLY0h
3084 b2ZnG8HSLyFdRj07vk+qTvcF58qUuYFSLIF2t2imTCR/PwR/LwQA632vn2/7KIHj
3085 DR0O+G9eccTtAfX4TN4Q4Ua3WByClLZu/LSAenCLZ1CHVABEH6dwwjEARLeNUdLi
3086 Xy5KKlpr2vkoh96fnw0r2yg7dlBXq4yQKjJBXwNaKpuvqgzd8en0zJGLXxzt0NT3
3087 H+QNIP2WZMJSDQcDh3HhQrH0IeNdDm0D/iyJgSMXvqjm+KhYIa3xiloQsCRlDNm+
3088 XC7Eo5hsjvBaIKba6o9oL9oEiSVUFryPWKWIpi0P7/F5voJL6KFSZTor3x3o9CcC
3089 qHyqMHfNL23EAVJulySfPYLC7S3QB+tCBLXmKxb/YXCSLVi/UDzVgvWN6KIknZg2
3090 6uDLUzPbzDGjOZ20K1JvdW5kdXAgVGVzdGtleSA8cm91bmR1cC1hZG1pbkBleGFt
3091 cGxlLmNvbT6JATgEEwECACIFAk6NqtsCGwMGCwkIBwMCBhUIAgkKCwQWAgMBAh4B
3092 AheAAAoJEFrc/VYxw4dBG7oIAMCU9sRjK0dS7z/IGJ8KcCOQNN674AooJLn+J9Ew
3093 BT6/WxMY13nm/iK0uX2sOGnnXdg1PJ15IvD8zB5wXLbe25t6oRl5G58vmeKEyjc8
3094 QTB43/c8EsqY1ob7EVcuhrJCSS/JM8ApzQyXrh2QNmS+mBCJcx74MeipE6mNVT9j
3095 VscizixdFjqvJLkbW1kGac3Wj+c3ICNUIp0lbwb+Ve2rXlU+iXHEDqaVJDMEppme
3096 gDiZl+bKYrqljhZkH9Slv55uqqXUSg1SmTm/2orHUdAmDc6Y6azKNqQEqD2B0JyT
3097 jTJQJVMl5Oln63aZDCTxHkoqn8q06OjLJRD4on7jlanZEladA5gETo2q2wEIALEF
3098 poVkZrnqme2M8FObrQyVB+ZYT2mox56WLyInbxVFDg20qqIvQfVE0P69Yuf1OXkj
3099 q7bNI03Jvo+uzxpztOKPDo7tnbQ7bXbOmq3n4wUoN29NMrYNg6tF1ubEv1WwYUMw
3100 7LfF4BLMETXpT0JElV1+awfP9rrGiyWkH4enG612HT+1OoA0R0nNH0kslD6OhdoR
3101 VDqkyiCmdY9x176EhzhL3vCoN6ywRVTfFbAJiMv9UDzxs0SStmVOK/l5XLfWQO6f
3102 9boAHihpnxEfPIJhsD+FpVKVf3g85qWAjh2BfuzdW79vjLBdTHJQxg4HdhliWbXg
3103 PjjrVEgWEFVc+NDlNb0AEQEAAQAH/A1a6sbniI8q3DVoIP19zN7FI5UaQSuB2Jrl
3104 +Q+vlUQv3dvk2cwQmqj2vyRo2gcRS3u7LYpGDGLNqfshv22JyzId2YWo9vE7sTTP
3105 E4EJRz8CsLlMmVsoxoVBE0cnvXOpMef6z0ZyFEdMGVmi4iA9bQi3r+V6qBehQQA0
3106 U034VTCPN4yvWyq6TWsABesOx48nkQ5TlduIq2ZGNCR8Vd1fe6vGM7YXyQWxy5ke
3107 guqmph73H2bOB6hSuUnyBFKtinrF9MbCGA0PqheUVqy0p7og6x/pEoAVkKBJ9Ki+
3108 ePuQtBl5h9e3SbiN+r7aa6T0Ygx/7igl4eWPfvJYIXYXc4aKiwEEANEa5rBoN7Ta
3109 ED+R47Rg9w/EW3VDQ6R3Szy1rvIKjC6JlDyKlGgTeWEFjDeTwCB4xU7YtxVpt6bk
3110 b7RBtDkRck2+DwnscutA7Uxn267UxzNUd1IxhUccRFRfRS7OEnmlVmaLUnOeHHwe
3111 OrZyRSiNVnh0QABEJnwNjX4m139v6YD9BADYuM5XCawI63pYa3/l7UX9H5EH95OZ
3112 G9Hw7pXQ/YJYerSxRx+2q0+koRcdoby1TVaRrdDC+kOm3PI7e66S5rnaZ1FZeYQP
3113 nVYzyGqNnsvncs24kYBL8DYaDDfdm7vfzSEqia0VNqZ4TMbwJLk5f5Ys4WOF791G
3114 LPJgrAPG1jgDwQQAovKbw0u6blIUKsUYOLsviaLCyFC9DwaHqIZwjy8omnh7MaKE
3115 7+MXxJpfcVqFifj3CmqMdSmTfkgbKQPAI46Q1OKWvkvUxEvi7WATo4taEXupRFL5
3116 jnL8c4h46z8UpMX2CMwWU0k1Et/zlBoYy7gNON7tF2/uuN18zWFBlD72HuM9HIkB
3117 HwQYAQIACQUCTo2q2wIbDAAKCRBa3P1WMcOHQYI+CACDXJf1e695LpcsrVxKgiQr
3118 9fTbNJYB+tjbnd9vas92Gz1wZcQV9RjLkYQeEbOpWQud/1UeLRsFECMj7kbgAEqz
3119 7fIO4SeN8hFEvvZ+lI0AoBi4XvuUcCm5kvAodvmF8M9kQiUzF1gm+R9QQeJFDLpW
3120 8Gg7J3V3qM+N0FuXrypYcsEv7n/RJ1n+lhTW5hFzKBlNL4WrAhY/QsXEbmdsa478
3121 tzuHlETtjMm4g4DgppUdlCMegcpjjC9zKsN5xFOQmNMTO/6rPFUqk3k3T6I0LV4O
3122 zm4xNC+wwAA69ibnbrY1NR019et7RYW+qBudGbpJB1ABzkf/NsaCj6aTaubt7PZP
3123 =3uFZ
3124 -----END PGP PRIVATE KEY BLOCK-----
3125 """
3127 john_doe_key = """
3128 -----BEGIN PGP PRIVATE KEY BLOCK-----
3129 Version: GnuPG v1.4.10 (GNU/Linux)
3131 lQHYBE6NwvABBACxg7QqV2qHywwM3wae6HAHJVEo7EeYA6Lv0pZlW3Aw4CCCnpgJ
3132 jA7CekGFcmGmoCaN9ezuVAPTgUlK4yt8a7P6cT0vw1q341Om9IEKAu59RpNZN/H9
3133 6GfZ95bU51W/hdTFysH1DRwbCR3MowvLeA6Pk4cZlPsYHD0SD3De2i1BewARAQAB
3134 AAP+IRi4L6jKwPS3k3LFrj0SHhL0Fdgv5QTQjTxLNCyfN02iYhglqqoFWncm3jWc
3135 RU/YwGEYwrrBV97kBmVihzkhfgFRsxynE9PMGKKEAuRcAl21RPJDFA6Dlnp6M2No
3136 rR6eoAhrlZ8+KsK9JaXSMalzO/Yh4u3mOinq3f3XL96wAEkCAMAxeZMF5pnXARNR
3137 Y7u2clhNNnLuf+BzpENCFMaWzWPyTcvbf4xNK7ZHPxFVZpX5/qAPJ8rnTaOTHxnN
3138 5PgqbO8CAOxyrTw/muakTJLg+FXdn8BgxZGJXMT7KmkU9SReefjo7c1WlnZxKIAy
3139 6vLIG8WMGpdfCFDve0YLr/GGyDtOjDUB/RN3gn6qnAJThBnVk2wESZVx41fihbIF
3140 ACCKc9heFskzwurtvvp+bunM3quwrSH1hWvxiWJlDmGSn8zQFypGChifgLQZSm9o
3141 biBEb2UgPGpvaG5AdGVzdC50ZXN0Poi4BBMBAgAiBQJOjcLwAhsDBgsJCAcDAgYV
3142 CAIJCgsEFgIDAQIeAQIXgAAKCRC/z7qg+FujnPWiA/9T5SOGraRNIVVIyvJvYwkG
3143 OTAfQ0K3QMlLoQMPmaEbx9Q+isF15M9sOMcl1XGO4UNWuCPIIN8z/y/OLgAB0ZuL
3144 GlnAPPOOZ+MlaUXiMYo8oi416QZrMDf2H/Nkc10csiXm+zMl8RqeIQBEeljNyJ+t
3145 MG1EWn/PHTwFTd/VePuQdJ0B2AROjcLwAQQApw+72jKy0/wqg5SAtnVSkA1F3Jna
3146 /OG+ufz5dX57jkMFRvFoksWIWqHmiCjdE5QV8j+XTnjElhLsmrgjl7aAFveb30R6
3147 ImmcpKMN31vAp4RZlnyYbYUCY4IXFuz3n1CaUL+mRx5yNJykrZNfpWNf2pwozkZq
3148 lcDI69ymIW5acXUAEQEAAQAD/R7Jdf98l1scngMYo228ikYUxBqm2eX/fiQNXDWM
3149 ZR2u+TJ9O53MvFejfXX7Pd6lTDQUBwDFncjgXO0YYSrMzabhqpqoKLqOIpZmBuWC
3150 Hh1lvcFoIYoDR2LkiJ9EPBUEVUBDsUO8ajkILEE3G+DDpCaf9Vo82lCVyhDESqyt
3151 v4lxAgDOLpoq1Whv5Ejr6FifTWytCiQjH2P1SmePlQmy6oEJRUYA1t4zYrzCJUX8
3152 VAvPjh9JXilP6mhDbyQArWllewV9AgDPbVOf75ktRwfhje26tZsukqWYJCc1XvoH
3153 3PTzA7vH1HZZq7dvxa87PiSnkOLEsIAsI+4jpeMxpPlQRxUvHf1ZAf9rK3v3HMJ/
3154 2xVzwK24Oaj+g2O7D/fdqtLFGe5S5JobnTyp9xArDAhaZ/AKfDMYjUIKMP+bdNAf
3155 y8fQUtuawFltm1GInwQYAQIACQUCTo3C8AIbDAAKCRC/z7qg+FujnDzYA/9EU6Pv
3156 Ci1+DCtxjnq7IOvOjqExhFNGvN9Dw17Tl8HcyW3if9v5RxeSWYKl0DhzVdzMQgH/
3157 78q4F4W1q2IkB7SCpXizHLIc3eh8iZkbWZE+CGPvTpqyF03Yi16qhxpAbkGs2Yhq
3158 jTx5oJ4CL5fybBOZLg+BTlK4HIee6xEcbNoq+A==
3159 =ZKBW
3160 -----END PGP PRIVATE KEY BLOCK-----
3161 """
3163 ownertrust = """
3164 723762CD5A5FECB76DC72DF85ADCFD5631C38741:6:
3165 2940C247A1FBAD508A1AF24BBFCFBAA0F85BA39C:6:
3166 """
3168 class MailgwPGPTestCase(MailgwTestAbstractBase):
3169     pgphome = gpgmelib.pgphome
3170     def setUp(self):
3171         MailgwTestAbstractBase.setUp(self)
3172         self.db.security.addRole(name = 'pgp', description = 'PGP Role')
3173         self.instance.config['PGP_HOMEDIR'] = self.pgphome
3174         self.instance.config['PGP_ROLES'] = 'pgp'
3175         self.instance.config['PGP_ENABLE'] = True
3176         self.instance.config['MAIL_DOMAIN'] = 'example.com'
3177         self.instance.config['ADMIN_EMAIL'] = 'roundup-admin@example.com'
3178         self.db.user.set(self.john_id, roles='User,pgp')
3179         gpgmelib.setUpPGP()
3181     def tearDown(self):
3182         MailgwTestAbstractBase.tearDown(self)
3183         gpgmelib.tearDownPGP()
3185     def testPGPUnsignedMessage(self):
3186         self.assertRaises(MailUsageError, self._handle_mail,
3187             '''Content-Type: text/plain;
3188   charset="iso-8859-1"
3189 From: John Doe <john@test.test>
3190 To: issue_tracker@your.tracker.email.domain.example
3191 Message-Id: <dummy_test_message_id>
3192 Subject: [issue] Testing non-signed message...
3194 This is no pgp signed message.
3195 ''')
3197     signed_msg = '''Content-Disposition: inline
3198 From: John Doe <john@test.test>
3199 To: issue_tracker@your.tracker.email.domain.example
3200 Subject: [issue] Testing signed message...
3201 Content-Type: multipart/signed; micalg=pgp-sha1;
3202         protocol="application/pgp-signature"; boundary="cWoXeonUoKmBZSoM"
3205 --cWoXeonUoKmBZSoM
3206 Content-Type: text/plain; charset=us-ascii
3207 Content-Disposition: inline
3209 This is a pgp signed message.
3211 --cWoXeonUoKmBZSoM
3212 Content-Type: application/pgp-signature; name="signature.asc"
3213 Content-Description: Digital signature
3214 Content-Disposition: inline
3216 -----BEGIN PGP SIGNATURE-----
3217 Version: GnuPG v1.4.10 (GNU/Linux)
3219 iJwEAQECAAYFAk6N4A4ACgkQv8+6oPhbo5x5nAP/d7R7SxTvLoVESI+1r7eDXp1J
3220 LvBVU2EF3YFYKBHMLcWmjG92fNjnHX6NENTEhTeBynba5IPEwUfITC+7PmgPmQkA
3221 VXnFZnwraHxsYgyFsVFN1kkTSbwRUlWl9+nTEsr0yBLTpZN0QSIDcwu+i/xVcg+t
3222 ZQ4K6R3m3AOw7BLdvZs=
3223 =wpYk
3224 -----END PGP SIGNATURE-----
3226 --cWoXeonUoKmBZSoM--
3227 '''
3229     def testPGPSignedMessage(self):
3230         nodeid = self._handle_mail(self.signed_msg)
3231         m = self.db.issue.get(nodeid, 'messages')[0]
3232         self.assertEqual(self.db.msg.get(m, 'content'), 
3233             'This is a pgp signed message.')
3235     def testPGPSignedMessageFail(self):
3236         # require both, signing and encryption
3237         self.instance.config['PGP_REQUIRE_INCOMING'] = 'both'
3238         self.assertRaises(MailUsageError, self._handle_mail, self.signed_msg)
3240     encrypted_msg = '''Content-Disposition: inline
3241 From: John Doe <john@test.test>
3242 To: roundup-admin@example.com
3243 Subject: [issue] Testing encrypted message...
3244 Content-Type: multipart/encrypted; protocol="application/pgp-encrypted";
3245         boundary="d6Gm4EdcadzBjdND"
3247 --d6Gm4EdcadzBjdND
3248 Content-Type: application/pgp-encrypted
3249 Content-Disposition: attachment
3251 Version: 1
3253 --d6Gm4EdcadzBjdND
3254 Content-Type: application/octet-stream
3255 Content-Disposition: inline; filename="msg.asc"
3257 -----BEGIN PGP MESSAGE-----
3258 Version: GnuPG v1.4.10 (GNU/Linux)
3260 hQEMAzfeQttq+Q2YAQf9FxCtZVgC7jAy6UkeAJ1imCpnh9DgKA5w40OFtrY4mVAp
3261 cL7kCkvGvJCW7uQZrmSgIiYaZGLI3GS42XutORC6E6PzBEW0fJUMIXYmoSd0OFeY
3262 3H2+854qu37W/uCOWM9OnPFIH8g8q8DgYy88i0goM+Ot9Q96yFfJ7QymanOZJgVa
3263 MNC+oKDiIZKiE3PCwtGr+8CHZN/9J6O4FeJijBlr09C5LXc+Nif5T0R0nt17MAns
3264 9g2UvGxW8U24NAS1mOg868U05hquLPIcFz9jGZGknJu7HBpOkQ9GjKqkzN8pgZVN
3265 VbN8IdDqi0QtRKE44jtWQlyNlESMjv6GtC2V9F6qKNK8AfHtBexDhyv4G9cPFFNO
3266 afQ6e4dPi89RYIQyydtwiqao8fj6jlAy2Z1cbr7YxwBG7BeUZv9yis7ShaAIo78S
3267 82MrCYpSjfHNwKiSfC5yITw22Uv4wWgixVdAsaSdtBqEKXJPG9LNey18ArsBjSM1
3268 P81iDOWUp/uyIe5ZfvNI38BBxEYslPTUlDk2GB8J2Vun7IWHoj9a4tY3IotC9jBr
3269 5Qnigzqrt7cJZX6OrN0c+wnOjXbMGYXmgSs4jeM=
3270 =XX5Q
3271 -----END PGP MESSAGE-----
3273 --d6Gm4EdcadzBjdND--
3274 '''
3275     def testPGPEncryptedUnsignedMessageError(self):
3276         self.assertRaises(MailUsageError, self._handle_mail, self.encrypted_msg)
3278     def testPGPEncryptedUnsignedMessage(self):
3279         # no error if we don't require a signature:
3280         self.instance.config['PGP_REQUIRE_INCOMING'] = 'encrypted'
3281         nodeid = self._handle_mail (self.encrypted_msg)
3282         m = self.db.issue.get(nodeid, 'messages')[0]
3283         self.assertEqual(self.db.msg.get(m, 'content'), 
3284             'This is the text to be encrypted')
3286     def testPGPEncryptedUnsignedMessageFromNonPGPUser(self):
3287         msg = self.encrypted_msg.replace('John Doe <john@test.test>',
3288             '"Contrary, Mary" <mary@test.test>')
3289         nodeid = self._handle_mail (msg)
3290         m = self.db.issue.get(nodeid, 'messages')[0]
3291         self.assertEqual(self.db.msg.get(m, 'content'), 
3292             'This is the text to be encrypted')
3293         self.assertEqual(self.db.msg.get(m, 'author'), self.mary_id)
3295     # check that a bounce-message that is triggered *after*
3296     # decrypting is properly encrypted:
3297     def testPGPEncryptedUnsignedMessageCheckBounce(self):
3298         # allow non-signed msg
3299         self.instance.config['PGP_REQUIRE_INCOMING'] = 'encrypted'
3300         # don't allow creation of message, trigger error *after* decrypt
3301         self.db.user.set(self.john_id, roles='pgp')
3302         self.db.security.addPermissionToRole('pgp', 'Email Access')
3303         self.db.security.addPermissionToRole('pgp', 'Create', 'issue')
3304         # trap_exc=1: we want a bounce message:
3305         self._handle_mail(self.encrypted_msg, trap_exc=1)
3306         m = self._get_mail()
3307         fp = FeedParser()
3308         fp.feed(m)
3309         parts = fp.close().get_payload()
3310         self.assertEqual(len(parts),2)
3311         self.assertEqual(parts[0].get_payload().strip(), 'Version: 1')
3312         crypt = pyme.core.Data(parts[1].get_payload())
3313         plain = pyme.core.Data()
3314         ctx = pyme.core.Context()
3315         res = ctx.op_decrypt(crypt, plain)
3316         self.assertEqual(res, None)
3317         plain.seek(0,0)
3318         fp = FeedParser()
3319         fp.feed(plain.read())
3320         parts = fp.close().get_payload()
3321         self.assertEqual(len(parts),2)
3322         self.assertEqual(parts[0].get_payload().strip(),
3323             'You are not permitted to create messages.')
3324         self.assertEqual(parts[1].get_payload().strip(),
3325             '''Content-Type: text/plain; charset=us-ascii
3326 Content-Disposition: inline
3328 This is the text to be encrypted''')
3331     def testPGPEncryptedSignedMessage(self):
3332         # require both, signing and encryption
3333         self.instance.config['PGP_REQUIRE_INCOMING'] = 'both'
3334         nodeid = self._handle_mail('''Content-Disposition: inline
3335 From: John Doe <john@test.test>
3336 To: roundup-admin@example.com
3337 Subject: Testing encrypted and signed message
3338 MIME-Version: 1.0
3339 Content-Type: multipart/encrypted; protocol="application/pgp-encrypted";
3340         boundary="ReaqsoxgOBHFXBhH"
3342 --ReaqsoxgOBHFXBhH
3343 Content-Type: application/pgp-encrypted
3344 Content-Disposition: attachment
3346 Version: 1
3348 --ReaqsoxgOBHFXBhH
3349 Content-Type: application/octet-stream
3350 Content-Disposition: inline; filename="msg.asc"
3352 -----BEGIN PGP MESSAGE-----
3353 Version: GnuPG v1.4.10 (GNU/Linux)
3355 hQEMAzfeQttq+Q2YAQf+NaC3r8qBURQqxHH9IAP4vg0QAP2yj3n0v6guo1lRf5BA
3356 EUfTQ3jc3chxLvzTgoUIuMOvhlNroqR1lgLwhfSTCyuKWDZa+aVNiSgsB2MD44Xd
3357 mAkKKmnmOGLmfbICbPQZxl4xNhCMTHiAy1xQE6mTj/+pEAq5XxjJUwn/gJ3O1Wmd
3358 NyWtJY2N+TRbxUVB2WhG1j9J1D2sjhG26TciE8JeuLDZzaiVNOW9YlX2Lw5KtlkR
3359 Hkgw6Xme06G0XXZUcm9JuBU/7oFP/tSrC1tBsnVlq1pZYf6AygIBdXWb9gD/WmXh
3360 7Eu/xCKrw4RFnXnTgmBz/NHRfVDkfdSscZqexnG1D9LAwQHSuVf8sxDPNesv0W+8
3361 e49loVjvU+Y0BCFQAbWSW4iOEUYZpW/ITRE4+wIqMXZbAraeBV0KPZ4hAa3qSmf+
3362 oZBRcbzssL163Odx/OHRuK2J2CHC654+crrlTBnxd/RUKgRbSUKwrZzB2G6OPcGv
3363 wfiqXsY+XvSZtTbWuvUJxePh8vhhhjpuo1JtlrYc3hZ9OYgoCoV1JiLl5c60U5Es
3364 oUT9GDl1Qsgb4dF4TJ1IBj+riYiocYpJxPhxzsy6liSLNy2OA6VEjG0FGk53+Ok9
3365 7UzOA+WaHJHSXafZzrdP1TWJUFlOMA+dOgTKpH69eL1+IRfywOjEwp1UNSbLnJpc
3366 D0QQLwIFttplKvYkn0DZByJCVnIlGkl4s5LM5rnc8iecX8Jad0iRIlPV6CVM+Nso
3367 WdARUfyJfXAmz8uk4f2sVfeMu1gdMySdjvxwlgHDJdBPIG51r2b8L/NCTiC57YjF
3368 zGhS06FLl3V1xx6gBlpqQHjut3efrAGpXGBVpnTJMOcgYAk=
3369 =jt/n
3370 -----END PGP MESSAGE-----
3372 --ReaqsoxgOBHFXBhH--
3373 ''')
3374         m = self.db.issue.get(nodeid, 'messages')[0]
3375         self.assertEqual(self.db.msg.get(m, 'content'), 
3376             'This is the text of a signed and encrypted email.')
3379 def test_suite():
3380     suite = unittest.TestSuite()
3381     suite.addTest(unittest.makeSuite(MailgwTestCase))
3382     if pyme is not None:
3383         suite.addTest(unittest.makeSuite(MailgwPGPTestCase))
3384     else:
3385         print "Skipping PGP tests"
3386     return suite
3388 if __name__ == '__main__':
3389     runner = unittest.TextTestRunner()
3390     unittest.main(testRunner=runner)
3392 # vim: set filetype=python sts=4 sw=4 et si :