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
2275 >
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
2296 >
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. For your benefit I changed the subject line and am adding =
2900 these words to the message body. 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. Much appreciated.</FONT>
2906 </P>
2907 <BR>
2909 <P><FONT FACE=3D"Arial" SIZE=3D2 COLOR=3D"#000000"> <<battery =
2910 backup>> </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> <FONT SIZE=3D2>A car =
2977 batter has an energy capacity of ~ 500Wh. 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. 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 :