ea1a53a67c9906abaafba1c2bbf40dcfc4b4fafe
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
19 try:
20 import pyme, pyme.core
21 except ImportError:
22 pyme = None
25 from cStringIO import StringIO
27 if not os.environ.has_key('SENDMAILDEBUG'):
28 os.environ['SENDMAILDEBUG'] = 'mail-test.log'
29 SENDMAILDEBUG = os.environ['SENDMAILDEBUG']
31 from roundup import mailgw, i18n, roundupdb
32 from roundup.mailgw import MailGW, Unauthorized, uidFromAddress, \
33 parseContent, IgnoreLoop, IgnoreBulk, MailUsageError, MailUsageHelp
34 from roundup import init, instance, password, rfc2822, __version__
35 from roundup.anypy.sets_ import set
37 #import db_test_base
38 import memorydb
40 class Message(rfc822.Message):
41 """String-based Message class with equivalence test."""
42 def __init__(self, s):
43 rfc822.Message.__init__(self, StringIO(s.strip()))
45 def __eq__(self, other):
46 return (self.dict == other.dict and
47 self.fp.read() == other.fp.read())
49 class Tracker(object):
50 def open(self, journaltag):
51 return self.db
53 class DiffHelper:
54 def compareMessages(self, new, old):
55 """Compare messages for semantic equivalence."""
56 new, old = Message(new), Message(old)
58 # all Roundup-generated messages have "Precedence: bulk"
59 old['Precedence'] = 'bulk'
61 # don't try to compare the date
62 del new['date'], old['date']
64 if not new == old:
65 res = []
67 replace = {}
68 for key in new.keys():
69 if key.startswith('from '):
70 # skip the unix from line
71 continue
72 if key.lower() == 'x-roundup-version':
73 # version changes constantly, so handle it specially
74 if new[key] != __version__:
75 res.append(' %s: %r != %r' % (key, __version__,
76 new[key]))
77 elif key.lower() == 'content-type' and 'boundary=' in new[key]:
78 # handle mime messages
79 newmime = new[key].split('=',1)[-1].strip('"')
80 oldmime = old.get(key, '').split('=',1)[-1].strip('"')
81 replace ['--' + newmime] = '--' + oldmime
82 replace ['--' + newmime + '--'] = '--' + oldmime + '--'
83 elif new.get(key, '') != old.get(key, ''):
84 res.append(' %s: %r != %r' % (key, old.get(key, ''),
85 new.get(key, '')))
87 body_diff = self.compareStrings(new.fp.read(), old.fp.read(),
88 replace=replace)
89 if body_diff:
90 res.append('')
91 res.extend(body_diff)
93 if res:
94 res.insert(0, 'Generated message not correct (diff follows, expected vs. actual):')
95 raise AssertionError, '\n'.join(res)
97 def compareStrings(self, s2, s1, replace={}):
98 '''Note the reversal of s2 and s1 - difflib.SequenceMatcher wants
99 the first to be the "original" but in the calls in this file,
100 the second arg is the original. Ho hum.
101 Do replacements over the replace dict -- used for mime boundary
102 '''
103 l1 = s1.strip().split('\n')
104 l2 = [replace.get(i,i) for i in s2.strip().split('\n')]
105 if l1 == l2:
106 return
107 s = difflib.SequenceMatcher(None, l1, l2)
108 res = []
109 for value, s1s, s1e, s2s, s2e in s.get_opcodes():
110 if value == 'equal':
111 for i in range(s1s, s1e):
112 res.append(' %s'%l1[i])
113 elif value == 'delete':
114 for i in range(s1s, s1e):
115 res.append('- %s'%l1[i])
116 elif value == 'insert':
117 for i in range(s2s, s2e):
118 res.append('+ %s'%l2[i])
119 elif value == 'replace':
120 for i, j in zip(range(s1s, s1e), range(s2s, s2e)):
121 res.append('- %s'%l1[i])
122 res.append('+ %s'%l2[j])
124 return res
126 class MailgwTestAbstractBase(unittest.TestCase, DiffHelper):
127 count = 0
128 schema = 'classic'
129 def setUp(self):
130 self.old_translate_ = mailgw._
131 roundupdb._ = mailgw._ = i18n.get_translation(language='C').gettext
132 self.__class__.count = self.__class__.count + 1
134 # and open the database / "instance"
135 self.db = memorydb.create('admin')
136 self.instance = Tracker()
137 self.instance.db = self.db
138 self.instance.config = self.db.config
139 self.instance.MailGW = MailGW
141 self.chef_id = self.db.user.create(username='Chef',
142 address='chef@bork.bork.bork', realname='Bork, Chef', roles='User')
143 self.richard_id = self.db.user.create(username='richard',
144 address='richard@test.test', roles='User')
145 self.mary_id = self.db.user.create(username='mary',
146 address='mary@test.test', roles='User', realname='Contrary, Mary')
147 self.john_id = self.db.user.create(username='john',
148 address='john@test.test', roles='User', realname='John Doe',
149 alternate_addresses='jondoe@test.test\njohn.doe@test.test')
150 self.rgg_id = self.db.user.create(username='rgg',
151 address='rgg@test.test', roles='User')
153 def tearDown(self):
154 roundupdb._ = mailgw._ = self.old_translate_
155 if os.path.exists(SENDMAILDEBUG):
156 os.remove(SENDMAILDEBUG)
157 self.db.close()
159 def _create_mailgw(self, message, args=()):
160 class MailGW(self.instance.MailGW):
161 def handle_message(self, message):
162 return self._handle_message(message)
163 handler = MailGW(self.instance, args)
164 handler.db = self.db
165 return handler
167 def _handle_mail(self, message, args=()):
168 handler = self._create_mailgw(message, args)
169 handler.trapExceptions = 0
170 return handler.main(StringIO(message))
172 def _get_mail(self):
173 f = open(SENDMAILDEBUG)
174 try:
175 return f.read()
176 finally:
177 f.close()
179 # Normal test-case used for both non-pgp test and a test while pgp
180 # is enabled, so this test is run in both test suites.
181 def testEmptyMessage(self):
182 nodeid = self._handle_mail('''Content-Type: text/plain;
183 charset="iso-8859-1"
184 From: Chef <chef@bork.bork.bork>
185 To: issue_tracker@your.tracker.email.domain.example
186 Cc: richard@test.test
187 Reply-To: chef@bork.bork.bork
188 Message-Id: <dummy_test_message_id>
189 Subject: [issue] Testing...
191 ''')
192 assert not os.path.exists(SENDMAILDEBUG)
193 self.assertEqual(self.db.issue.get(nodeid, 'title'), 'Testing...')
196 class MailgwTestCase(MailgwTestAbstractBase):
198 def testMessageWithFromInIt(self):
199 nodeid = self._handle_mail('''Content-Type: text/plain;
200 charset="iso-8859-1"
201 From: Chef <chef@bork.bork.bork>
202 To: issue_tracker@your.tracker.email.domain.example
203 Cc: richard@test.test
204 Reply-To: chef@bork.bork.bork
205 Message-Id: <dummy_test_message_id>
206 Subject: [issue] Testing...
208 From here to there!
209 ''')
210 assert not os.path.exists(SENDMAILDEBUG)
211 msgid = self.db.issue.get(nodeid, 'messages')[0]
212 self.assertEqual(self.db.msg.get(msgid, 'content'), 'From here to there!')
214 def testNoMessageId(self):
215 self.instance.config['MAIL_DOMAIN'] = 'example.com'
216 nodeid = self._handle_mail('''Content-Type: text/plain;
217 charset="iso-8859-1"
218 From: Chef <chef@bork.bork.bork>
219 To: issue_tracker@your.tracker.email.domain.example
220 Cc: richard@test.test
221 Reply-To: chef@bork.bork.bork
222 Subject: [issue] Testing...
224 Hi there!
225 ''')
226 assert not os.path.exists(SENDMAILDEBUG)
227 msgid = self.db.issue.get(nodeid, 'messages')[0]
228 messageid = self.db.msg.get(msgid, 'messageid')
229 x1, x2 = messageid.split('@')
230 self.assertEqual(x2, 'example.com>')
231 x = x1.split('.')[-1]
232 self.assertEqual(x, 'issueNone')
233 nodeid = self._handle_mail('''Content-Type: text/plain;
234 charset="iso-8859-1"
235 From: Chef <chef@bork.bork.bork>
236 To: issue_tracker@your.tracker.email.domain.example
237 Subject: [issue%(nodeid)s] Testing...
239 Just a test reply
240 '''%locals())
241 msgid = self.db.issue.get(nodeid, 'messages')[-1]
242 messageid = self.db.msg.get(msgid, 'messageid')
243 x1, x2 = messageid.split('@')
244 self.assertEqual(x2, 'example.com>')
245 x = x1.split('.')[-1]
246 self.assertEqual(x, "issue%s"%nodeid)
248 def testOptions(self):
249 nodeid = self._handle_mail('''Content-Type: text/plain;
250 charset="iso-8859-1"
251 From: Chef <chef@bork.bork.bork>
252 To: issue_tracker@your.tracker.email.domain.example
253 Message-Id: <dummy_test_message_id>
254 Reply-To: chef@bork.bork.bork
255 Subject: [issue] Testing...
257 Hi there!
258 ''', (('-C', 'issue'), ('-S', 'status=chatting;priority=critical')))
259 self.assertEqual(self.db.issue.get(nodeid, 'status'), '3')
260 self.assertEqual(self.db.issue.get(nodeid, 'priority'), '1')
262 def testOptionsMulti(self):
263 nodeid = self._handle_mail('''Content-Type: text/plain;
264 charset="iso-8859-1"
265 From: Chef <chef@bork.bork.bork>
266 To: issue_tracker@your.tracker.email.domain.example
267 Message-Id: <dummy_test_message_id>
268 Reply-To: chef@bork.bork.bork
269 Subject: [issue] Testing...
271 Hi there!
272 ''', (('-C', 'issue'), ('-S', 'status=chatting'), ('-S', 'priority=critical')))
273 self.assertEqual(self.db.issue.get(nodeid, 'status'), '3')
274 self.assertEqual(self.db.issue.get(nodeid, 'priority'), '1')
276 def testOptionClass(self):
277 nodeid = self._handle_mail('''Content-Type: text/plain;
278 charset="iso-8859-1"
279 From: Chef <chef@bork.bork.bork>
280 To: issue_tracker@your.tracker.email.domain.example
281 Message-Id: <dummy_test_message_id>
282 Reply-To: chef@bork.bork.bork
283 Subject: [issue] Testing... [status=chatting;priority=critical]
285 Hi there!
286 ''', (('-c', 'issue'),))
287 self.assertEqual(self.db.issue.get(nodeid, 'title'), 'Testing...')
288 self.assertEqual(self.db.issue.get(nodeid, 'status'), '3')
289 self.assertEqual(self.db.issue.get(nodeid, 'priority'), '1')
291 def doNewIssue(self):
292 nodeid = self._handle_mail('''Content-Type: text/plain;
293 charset="iso-8859-1"
294 From: Chef <chef@bork.bork.bork>
295 To: issue_tracker@your.tracker.email.domain.example
296 Cc: richard@test.test
297 Message-Id: <dummy_test_message_id>
298 Subject: [issue] Testing...
300 This is a test submission of a new issue.
301 ''')
302 assert not os.path.exists(SENDMAILDEBUG)
303 l = self.db.issue.get(nodeid, 'nosy')
304 l.sort()
305 self.assertEqual(l, [self.chef_id, self.richard_id])
306 return nodeid
308 def testNewIssue(self):
309 self.doNewIssue()
311 def testNewIssueNosy(self):
312 self.instance.config.ADD_AUTHOR_TO_NOSY = 'yes'
313 nodeid = self._handle_mail('''Content-Type: text/plain;
314 charset="iso-8859-1"
315 From: Chef <chef@bork.bork.bork>
316 To: issue_tracker@your.tracker.email.domain.example
317 Cc: richard@test.test
318 Message-Id: <dummy_test_message_id>
319 Subject: [issue] Testing...
321 This is a test submission of a new issue.
322 ''')
323 assert not os.path.exists(SENDMAILDEBUG)
324 l = self.db.issue.get(nodeid, 'nosy')
325 l.sort()
326 self.assertEqual(l, [self.chef_id, self.richard_id])
328 def testAlternateAddress(self):
329 self._handle_mail('''Content-Type: text/plain;
330 charset="iso-8859-1"
331 From: John Doe <john.doe@test.test>
332 To: issue_tracker@your.tracker.email.domain.example
333 Message-Id: <dummy_test_message_id>
334 Subject: [issue] Testing...
336 This is a test submission of a new issue.
337 ''')
338 userlist = self.db.user.list()
339 assert not os.path.exists(SENDMAILDEBUG)
340 self.assertEqual(userlist, self.db.user.list(),
341 "user created when it shouldn't have been")
343 def testNewIssueNoClass(self):
344 self._handle_mail('''Content-Type: text/plain;
345 charset="iso-8859-1"
346 From: Chef <chef@bork.bork.bork>
347 To: issue_tracker@your.tracker.email.domain.example
348 Cc: richard@test.test
349 Message-Id: <dummy_test_message_id>
350 Subject: Testing...
352 This is a test submission of a new issue.
353 ''')
354 assert not os.path.exists(SENDMAILDEBUG)
356 def testNewIssueAuthMsg(self):
357 # TODO: fix the damn config - this is apalling
358 self.db.config.MESSAGES_TO_AUTHOR = 'yes'
359 self._handle_mail('''Content-Type: text/plain;
360 charset="iso-8859-1"
361 From: Chef <chef@bork.bork.bork>
362 To: issue_tracker@your.tracker.email.domain.example
363 Message-Id: <dummy_test_message_id>
364 Subject: [issue] Testing... [nosy=mary; assignedto=richard]
366 This is a test submission of a new issue.
367 ''')
368 self.compareMessages(self._get_mail(),
369 '''FROM: roundup-admin@your.tracker.email.domain.example
370 TO: chef@bork.bork.bork, mary@test.test, richard@test.test
371 Content-Type: text/plain; charset="utf-8"
372 Subject: [issue1] Testing...
373 To: chef@bork.bork.bork, mary@test.test, richard@test.test
374 From: "Bork, Chef" <issue_tracker@your.tracker.email.domain.example>
375 Reply-To: Roundup issue tracker
376 <issue_tracker@your.tracker.email.domain.example>
377 MIME-Version: 1.0
378 Message-Id: <dummy_test_message_id>
379 X-Roundup-Name: Roundup issue tracker
380 X-Roundup-Loop: hello
381 X-Roundup-Issue-Status: unread
382 Content-Transfer-Encoding: quoted-printable
385 New submission from Bork, Chef <chef@bork.bork.bork>:
387 This is a test submission of a new issue.
389 ----------
390 assignedto: richard
391 messages: 1
392 nosy: Chef, mary, richard
393 status: unread
394 title: Testing...
396 _______________________________________________________________________
397 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
398 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
399 _______________________________________________________________________
400 ''')
402 def testNewIssueNoAuthorInfo(self):
403 self.db.config.MAIL_ADD_AUTHORINFO = 'no'
404 self._handle_mail('''Content-Type: text/plain;
405 charset="iso-8859-1"
406 From: Chef <chef@bork.bork.bork>
407 To: issue_tracker@your.tracker.email.domain.example
408 Message-Id: <dummy_test_message_id>
409 Subject: [issue] Testing... [nosy=mary; assignedto=richard]
411 This is a test submission of a new issue.
412 ''')
413 self.compareMessages(self._get_mail(),
414 '''FROM: roundup-admin@your.tracker.email.domain.example
415 TO: chef@bork.bork.bork, mary@test.test, richard@test.test
416 Content-Type: text/plain; charset="utf-8"
417 Subject: [issue1] Testing...
418 To: mary@test.test, richard@test.test
419 From: "Bork, Chef" <issue_tracker@your.tracker.email.domain.example>
420 Reply-To: Roundup issue tracker
421 <issue_tracker@your.tracker.email.domain.example>
422 MIME-Version: 1.0
423 Message-Id: <dummy_test_message_id>
424 X-Roundup-Name: Roundup issue tracker
425 X-Roundup-Loop: hello
426 X-Roundup-Issue-Status: unread
427 Content-Transfer-Encoding: quoted-printable
429 This is a test submission of a new issue.
431 ----------
432 assignedto: richard
433 messages: 1
434 nosy: Chef, mary, richard
435 status: unread
436 title: Testing...
438 _______________________________________________________________________
439 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
440 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
441 _______________________________________________________________________
442 ''')
444 def testNewIssueNoAuthorEmail(self):
445 self.db.config.MAIL_ADD_AUTHOREMAIL = 'no'
446 self._handle_mail('''Content-Type: text/plain;
447 charset="iso-8859-1"
448 From: Chef <chef@bork.bork.bork>
449 To: issue_tracker@your.tracker.email.domain.example
450 Message-Id: <dummy_test_message_id>
451 Subject: [issue] Testing... [nosy=mary; assignedto=richard]
453 This is a test submission of a new issue.
454 ''')
455 self.compareMessages(self._get_mail(),
456 '''FROM: roundup-admin@your.tracker.email.domain.example
457 TO: chef@bork.bork.bork, mary@test.test, richard@test.test
458 Content-Type: text/plain; charset="utf-8"
459 Subject: [issue1] Testing...
460 To: mary@test.test, richard@test.test
461 From: "Bork, Chef" <issue_tracker@your.tracker.email.domain.example>
462 Reply-To: Roundup issue tracker
463 <issue_tracker@your.tracker.email.domain.example>
464 MIME-Version: 1.0
465 Message-Id: <dummy_test_message_id>
466 X-Roundup-Name: Roundup issue tracker
467 X-Roundup-Loop: hello
468 X-Roundup-Issue-Status: unread
469 Content-Transfer-Encoding: quoted-printable
471 New submission from Bork, Chef:
473 This is a test submission of a new issue.
475 ----------
476 assignedto: richard
477 messages: 1
478 nosy: Chef, mary, richard
479 status: unread
480 title: Testing...
482 _______________________________________________________________________
483 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
484 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
485 _______________________________________________________________________
486 ''')
488 multipart_msg = '''From: mary <mary@test.test>
489 To: issue_tracker@your.tracker.email.domain.example
490 Message-Id: <followup_dummy_id>
491 In-Reply-To: <dummy_test_message_id>
492 Subject: [issue1] Testing...
493 Content-Type: multipart/mixed; boundary="bxyzzy"
494 Content-Disposition: inline
497 --bxyzzy
498 Content-Type: multipart/alternative; boundary="bCsyhTFzCvuiizWE"
499 Content-Disposition: inline
501 --bCsyhTFzCvuiizWE
502 Content-Type: text/plain; charset=us-ascii
503 Content-Disposition: inline
505 test attachment first text/plain
507 --bCsyhTFzCvuiizWE
508 Content-Type: application/octet-stream
509 Content-Disposition: attachment; filename="first.dvi"
510 Content-Transfer-Encoding: base64
512 SnVzdCBhIHRlc3QgAQo=
514 --bCsyhTFzCvuiizWE
515 Content-Type: text/plain; charset=us-ascii
516 Content-Disposition: inline
518 test attachment second text/plain
520 --bCsyhTFzCvuiizWE
521 Content-Type: text/html
522 Content-Disposition: inline
524 <html>
525 to be ignored.
526 </html>
528 --bCsyhTFzCvuiizWE--
530 --bxyzzy
531 Content-Type: multipart/alternative; boundary="bCsyhTFzCvuiizWF"
532 Content-Disposition: inline
534 --bCsyhTFzCvuiizWF
535 Content-Type: text/plain; charset=us-ascii
536 Content-Disposition: inline
538 test attachment third text/plain
540 --bCsyhTFzCvuiizWF
541 Content-Type: application/octet-stream
542 Content-Disposition: attachment; filename="second.dvi"
543 Content-Transfer-Encoding: base64
545 SnVzdCBhIHRlc3QK
547 --bCsyhTFzCvuiizWF--
549 --bxyzzy--
550 '''
552 multipart_msg_latin1 = '''From: mary <mary@test.test>
553 To: issue_tracker@your.tracker.email.domain.example
554 Message-Id: <followup_dummy_id>
555 In-Reply-To: <dummy_test_message_id>
556 Subject: [issue1] Testing...
557 Content-Type: multipart/alternative; boundary=001485f339f8f361fb049188dbba
560 --001485f339f8f361fb049188dbba
561 Content-Type: text/plain; charset=ISO-8859-1
562 Content-Transfer-Encoding: quoted-printable
564 umlaut =E4=F6=FC=C4=D6=DC=DF
566 --001485f339f8f361fb049188dbba
567 Content-Type: text/html; charset=ISO-8859-1
568 Content-Transfer-Encoding: quoted-printable
570 <html>umlaut =E4=F6=FC=C4=D6=DC=DF</html>
572 --001485f339f8f361fb049188dbba--
573 '''
575 multipart_msg_rfc822 = '''From: mary <mary@test.test>
576 To: issue_tracker@your.tracker.email.domain.example
577 Message-Id: <followup_dummy_id>
578 In-Reply-To: <dummy_test_message_id>
579 Subject: [issue1] Testing...
580 Content-Type: multipart/mixed; boundary=001485f339f8f361fb049188dbba
582 This is a multi-part message in MIME format.
583 --001485f339f8f361fb049188dbba
584 Content-Type: text/plain; charset=ISO-8859-15
585 Content-Transfer-Encoding: 7bit
587 First part: Text
589 --001485f339f8f361fb049188dbba
590 Content-Type: message/rfc822; name="Fwd: Original email subject.eml"
591 Content-Transfer-Encoding: 7bit
592 Content-Disposition: attachment; filename="Fwd: Original email subject.eml"
594 Message-Id: <followup_dummy_id_2>
595 In-Reply-To: <dummy_test_message_id_2>
596 MIME-Version: 1.0
597 Subject: Fwd: Original email subject
598 Date: Mon, 23 Aug 2010 08:23:33 +0200
599 Content-Type: multipart/alternative; boundary="090500050101020406060002"
601 This is a multi-part message in MIME format.
602 --090500050101020406060002
603 Content-Type: text/plain; charset=ISO-8859-15; format=flowed
604 Content-Transfer-Encoding: 7bit
606 some text in inner email
607 ========================
609 --090500050101020406060002
610 Content-Type: text/html; charset=ISO-8859-15
611 Content-Transfer-Encoding: 7bit
613 <html>
614 some text in inner email
615 ========================
616 </html>
618 --090500050101020406060002--
620 --001485f339f8f361fb049188dbba--
621 '''
623 def testMultipartKeepAlternatives(self):
624 self.doNewIssue()
625 self._handle_mail(self.multipart_msg)
626 messages = self.db.issue.get('1', 'messages')
627 messages.sort()
628 msg = self.db.msg.getnode (messages[-1])
629 assert(len(msg.files) == 5)
630 names = {0 : 'first.dvi', 4 : 'second.dvi'}
631 content = {3 : 'test attachment third text/plain\n',
632 4 : 'Just a test\n'}
633 for n, id in enumerate (msg.files):
634 f = self.db.file.getnode (id)
635 self.assertEqual(f.name, names.get (n, 'unnamed'))
636 if n in content :
637 self.assertEqual(f.content, content [n])
638 self.assertEqual(msg.content, 'test attachment second text/plain')
640 def testMultipartSeveralAttachmentMessages(self):
641 self.doNewIssue()
642 self._handle_mail(self.multipart_msg)
643 messages = self.db.issue.get('1', 'messages')
644 messages.sort()
645 self.assertEqual(messages[-1], '2')
646 msg = self.db.msg.getnode (messages[-1])
647 self.assertEqual(len(msg.files), 5)
648 issue = self.db.issue.getnode ('1')
649 self.assertEqual(len(issue.files), 5)
650 names = {0 : 'first.dvi', 4 : 'second.dvi'}
651 content = {3 : 'test attachment third text/plain\n',
652 4 : 'Just a test\n'}
653 for n, id in enumerate (msg.files):
654 f = self.db.file.getnode (id)
655 self.assertEqual(f.name, names.get (n, 'unnamed'))
656 if n in content :
657 self.assertEqual(f.content, content [n])
658 self.assertEqual(msg.content, 'test attachment second text/plain')
659 self.assertEqual(msg.files, ['1', '2', '3', '4', '5'])
660 self.assertEqual(issue.files, ['1', '2', '3', '4', '5'])
662 self._handle_mail(self.multipart_msg)
663 issue = self.db.issue.getnode ('1')
664 self.assertEqual(len(issue.files), 10)
665 messages = self.db.issue.get('1', 'messages')
666 messages.sort()
667 self.assertEqual(messages[-1], '3')
668 msg = self.db.msg.getnode (messages[-1])
669 self.assertEqual(issue.files, [str(i+1) for i in range(10)])
670 self.assertEqual(msg.files, ['6', '7', '8', '9', '10'])
672 def testMultipartKeepFiles(self):
673 self.doNewIssue()
674 self._handle_mail(self.multipart_msg)
675 messages = self.db.issue.get('1', 'messages')
676 messages.sort()
677 msg = self.db.msg.getnode (messages[-1])
678 self.assertEqual(len(msg.files), 5)
679 issue = self.db.issue.getnode ('1')
680 self.assertEqual(len(issue.files), 5)
681 names = {0 : 'first.dvi', 4 : 'second.dvi'}
682 content = {3 : 'test attachment third text/plain\n',
683 4 : 'Just a test\n'}
684 for n, id in enumerate (msg.files):
685 f = self.db.file.getnode (id)
686 self.assertEqual(f.name, names.get (n, 'unnamed'))
687 if n in content :
688 self.assertEqual(f.content, content [n])
689 self.assertEqual(msg.content, 'test attachment second text/plain')
690 self._handle_mail('''From: mary <mary@test.test>
691 To: issue_tracker@your.tracker.email.domain.example
692 Message-Id: <followup_dummy_id2>
693 In-Reply-To: <dummy_test_message_id>
694 Subject: [issue1] Testing...
696 This ist a message without attachment
697 ''')
698 issue = self.db.issue.getnode ('1')
699 self.assertEqual(len(issue.files), 5)
700 self.assertEqual(issue.files, ['1', '2', '3', '4', '5'])
702 def testMultipartDropAlternatives(self):
703 self.doNewIssue()
704 self.db.config.MAILGW_IGNORE_ALTERNATIVES = True
705 self._handle_mail(self.multipart_msg)
706 messages = self.db.issue.get('1', 'messages')
707 messages.sort()
708 msg = self.db.msg.getnode (messages[-1])
709 self.assertEqual(len(msg.files), 2)
710 names = {1 : 'second.dvi'}
711 content = {0 : 'test attachment third text/plain\n',
712 1 : 'Just a test\n'}
713 for n, id in enumerate (msg.files):
714 f = self.db.file.getnode (id)
715 self.assertEqual(f.name, names.get (n, 'unnamed'))
716 if n in content :
717 self.assertEqual(f.content, content [n])
718 self.assertEqual(msg.content, 'test attachment second text/plain')
720 def testMultipartCharsetUTF8NoAttach(self):
721 c = 'umlaut \xc3\xa4\xc3\xb6\xc3\xbc\xc3\x84\xc3\x96\xc3\x9c\xc3\x9f'
722 self.doNewIssue()
723 self.db.config.NOSY_MAX_ATTACHMENT_SIZE = 0
724 self._handle_mail(self.multipart_msg_latin1)
725 messages = self.db.issue.get('1', 'messages')
726 messages.sort()
727 msg = self.db.msg.getnode (messages[-1])
728 self.assertEqual(len(msg.files), 1)
729 name = 'unnamed'
730 content = '<html>' + c + '</html>\n'
731 for n, id in enumerate (msg.files):
732 f = self.db.file.getnode (id)
733 self.assertEqual(f.name, name)
734 self.assertEqual(f.content, content)
735 self.assertEqual(msg.content, c)
736 self.compareMessages(self._get_mail(),
737 '''FROM: roundup-admin@your.tracker.email.domain.example
738 TO: chef@bork.bork.bork, richard@test.test
739 Content-Type: text/plain; charset="utf-8"
740 Subject: [issue1] Testing...
741 To: chef@bork.bork.bork, richard@test.test
742 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
743 Reply-To: Roundup issue tracker
744 <issue_tracker@your.tracker.email.domain.example>
745 MIME-Version: 1.0
746 Message-Id: <followup_dummy_id>
747 In-Reply-To: <dummy_test_message_id>
748 X-Roundup-Name: Roundup issue tracker
749 X-Roundup-Loop: hello
750 X-Roundup-Issue-Status: chatting
751 X-Roundup-Issue-Files: unnamed
752 Content-Transfer-Encoding: quoted-printable
755 Contrary, Mary <mary@test.test> added the comment:
757 umlaut =C3=A4=C3=B6=C3=BC=C3=84=C3=96=C3=9C=C3=9F
758 File 'unnamed' not attached - you can download it from http://tracker.examp=
759 le/cgi-bin/roundup.cgi/bugs/file1.
761 ----------
762 status: unread -> chatting
764 _______________________________________________________________________
765 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
766 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
767 _______________________________________________________________________
768 ''')
770 def testMultipartCharsetLatin1NoAttach(self):
771 c = 'umlaut \xc3\xa4\xc3\xb6\xc3\xbc\xc3\x84\xc3\x96\xc3\x9c\xc3\x9f'
772 self.doNewIssue()
773 self.db.config.NOSY_MAX_ATTACHMENT_SIZE = 0
774 self.db.config.MAIL_CHARSET = 'iso-8859-1'
775 self._handle_mail(self.multipart_msg_latin1)
776 messages = self.db.issue.get('1', 'messages')
777 messages.sort()
778 msg = self.db.msg.getnode (messages[-1])
779 self.assertEqual(len(msg.files), 1)
780 name = 'unnamed'
781 content = '<html>' + c + '</html>\n'
782 for n, id in enumerate (msg.files):
783 f = self.db.file.getnode (id)
784 self.assertEqual(f.name, name)
785 self.assertEqual(f.content, content)
786 self.assertEqual(msg.content, c)
787 self.compareMessages(self._get_mail(),
788 '''FROM: roundup-admin@your.tracker.email.domain.example
789 TO: chef@bork.bork.bork, richard@test.test
790 Content-Type: text/plain; charset="iso-8859-1"
791 Subject: [issue1] Testing...
792 To: chef@bork.bork.bork, richard@test.test
793 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
794 Reply-To: Roundup issue tracker
795 <issue_tracker@your.tracker.email.domain.example>
796 MIME-Version: 1.0
797 Message-Id: <followup_dummy_id>
798 In-Reply-To: <dummy_test_message_id>
799 X-Roundup-Name: Roundup issue tracker
800 X-Roundup-Loop: hello
801 X-Roundup-Issue-Status: chatting
802 X-Roundup-Issue-Files: unnamed
803 Content-Transfer-Encoding: quoted-printable
806 Contrary, Mary <mary@test.test> added the comment:
808 umlaut =E4=F6=FC=C4=D6=DC=DF
809 File 'unnamed' not attached - you can download it from http://tracker.examp=
810 le/cgi-bin/roundup.cgi/bugs/file1.
812 ----------
813 status: unread -> chatting
815 _______________________________________________________________________
816 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
817 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
818 _______________________________________________________________________
819 ''')
821 def testMultipartCharsetUTF8AttachFile(self):
822 c = 'umlaut \xc3\xa4\xc3\xb6\xc3\xbc\xc3\x84\xc3\x96\xc3\x9c\xc3\x9f'
823 self.doNewIssue()
824 self._handle_mail(self.multipart_msg_latin1)
825 messages = self.db.issue.get('1', 'messages')
826 messages.sort()
827 msg = self.db.msg.getnode (messages[-1])
828 self.assertEqual(len(msg.files), 1)
829 name = 'unnamed'
830 content = '<html>' + c + '</html>\n'
831 for n, id in enumerate (msg.files):
832 f = self.db.file.getnode (id)
833 self.assertEqual(f.name, name)
834 self.assertEqual(f.content, content)
835 self.assertEqual(msg.content, c)
836 self.compareMessages(self._get_mail(),
837 '''FROM: roundup-admin@your.tracker.email.domain.example
838 TO: chef@bork.bork.bork, richard@test.test
839 Content-Type: multipart/mixed; boundary="utf-8"
840 Subject: [issue1] Testing...
841 To: chef@bork.bork.bork, richard@test.test
842 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
843 Reply-To: Roundup issue tracker
844 <issue_tracker@your.tracker.email.domain.example>
845 MIME-Version: 1.0
846 Message-Id: <followup_dummy_id>
847 In-Reply-To: <dummy_test_message_id>
848 X-Roundup-Name: Roundup issue tracker
849 X-Roundup-Loop: hello
850 X-Roundup-Issue-Status: chatting
851 X-Roundup-Issue-Files: unnamed
852 Content-Transfer-Encoding: quoted-printable
855 --utf-8
856 MIME-Version: 1.0
857 Content-Type: text/plain; charset="utf-8"
858 Content-Transfer-Encoding: quoted-printable
861 Contrary, Mary <mary@test.test> added the comment:
863 umlaut =C3=A4=C3=B6=C3=BC=C3=84=C3=96=C3=9C=C3=9F
865 ----------
866 status: unread -> chatting
868 _______________________________________________________________________
869 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
870 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
871 _______________________________________________________________________
872 --utf-8
873 Content-Type: text/html
874 MIME-Version: 1.0
875 Content-Transfer-Encoding: base64
876 Content-Disposition: attachment;
877 filename="unnamed"
879 PGh0bWw+dW1sYXV0IMOkw7bDvMOEw5bDnMOfPC9odG1sPgo=
881 --utf-8--
882 ''')
884 def testMultipartCharsetLatin1AttachFile(self):
885 c = 'umlaut \xc3\xa4\xc3\xb6\xc3\xbc\xc3\x84\xc3\x96\xc3\x9c\xc3\x9f'
886 self.doNewIssue()
887 self.db.config.MAIL_CHARSET = 'iso-8859-1'
888 self._handle_mail(self.multipart_msg_latin1)
889 messages = self.db.issue.get('1', 'messages')
890 messages.sort()
891 msg = self.db.msg.getnode (messages[-1])
892 self.assertEqual(len(msg.files), 1)
893 name = 'unnamed'
894 content = '<html>' + c + '</html>\n'
895 for n, id in enumerate (msg.files):
896 f = self.db.file.getnode (id)
897 self.assertEqual(f.name, name)
898 self.assertEqual(f.content, content)
899 self.assertEqual(msg.content, c)
900 self.compareMessages(self._get_mail(),
901 '''FROM: roundup-admin@your.tracker.email.domain.example
902 TO: chef@bork.bork.bork, richard@test.test
903 Content-Type: multipart/mixed; boundary="utf-8"
904 Subject: [issue1] Testing...
905 To: chef@bork.bork.bork, richard@test.test
906 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
907 Reply-To: Roundup issue tracker
908 <issue_tracker@your.tracker.email.domain.example>
909 MIME-Version: 1.0
910 Message-Id: <followup_dummy_id>
911 In-Reply-To: <dummy_test_message_id>
912 X-Roundup-Name: Roundup issue tracker
913 X-Roundup-Loop: hello
914 X-Roundup-Issue-Status: chatting
915 X-Roundup-Issue-Files: unnamed
916 Content-Transfer-Encoding: quoted-printable
919 --utf-8
920 MIME-Version: 1.0
921 Content-Type: text/plain; charset="iso-8859-1"
922 Content-Transfer-Encoding: quoted-printable
925 Contrary, Mary <mary@test.test> added the comment:
927 umlaut =E4=F6=FC=C4=D6=DC=DF
929 ----------
930 status: unread -> chatting
932 _______________________________________________________________________
933 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
934 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
935 _______________________________________________________________________
936 --utf-8
937 Content-Type: text/html
938 MIME-Version: 1.0
939 Content-Transfer-Encoding: base64
940 Content-Disposition: attachment;
941 filename="unnamed"
943 PGh0bWw+dW1sYXV0IMOkw7bDvMOEw5bDnMOfPC9odG1sPgo=
945 --utf-8--
946 ''')
948 def testMultipartRFC822(self):
949 self.doNewIssue()
950 self._handle_mail(self.multipart_msg_rfc822)
951 messages = self.db.issue.get('1', 'messages')
952 messages.sort()
953 msg = self.db.msg.getnode (messages[-1])
954 self.assertEqual(len(msg.files), 1)
955 name = "Fwd: Original email subject.eml"
956 for n, id in enumerate (msg.files):
957 f = self.db.file.getnode (id)
958 self.assertEqual(f.name, name)
959 self.assertEqual(msg.content, 'First part: Text')
960 self.compareMessages(self._get_mail(),
961 '''TO: chef@bork.bork.bork, richard@test.test
962 Content-Type: text/plain; charset="utf-8"
963 Subject: [issue1] Testing...
964 To: chef@bork.bork.bork, richard@test.test
965 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
966 Reply-To: Roundup issue tracker
967 <issue_tracker@your.tracker.email.domain.example>
968 MIME-Version: 1.0
969 Message-Id: <followup_dummy_id>
970 In-Reply-To: <dummy_test_message_id>
971 X-Roundup-Name: Roundup issue tracker
972 X-Roundup-Loop: hello
973 X-Roundup-Issue-Status: chatting
974 X-Roundup-Issue-Files: Fwd: Original email subject.eml
975 Content-Transfer-Encoding: quoted-printable
978 --utf-8
979 MIME-Version: 1.0
980 Content-Type: text/plain; charset="utf-8"
981 Content-Transfer-Encoding: quoted-printable
984 Contrary, Mary <mary@test.test> added the comment:
986 First part: Text
988 ----------
989 status: unread -> chatting
991 _______________________________________________________________________
992 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
993 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
994 _______________________________________________________________________
995 --utf-8
996 Content-Type: message/rfc822
997 MIME-Version: 1.0
998 Content-Disposition: attachment;
999 filename="Fwd: Original email subject.eml"
1001 Message-Id: <followup_dummy_id_2>
1002 In-Reply-To: <dummy_test_message_id_2>
1003 MIME-Version: 1.0
1004 Subject: Fwd: Original email subject
1005 Date: Mon, 23 Aug 2010 08:23:33 +0200
1006 Content-Type: multipart/alternative; boundary="090500050101020406060002"
1008 This is a multi-part message in MIME format.
1009 --090500050101020406060002
1010 Content-Type: text/plain; charset=ISO-8859-15; format=flowed
1011 Content-Transfer-Encoding: 7bit
1013 some text in inner email
1014 ========================
1016 --090500050101020406060002
1017 Content-Type: text/html; charset=ISO-8859-15
1018 Content-Transfer-Encoding: 7bit
1020 <html>
1021 some text in inner email
1022 ========================
1023 </html>
1025 --090500050101020406060002--
1027 --utf-8--
1028 ''')
1030 def testMultipartRFC822Unpack(self):
1031 self.doNewIssue()
1032 self.db.config.MAILGW_UNPACK_RFC822 = True
1033 self._handle_mail(self.multipart_msg_rfc822)
1034 messages = self.db.issue.get('1', 'messages')
1035 messages.sort()
1036 msg = self.db.msg.getnode (messages[-1])
1037 self.assertEqual(len(msg.files), 2)
1038 t = 'some text in inner email\n========================\n'
1039 content = {0 : t, 1 : '<html>\n' + t + '</html>\n'}
1040 for n, id in enumerate (msg.files):
1041 f = self.db.file.getnode (id)
1042 self.assertEqual(f.name, 'unnamed')
1043 if n in content :
1044 self.assertEqual(f.content, content [n])
1045 self.assertEqual(msg.content, 'First part: Text')
1047 def testSimpleFollowup(self):
1048 self.doNewIssue()
1049 self._handle_mail('''Content-Type: text/plain;
1050 charset="iso-8859-1"
1051 From: mary <mary@test.test>
1052 To: issue_tracker@your.tracker.email.domain.example
1053 Message-Id: <followup_dummy_id>
1054 In-Reply-To: <dummy_test_message_id>
1055 Subject: [issue1] Testing...
1057 This is a second followup
1058 ''')
1059 self.compareMessages(self._get_mail(),
1060 '''FROM: roundup-admin@your.tracker.email.domain.example
1061 TO: chef@bork.bork.bork, richard@test.test
1062 Content-Type: text/plain; charset="utf-8"
1063 Subject: [issue1] Testing...
1064 To: chef@bork.bork.bork, richard@test.test
1065 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
1066 Reply-To: Roundup issue tracker
1067 <issue_tracker@your.tracker.email.domain.example>
1068 MIME-Version: 1.0
1069 Message-Id: <followup_dummy_id>
1070 In-Reply-To: <dummy_test_message_id>
1071 X-Roundup-Name: Roundup issue tracker
1072 X-Roundup-Loop: hello
1073 X-Roundup-Issue-Status: chatting
1074 Content-Transfer-Encoding: quoted-printable
1077 Contrary, Mary <mary@test.test> added the comment:
1079 This is a second followup
1081 ----------
1082 status: unread -> chatting
1084 _______________________________________________________________________
1085 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1086 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1087 _______________________________________________________________________
1088 ''')
1090 def testFollowup(self):
1091 self.doNewIssue()
1093 self._handle_mail('''Content-Type: text/plain;
1094 charset="iso-8859-1"
1095 From: richard <richard@test.test>
1096 To: issue_tracker@your.tracker.email.domain.example
1097 Message-Id: <followup_dummy_id>
1098 In-Reply-To: <dummy_test_message_id>
1099 Subject: [issue1] Testing... [assignedto=mary; nosy=+john]
1101 This is a followup
1102 ''')
1103 l = self.db.issue.get('1', 'nosy')
1104 l.sort()
1105 self.assertEqual(l, [self.chef_id, self.richard_id, self.mary_id,
1106 self.john_id])
1108 self.compareMessages(self._get_mail(),
1109 '''FROM: roundup-admin@your.tracker.email.domain.example
1110 TO: chef@bork.bork.bork, john@test.test, mary@test.test
1111 Content-Type: text/plain; charset="utf-8"
1112 Subject: [issue1] Testing...
1113 To: chef@bork.bork.bork, john@test.test, mary@test.test
1114 From: richard <issue_tracker@your.tracker.email.domain.example>
1115 Reply-To: Roundup issue tracker
1116 <issue_tracker@your.tracker.email.domain.example>
1117 MIME-Version: 1.0
1118 Message-Id: <followup_dummy_id>
1119 In-Reply-To: <dummy_test_message_id>
1120 X-Roundup-Name: Roundup issue tracker
1121 X-Roundup-Loop: hello
1122 X-Roundup-Issue-Status: chatting
1123 Content-Transfer-Encoding: quoted-printable
1126 richard <richard@test.test> added the comment:
1128 This is a followup
1130 ----------
1131 assignedto: -> mary
1132 nosy: +john, mary
1133 status: unread -> chatting
1135 _______________________________________________________________________
1136 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1137 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1138 _______________________________________________________________________
1139 ''')
1141 def testFollowupNoSubjectChange(self):
1142 self.db.config.MAILGW_SUBJECT_UPDATES_TITLE = 'no'
1143 self.doNewIssue()
1145 self._handle_mail('''Content-Type: text/plain;
1146 charset="iso-8859-1"
1147 From: richard <richard@test.test>
1148 To: issue_tracker@your.tracker.email.domain.example
1149 Message-Id: <followup_dummy_id>
1150 In-Reply-To: <dummy_test_message_id>
1151 Subject: [issue1] Wrzlbrmft... [assignedto=mary; nosy=+john]
1153 This is a followup
1154 ''')
1155 l = self.db.issue.get('1', 'nosy')
1156 l.sort()
1157 self.assertEqual(l, [self.chef_id, self.richard_id, self.mary_id,
1158 self.john_id])
1160 self.compareMessages(self._get_mail(),
1161 '''FROM: roundup-admin@your.tracker.email.domain.example
1162 TO: chef@bork.bork.bork, john@test.test, mary@test.test
1163 Content-Type: text/plain; charset="utf-8"
1164 Subject: [issue1] Testing...
1165 To: chef@bork.bork.bork, john@test.test, mary@test.test
1166 From: richard <issue_tracker@your.tracker.email.domain.example>
1167 Reply-To: Roundup issue tracker
1168 <issue_tracker@your.tracker.email.domain.example>
1169 MIME-Version: 1.0
1170 Message-Id: <followup_dummy_id>
1171 In-Reply-To: <dummy_test_message_id>
1172 X-Roundup-Name: Roundup issue tracker
1173 X-Roundup-Loop: hello
1174 X-Roundup-Issue-Status: chatting
1175 Content-Transfer-Encoding: quoted-printable
1178 richard <richard@test.test> added the comment:
1180 This is a followup
1182 ----------
1183 assignedto: -> mary
1184 nosy: +john, mary
1185 status: unread -> chatting
1187 _______________________________________________________________________
1188 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1189 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1190 _______________________________________________________________________
1191 ''')
1192 self.assertEqual(self.db.issue.get('1','title'), 'Testing...')
1194 def testFollowupExplicitSubjectChange(self):
1195 self.doNewIssue()
1197 self._handle_mail('''Content-Type: text/plain;
1198 charset="iso-8859-1"
1199 From: richard <richard@test.test>
1200 To: issue_tracker@your.tracker.email.domain.example
1201 Message-Id: <followup_dummy_id>
1202 In-Reply-To: <dummy_test_message_id>
1203 Subject: [issue1] Wrzlbrmft... [assignedto=mary; nosy=+john; title=new title]
1205 This is a followup
1206 ''')
1207 l = self.db.issue.get('1', 'nosy')
1208 l.sort()
1209 self.assertEqual(l, [self.chef_id, self.richard_id, self.mary_id,
1210 self.john_id])
1212 self.compareMessages(self._get_mail(),
1213 '''FROM: roundup-admin@your.tracker.email.domain.example
1214 TO: chef@bork.bork.bork, john@test.test, mary@test.test
1215 Content-Type: text/plain; charset="utf-8"
1216 Subject: [issue1] new title
1217 To: chef@bork.bork.bork, john@test.test, mary@test.test
1218 From: richard <issue_tracker@your.tracker.email.domain.example>
1219 Reply-To: Roundup issue tracker
1220 <issue_tracker@your.tracker.email.domain.example>
1221 MIME-Version: 1.0
1222 Message-Id: <followup_dummy_id>
1223 In-Reply-To: <dummy_test_message_id>
1224 X-Roundup-Name: Roundup issue tracker
1225 X-Roundup-Loop: hello
1226 X-Roundup-Issue-Status: chatting
1227 Content-Transfer-Encoding: quoted-printable
1230 richard <richard@test.test> added the comment:
1232 This is a followup
1234 ----------
1235 assignedto: -> mary
1236 nosy: +john, mary
1237 status: unread -> chatting
1238 title: Testing... -> new title
1240 _______________________________________________________________________
1241 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1242 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1243 _______________________________________________________________________
1244 ''')
1246 def testNosyGeneration(self):
1247 self.db.issue.create(title='test')
1249 # create a nosy message
1250 msg = self.db.msg.create(content='This is a test',
1251 author=self.richard_id, messageid='<dummy_test_message_id>')
1252 self.db.journaltag = 'richard'
1253 l = self.db.issue.create(title='test', messages=[msg],
1254 nosy=[self.chef_id, self.mary_id, self.john_id])
1256 self.compareMessages(self._get_mail(),
1257 '''FROM: roundup-admin@your.tracker.email.domain.example
1258 TO: chef@bork.bork.bork, john@test.test, mary@test.test
1259 Content-Type: text/plain; charset="utf-8"
1260 Subject: [issue2] test
1261 To: chef@bork.bork.bork, john@test.test, mary@test.test
1262 From: richard <issue_tracker@your.tracker.email.domain.example>
1263 Reply-To: Roundup issue tracker
1264 <issue_tracker@your.tracker.email.domain.example>
1265 MIME-Version: 1.0
1266 Message-Id: <dummy_test_message_id>
1267 X-Roundup-Name: Roundup issue tracker
1268 X-Roundup-Loop: hello
1269 X-Roundup-Issue-Status: unread
1270 Content-Transfer-Encoding: quoted-printable
1273 New submission from richard <richard@test.test>:
1275 This is a test
1277 ----------
1278 messages: 1
1279 nosy: Chef, john, mary, richard
1280 status: unread
1281 title: test
1283 _______________________________________________________________________
1284 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1285 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue2>
1286 _______________________________________________________________________
1287 ''')
1289 def testPropertyChangeOnly(self):
1290 self.doNewIssue()
1291 oldvalues = self.db.getnode('issue', '1').copy()
1292 oldvalues['assignedto'] = None
1293 # reconstruct old behaviour: This would reuse the
1294 # database-handle from the doNewIssue above which has committed
1295 # as user "Chef". So we close and reopen the db as that user.
1296 #self.db.close() actually don't close 'cos this empties memorydb
1297 self.db = self.instance.open('Chef')
1298 self.db.issue.set('1', assignedto=self.chef_id)
1299 self.db.commit()
1300 self.db.issue.nosymessage('1', None, oldvalues)
1302 new_mail = ""
1303 for line in self._get_mail().split("\n"):
1304 if "Message-Id: " in line:
1305 continue
1306 if "Date: " in line:
1307 continue
1308 new_mail += line+"\n"
1310 self.compareMessages(new_mail, """
1311 FROM: roundup-admin@your.tracker.email.domain.example
1312 TO: chef@bork.bork.bork, richard@test.test
1313 Content-Type: text/plain; charset="utf-8"
1314 Subject: [issue1] Testing...
1315 To: chef@bork.bork.bork, richard@test.test
1316 From: "Bork, Chef" <issue_tracker@your.tracker.email.domain.example>
1317 X-Roundup-Name: Roundup issue tracker
1318 X-Roundup-Loop: hello
1319 X-Roundup-Issue-Status: unread
1320 X-Roundup-Version: 1.3.3
1321 In-Reply-To: <dummy_test_message_id>
1322 MIME-Version: 1.0
1323 Reply-To: Roundup issue tracker
1324 <issue_tracker@your.tracker.email.domain.example>
1325 Content-Transfer-Encoding: quoted-printable
1328 Change by Bork, Chef <chef@bork.bork.bork>:
1331 ----------
1332 assignedto: -> Chef
1334 _______________________________________________________________________
1335 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1336 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1337 _______________________________________________________________________
1338 """)
1341 #
1342 # FOLLOWUP TITLE MATCH
1343 #
1344 def testFollowupTitleMatch(self):
1345 self.doNewIssue()
1346 self._handle_mail('''Content-Type: text/plain;
1347 charset="iso-8859-1"
1348 From: richard <richard@test.test>
1349 To: issue_tracker@your.tracker.email.domain.example
1350 Message-Id: <followup_dummy_id>
1351 Subject: Re: Testing... [assignedto=mary; nosy=+john]
1353 This is a followup
1354 ''')
1355 self.compareMessages(self._get_mail(),
1356 '''FROM: roundup-admin@your.tracker.email.domain.example
1357 TO: chef@bork.bork.bork, john@test.test, mary@test.test
1358 Content-Type: text/plain; charset="utf-8"
1359 Subject: [issue1] Testing...
1360 To: chef@bork.bork.bork, john@test.test, mary@test.test
1361 From: richard <issue_tracker@your.tracker.email.domain.example>
1362 Reply-To: Roundup issue tracker
1363 <issue_tracker@your.tracker.email.domain.example>
1364 MIME-Version: 1.0
1365 Message-Id: <followup_dummy_id>
1366 In-Reply-To: <dummy_test_message_id>
1367 X-Roundup-Name: Roundup issue tracker
1368 X-Roundup-Loop: hello
1369 X-Roundup-Issue-Status: chatting
1370 Content-Transfer-Encoding: quoted-printable
1373 richard <richard@test.test> added the comment:
1375 This is a followup
1377 ----------
1378 assignedto: -> mary
1379 nosy: +john, mary
1380 status: unread -> chatting
1382 _______________________________________________________________________
1383 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1384 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1385 _______________________________________________________________________
1386 ''')
1388 def testFollowupTitleMatchMultiRe(self):
1389 nodeid1 = self.doNewIssue()
1390 nodeid2 = self._handle_mail('''Content-Type: text/plain;
1391 charset="iso-8859-1"
1392 From: richard <richard@test.test>
1393 To: issue_tracker@your.tracker.email.domain.example
1394 Message-Id: <followup_dummy_id>
1395 Subject: Re: Testing... [assignedto=mary; nosy=+john]
1397 This is a followup
1398 ''')
1400 nodeid3 = self._handle_mail('''Content-Type: text/plain;
1401 charset="iso-8859-1"
1402 From: richard <richard@test.test>
1403 To: issue_tracker@your.tracker.email.domain.example
1404 Message-Id: <followup2_dummy_id>
1405 Subject: Ang: Re: Testing...
1407 This is a followup
1408 ''')
1409 self.assertEqual(nodeid1, nodeid2)
1410 self.assertEqual(nodeid1, nodeid3)
1412 def testFollowupTitleMatchNever(self):
1413 nodeid = self.doNewIssue()
1414 self.db.config.MAILGW_SUBJECT_CONTENT_MATCH = 'never'
1415 self.assertNotEqual(self._handle_mail('''Content-Type: text/plain;
1416 charset="iso-8859-1"
1417 From: richard <richard@test.test>
1418 To: issue_tracker@your.tracker.email.domain.example
1419 Message-Id: <followup_dummy_id>
1420 Subject: Re: Testing...
1422 This is a followup
1423 '''), nodeid)
1425 def testFollowupTitleMatchNeverInterval(self):
1426 nodeid = self.doNewIssue()
1427 # force failure of the interval
1428 time.sleep(2)
1429 self.db.config.MAILGW_SUBJECT_CONTENT_MATCH = 'creation 00:00:01'
1430 self.assertNotEqual(self._handle_mail('''Content-Type: text/plain;
1431 charset="iso-8859-1"
1432 From: richard <richard@test.test>
1433 To: issue_tracker@your.tracker.email.domain.example
1434 Message-Id: <followup_dummy_id>
1435 Subject: Re: Testing...
1437 This is a followup
1438 '''), nodeid)
1441 def testFollowupTitleMatchInterval(self):
1442 nodeid = self.doNewIssue()
1443 self.db.config.MAILGW_SUBJECT_CONTENT_MATCH = 'creation +1d'
1444 self.assertEqual(self._handle_mail('''Content-Type: text/plain;
1445 charset="iso-8859-1"
1446 From: richard <richard@test.test>
1447 To: issue_tracker@your.tracker.email.domain.example
1448 Message-Id: <followup_dummy_id>
1449 Subject: Re: Testing...
1451 This is a followup
1452 '''), nodeid)
1455 def testFollowupNosyAuthor(self):
1456 self.doNewIssue()
1457 self.db.config.ADD_AUTHOR_TO_NOSY = 'yes'
1458 self._handle_mail('''Content-Type: text/plain;
1459 charset="iso-8859-1"
1460 From: john@test.test
1461 To: issue_tracker@your.tracker.email.domain.example
1462 Message-Id: <followup_dummy_id>
1463 In-Reply-To: <dummy_test_message_id>
1464 Subject: [issue1] Testing...
1466 This is a followup
1467 ''')
1469 self.compareMessages(self._get_mail(),
1470 '''FROM: roundup-admin@your.tracker.email.domain.example
1471 TO: chef@bork.bork.bork, richard@test.test
1472 Content-Type: text/plain; charset="utf-8"
1473 Subject: [issue1] Testing...
1474 To: chef@bork.bork.bork, richard@test.test
1475 From: John Doe <issue_tracker@your.tracker.email.domain.example>
1476 Reply-To: Roundup issue tracker
1477 <issue_tracker@your.tracker.email.domain.example>
1478 MIME-Version: 1.0
1479 Message-Id: <followup_dummy_id>
1480 In-Reply-To: <dummy_test_message_id>
1481 X-Roundup-Name: Roundup issue tracker
1482 X-Roundup-Loop: hello
1483 X-Roundup-Issue-Status: chatting
1484 Content-Transfer-Encoding: quoted-printable
1487 John Doe <john@test.test> added the comment:
1489 This is a followup
1491 ----------
1492 nosy: +john
1493 status: unread -> chatting
1495 _______________________________________________________________________
1496 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1497 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1498 _______________________________________________________________________
1500 ''')
1502 def testFollowupNosyRecipients(self):
1503 self.doNewIssue()
1504 self.db.config.ADD_RECIPIENTS_TO_NOSY = 'yes'
1505 self._handle_mail('''Content-Type: text/plain;
1506 charset="iso-8859-1"
1507 From: richard@test.test
1508 To: issue_tracker@your.tracker.email.domain.example
1509 Cc: john@test.test
1510 Message-Id: <followup_dummy_id>
1511 In-Reply-To: <dummy_test_message_id>
1512 Subject: [issue1] Testing...
1514 This is a followup
1515 ''')
1516 self.compareMessages(self._get_mail(),
1517 '''FROM: roundup-admin@your.tracker.email.domain.example
1518 TO: chef@bork.bork.bork
1519 Content-Type: text/plain; charset="utf-8"
1520 Subject: [issue1] Testing...
1521 To: chef@bork.bork.bork
1522 From: richard <issue_tracker@your.tracker.email.domain.example>
1523 Reply-To: Roundup issue tracker
1524 <issue_tracker@your.tracker.email.domain.example>
1525 MIME-Version: 1.0
1526 Message-Id: <followup_dummy_id>
1527 In-Reply-To: <dummy_test_message_id>
1528 X-Roundup-Name: Roundup issue tracker
1529 X-Roundup-Loop: hello
1530 X-Roundup-Issue-Status: chatting
1531 Content-Transfer-Encoding: quoted-printable
1534 richard <richard@test.test> added the comment:
1536 This is a followup
1538 ----------
1539 nosy: +john
1540 status: unread -> chatting
1542 _______________________________________________________________________
1543 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1544 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1545 _______________________________________________________________________
1547 ''')
1549 def testFollowupNosyAuthorAndCopy(self):
1550 self.doNewIssue()
1551 self.db.config.ADD_AUTHOR_TO_NOSY = 'yes'
1552 self.db.config.MESSAGES_TO_AUTHOR = 'yes'
1553 self._handle_mail('''Content-Type: text/plain;
1554 charset="iso-8859-1"
1555 From: john@test.test
1556 To: issue_tracker@your.tracker.email.domain.example
1557 Message-Id: <followup_dummy_id>
1558 In-Reply-To: <dummy_test_message_id>
1559 Subject: [issue1] Testing...
1561 This is a followup
1562 ''')
1563 self.compareMessages(self._get_mail(),
1564 '''FROM: roundup-admin@your.tracker.email.domain.example
1565 TO: chef@bork.bork.bork, john@test.test, richard@test.test
1566 Content-Type: text/plain; charset="utf-8"
1567 Subject: [issue1] Testing...
1568 To: chef@bork.bork.bork, john@test.test, richard@test.test
1569 From: John Doe <issue_tracker@your.tracker.email.domain.example>
1570 Reply-To: Roundup issue tracker
1571 <issue_tracker@your.tracker.email.domain.example>
1572 MIME-Version: 1.0
1573 Message-Id: <followup_dummy_id>
1574 In-Reply-To: <dummy_test_message_id>
1575 X-Roundup-Name: Roundup issue tracker
1576 X-Roundup-Loop: hello
1577 X-Roundup-Issue-Status: chatting
1578 Content-Transfer-Encoding: quoted-printable
1581 John Doe <john@test.test> added the comment:
1583 This is a followup
1585 ----------
1586 nosy: +john
1587 status: unread -> chatting
1589 _______________________________________________________________________
1590 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1591 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1592 _______________________________________________________________________
1594 ''')
1596 def testFollowupNoNosyAuthor(self):
1597 self.doNewIssue()
1598 self.instance.config.ADD_AUTHOR_TO_NOSY = 'no'
1599 self._handle_mail('''Content-Type: text/plain;
1600 charset="iso-8859-1"
1601 From: john@test.test
1602 To: issue_tracker@your.tracker.email.domain.example
1603 Message-Id: <followup_dummy_id>
1604 In-Reply-To: <dummy_test_message_id>
1605 Subject: [issue1] Testing...
1607 This is a followup
1608 ''')
1609 self.compareMessages(self._get_mail(),
1610 '''FROM: roundup-admin@your.tracker.email.domain.example
1611 TO: chef@bork.bork.bork, richard@test.test
1612 Content-Type: text/plain; charset="utf-8"
1613 Subject: [issue1] Testing...
1614 To: chef@bork.bork.bork, richard@test.test
1615 From: John Doe <issue_tracker@your.tracker.email.domain.example>
1616 Reply-To: Roundup issue tracker
1617 <issue_tracker@your.tracker.email.domain.example>
1618 MIME-Version: 1.0
1619 Message-Id: <followup_dummy_id>
1620 In-Reply-To: <dummy_test_message_id>
1621 X-Roundup-Name: Roundup issue tracker
1622 X-Roundup-Loop: hello
1623 X-Roundup-Issue-Status: chatting
1624 Content-Transfer-Encoding: quoted-printable
1627 John Doe <john@test.test> added the comment:
1629 This is a followup
1631 ----------
1632 status: unread -> chatting
1634 _______________________________________________________________________
1635 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1636 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1637 _______________________________________________________________________
1639 ''')
1641 def testFollowupNoNosyRecipients(self):
1642 self.doNewIssue()
1643 self.instance.config.ADD_RECIPIENTS_TO_NOSY = 'no'
1644 self._handle_mail('''Content-Type: text/plain;
1645 charset="iso-8859-1"
1646 From: richard@test.test
1647 To: issue_tracker@your.tracker.email.domain.example
1648 Cc: john@test.test
1649 Message-Id: <followup_dummy_id>
1650 In-Reply-To: <dummy_test_message_id>
1651 Subject: [issue1] Testing...
1653 This is a followup
1654 ''')
1655 self.compareMessages(self._get_mail(),
1656 '''FROM: roundup-admin@your.tracker.email.domain.example
1657 TO: chef@bork.bork.bork
1658 Content-Type: text/plain; charset="utf-8"
1659 Subject: [issue1] Testing...
1660 To: chef@bork.bork.bork
1661 From: richard <issue_tracker@your.tracker.email.domain.example>
1662 Reply-To: Roundup issue tracker
1663 <issue_tracker@your.tracker.email.domain.example>
1664 MIME-Version: 1.0
1665 Message-Id: <followup_dummy_id>
1666 In-Reply-To: <dummy_test_message_id>
1667 X-Roundup-Name: Roundup issue tracker
1668 X-Roundup-Loop: hello
1669 X-Roundup-Issue-Status: chatting
1670 Content-Transfer-Encoding: quoted-printable
1673 richard <richard@test.test> added the comment:
1675 This is a followup
1677 ----------
1678 status: unread -> chatting
1680 _______________________________________________________________________
1681 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1682 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1683 _______________________________________________________________________
1685 ''')
1687 def testFollowupEmptyMessage(self):
1688 self.doNewIssue()
1690 self._handle_mail('''Content-Type: text/plain;
1691 charset="iso-8859-1"
1692 From: richard <richard@test.test>
1693 To: issue_tracker@your.tracker.email.domain.example
1694 Message-Id: <followup_dummy_id>
1695 In-Reply-To: <dummy_test_message_id>
1696 Subject: [issue1] Testing... [assignedto=mary; nosy=+john]
1698 ''')
1699 l = self.db.issue.get('1', 'nosy')
1700 l.sort()
1701 self.assertEqual(l, [self.chef_id, self.richard_id, self.mary_id,
1702 self.john_id])
1704 # should be no file created (ie. no message)
1705 assert not os.path.exists(SENDMAILDEBUG)
1707 def testFollowupEmptyMessageNoSubject(self):
1708 self.doNewIssue()
1710 self._handle_mail('''Content-Type: text/plain;
1711 charset="iso-8859-1"
1712 From: richard <richard@test.test>
1713 To: issue_tracker@your.tracker.email.domain.example
1714 Message-Id: <followup_dummy_id>
1715 In-Reply-To: <dummy_test_message_id>
1716 Subject: [issue1] [assignedto=mary; nosy=+john]
1718 ''')
1719 l = self.db.issue.get('1', 'nosy')
1720 l.sort()
1721 self.assertEqual(l, [self.chef_id, self.richard_id, self.mary_id,
1722 self.john_id])
1724 # should be no file created (ie. no message)
1725 assert not os.path.exists(SENDMAILDEBUG)
1727 def testNosyRemove(self):
1728 self.doNewIssue()
1730 self._handle_mail('''Content-Type: text/plain;
1731 charset="iso-8859-1"
1732 From: richard <richard@test.test>
1733 To: issue_tracker@your.tracker.email.domain.example
1734 Message-Id: <followup_dummy_id>
1735 In-Reply-To: <dummy_test_message_id>
1736 Subject: [issue1] Testing... [nosy=-richard]
1738 ''')
1739 l = self.db.issue.get('1', 'nosy')
1740 l.sort()
1741 self.assertEqual(l, [self.chef_id])
1743 # NO NOSY MESSAGE SHOULD BE SENT!
1744 assert not os.path.exists(SENDMAILDEBUG)
1746 def testNewUserAuthor(self):
1747 self.db.commit()
1748 l = self.db.user.list()
1749 l.sort()
1750 message = '''Content-Type: text/plain;
1751 charset="iso-8859-1"
1752 From: fubar <fubar@bork.bork.bork>
1753 To: issue_tracker@your.tracker.email.domain.example
1754 Message-Id: <dummy_test_message_id>
1755 Subject: [issue] Testing...
1757 This is a test submission of a new issue.
1758 '''
1759 self.db.security.role['anonymous'].permissions=[]
1760 anonid = self.db.user.lookup('anonymous')
1761 self.db.user.set(anonid, roles='Anonymous')
1762 try:
1763 self._handle_mail(message)
1764 except Unauthorized, value:
1765 body_diff = self.compareMessages(str(value), """
1766 You are not a registered user.
1768 Unknown address: fubar@bork.bork.bork
1769 """)
1770 assert not body_diff, body_diff
1771 else:
1772 raise AssertionError, "Unathorized not raised when handling mail"
1774 # Add Web Access role to anonymous, and try again to make sure
1775 # we get a "please register at:" message this time.
1776 p = [
1777 self.db.security.getPermission('Register', 'user'),
1778 self.db.security.getPermission('Web Access', None),
1779 ]
1780 self.db.security.role['anonymous'].permissions=p
1781 try:
1782 self._handle_mail(message)
1783 except Unauthorized, value:
1784 body_diff = self.compareMessages(str(value), """
1785 You are not a registered user. Please register at:
1787 http://tracker.example/cgi-bin/roundup.cgi/bugs/user?template=register
1789 ...before sending mail to the tracker.
1791 Unknown address: fubar@bork.bork.bork
1792 """)
1793 assert not body_diff, body_diff
1794 else:
1795 raise AssertionError, "Unauthorized not raised when handling mail"
1797 # Make sure list of users is the same as before.
1798 m = self.db.user.list()
1799 m.sort()
1800 self.assertEqual(l, m)
1802 # now with the permission
1803 p = [
1804 self.db.security.getPermission('Register', 'user'),
1805 self.db.security.getPermission('Email Access', None),
1806 ]
1807 self.db.security.role['anonymous'].permissions=p
1808 self._handle_mail(message)
1809 m = self.db.user.list()
1810 m.sort()
1811 self.assertNotEqual(l, m)
1813 def testNewUserAuthorEncodedName(self):
1814 l = set(self.db.user.list())
1815 # From: name has Euro symbol in it
1816 message = '''Content-Type: text/plain;
1817 charset="iso-8859-1"
1818 From: =?utf8?b?SOKCrGxsbw==?= <fubar@bork.bork.bork>
1819 To: issue_tracker@your.tracker.email.domain.example
1820 Message-Id: <dummy_test_message_id>
1821 Subject: [issue] Testing...
1823 This is a test submission of a new issue.
1824 '''
1825 p = [
1826 self.db.security.getPermission('Register', 'user'),
1827 self.db.security.getPermission('Email Access', None),
1828 self.db.security.getPermission('Create', 'issue'),
1829 self.db.security.getPermission('Create', 'msg'),
1830 ]
1831 self.db.security.role['anonymous'].permissions = p
1832 self._handle_mail(message)
1833 m = set(self.db.user.list())
1834 new = list(m - l)[0]
1835 name = self.db.user.get(new, 'realname')
1836 self.assertEquals(name, 'H€llo')
1838 def testNewUserAuthorMixedEncodedName(self):
1839 l = set(self.db.user.list())
1840 # From: name has Euro symbol in it
1841 message = '''Content-Type: text/plain;
1842 charset="iso-8859-1"
1843 From: Firstname =?utf-8?b?w6TDtsOf?= Last <fubar@bork.bork.bork>
1844 To: issue_tracker@your.tracker.email.domain.example
1845 Message-Id: <dummy_test_message_id>
1846 Subject: [issue] Test =?utf-8?b?w4TDlsOc?= umlauts
1847 X1
1848 X2
1850 This is a test submission of a new issue.
1851 '''
1852 p = [
1853 self.db.security.getPermission('Register', 'user'),
1854 self.db.security.getPermission('Email Access', None),
1855 self.db.security.getPermission('Create', 'issue'),
1856 self.db.security.getPermission('Create', 'msg'),
1857 ]
1858 self.db.security.role['anonymous'].permissions = p
1859 self._handle_mail(message)
1860 title = self.db.issue.get('1', 'title')
1861 self.assertEquals(title, 'Test \xc3\x84\xc3\x96\xc3\x9c umlauts X1 X2')
1862 m = set(self.db.user.list())
1863 new = list(m - l)[0]
1864 name = self.db.user.get(new, 'realname')
1865 self.assertEquals(name, 'Firstname \xc3\xa4\xc3\xb6\xc3\x9f Last')
1867 def testUnknownUser(self):
1868 l = set(self.db.user.list())
1869 message = '''Content-Type: text/plain;
1870 charset="iso-8859-1"
1871 From: Nonexisting User <nonexisting@bork.bork.bork>
1872 To: issue_tracker@your.tracker.email.domain.example
1873 Message-Id: <dummy_test_message_id>
1874 Subject: [issue] Testing nonexisting user...
1876 This is a test submission of a new issue.
1877 '''
1878 handler = self._create_mailgw(message)
1879 # we want a bounce message:
1880 handler.trapExceptions = 1
1881 ret = handler.main(StringIO(message))
1882 self.compareMessages(self._get_mail(),
1883 '''FROM: Roundup issue tracker <roundup-admin@your.tracker.email.domain.example>
1884 TO: nonexisting@bork.bork.bork
1885 From nobody Tue Jul 14 12:04:11 2009
1886 Content-Type: multipart/mixed; boundary="===============0639262320=="
1887 MIME-Version: 1.0
1888 Subject: Failed issue tracker submission
1889 To: nonexisting@bork.bork.bork
1890 From: Roundup issue tracker <roundup-admin@your.tracker.email.domain.example>
1891 Date: Tue, 14 Jul 2009 12:04:11 +0000
1892 Precedence: bulk
1893 X-Roundup-Name: Roundup issue tracker
1894 X-Roundup-Loop: hello
1895 X-Roundup-Version: 1.4.8
1896 MIME-Version: 1.0
1898 --===============0639262320==
1899 Content-Type: text/plain; charset="us-ascii"
1900 MIME-Version: 1.0
1901 Content-Transfer-Encoding: 7bit
1905 You are not a registered user. Please register at:
1907 http://tracker.example/cgi-bin/roundup.cgi/bugs/user?template=register
1909 ...before sending mail to the tracker.
1911 Unknown address: nonexisting@bork.bork.bork
1913 --===============0639262320==
1914 Content-Type: text/plain; charset="us-ascii"
1915 MIME-Version: 1.0
1916 Content-Transfer-Encoding: 7bit
1918 Content-Type: text/plain;
1919 charset="iso-8859-1"
1920 From: Nonexisting User <nonexisting@bork.bork.bork>
1921 To: issue_tracker@your.tracker.email.domain.example
1922 Message-Id: <dummy_test_message_id>
1923 Subject: [issue] Testing nonexisting user...
1925 This is a test submission of a new issue.
1927 --===============0639262320==--
1928 ''')
1930 def testEnc01(self):
1931 self.db.user.set(self.mary_id,
1932 realname='\xe4\xf6\xfc\xc4\xd6\xdc\xdf, Mary'.decode
1933 ('latin-1').encode('utf-8'))
1934 self.doNewIssue()
1935 self._handle_mail('''Content-Type: text/plain;
1936 charset="iso-8859-1"
1937 From: mary <mary@test.test>
1938 To: issue_tracker@your.tracker.email.domain.example
1939 Message-Id: <followup_dummy_id>
1940 In-Reply-To: <dummy_test_message_id>
1941 Subject: [issue1] Testing...
1942 Content-Type: text/plain;
1943 charset="iso-8859-1"
1944 Content-Transfer-Encoding: quoted-printable
1946 A message with encoding (encoded oe =F6)
1948 ''')
1949 self.compareMessages(self._get_mail(),
1950 '''FROM: roundup-admin@your.tracker.email.domain.example
1951 TO: chef@bork.bork.bork, richard@test.test
1952 Content-Type: text/plain; charset="utf-8"
1953 Subject: [issue1] Testing...
1954 To: chef@bork.bork.bork, richard@test.test
1955 From: =?utf-8?b?w6TDtsO8w4TDlsOcw58sIE1hcnk=?=
1956 <issue_tracker@your.tracker.email.domain.example>
1957 Reply-To: Roundup issue tracker
1958 <issue_tracker@your.tracker.email.domain.example>
1959 MIME-Version: 1.0
1960 Message-Id: <followup_dummy_id>
1961 In-Reply-To: <dummy_test_message_id>
1962 X-Roundup-Name: Roundup issue tracker
1963 X-Roundup-Loop: hello
1964 X-Roundup-Issue-Status: chatting
1965 Content-Transfer-Encoding: quoted-printable
1968 =C3=A4=C3=B6=C3=BC=C3=84=C3=96=C3=9C=C3=9F, Mary <mary@test.test> added the=
1969 comment:
1971 A message with encoding (encoded oe =C3=B6)
1973 ----------
1974 status: unread -> chatting
1976 _______________________________________________________________________
1977 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1978 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1979 _______________________________________________________________________
1980 ''')
1982 def testEncNonUTF8(self):
1983 self.doNewIssue()
1984 self.instance.config.EMAIL_CHARSET = 'iso-8859-1'
1985 self._handle_mail('''Content-Type: text/plain;
1986 charset="iso-8859-1"
1987 From: mary <mary@test.test>
1988 To: issue_tracker@your.tracker.email.domain.example
1989 Message-Id: <followup_dummy_id>
1990 In-Reply-To: <dummy_test_message_id>
1991 Subject: [issue1] Testing...
1992 Content-Type: text/plain;
1993 charset="iso-8859-1"
1994 Content-Transfer-Encoding: quoted-printable
1996 A message with encoding (encoded oe =F6)
1998 ''')
1999 self.compareMessages(self._get_mail(),
2000 '''FROM: roundup-admin@your.tracker.email.domain.example
2001 TO: chef@bork.bork.bork, richard@test.test
2002 Content-Type: text/plain; charset="iso-8859-1"
2003 Subject: [issue1] Testing...
2004 To: chef@bork.bork.bork, richard@test.test
2005 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
2006 Reply-To: Roundup issue tracker
2007 <issue_tracker@your.tracker.email.domain.example>
2008 MIME-Version: 1.0
2009 Message-Id: <followup_dummy_id>
2010 In-Reply-To: <dummy_test_message_id>
2011 X-Roundup-Name: Roundup issue tracker
2012 X-Roundup-Loop: hello
2013 X-Roundup-Issue-Status: chatting
2014 Content-Transfer-Encoding: quoted-printable
2017 Contrary, Mary <mary@test.test> added the comment:
2019 A message with encoding (encoded oe =F6)
2021 ----------
2022 status: unread -> chatting
2024 _______________________________________________________________________
2025 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
2026 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
2027 _______________________________________________________________________
2028 ''')
2031 def testMultipartEnc01(self):
2032 self.doNewIssue()
2033 self._handle_mail('''Content-Type: text/plain;
2034 charset="iso-8859-1"
2035 From: mary <mary@test.test>
2036 To: issue_tracker@your.tracker.email.domain.example
2037 Message-Id: <followup_dummy_id>
2038 In-Reply-To: <dummy_test_message_id>
2039 Subject: [issue1] Testing...
2040 Content-Type: multipart/mixed;
2041 boundary="----_=_NextPart_000_01"
2043 This message is in MIME format. Since your mail reader does not understand
2044 this format, some or all of this message may not be legible.
2046 ------_=_NextPart_000_01
2047 Content-Type: text/plain;
2048 charset="iso-8859-1"
2049 Content-Transfer-Encoding: quoted-printable
2051 A message with first part encoded (encoded oe =F6)
2053 ''')
2054 self.compareMessages(self._get_mail(),
2055 '''FROM: roundup-admin@your.tracker.email.domain.example
2056 TO: chef@bork.bork.bork, richard@test.test
2057 Content-Type: text/plain; charset="utf-8"
2058 Subject: [issue1] Testing...
2059 To: chef@bork.bork.bork, richard@test.test
2060 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
2061 Reply-To: Roundup issue tracker
2062 <issue_tracker@your.tracker.email.domain.example>
2063 MIME-Version: 1.0
2064 Message-Id: <followup_dummy_id>
2065 In-Reply-To: <dummy_test_message_id>
2066 X-Roundup-Name: Roundup issue tracker
2067 X-Roundup-Loop: hello
2068 X-Roundup-Issue-Status: chatting
2069 Content-Transfer-Encoding: quoted-printable
2072 Contrary, Mary <mary@test.test> added the comment:
2074 A message with first part encoded (encoded oe =C3=B6)
2076 ----------
2077 status: unread -> chatting
2079 _______________________________________________________________________
2080 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
2081 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
2082 _______________________________________________________________________
2083 ''')
2085 def testContentDisposition(self):
2086 self.doNewIssue()
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: multipart/mixed; boundary="bCsyhTFzCvuiizWE"
2095 Content-Disposition: inline
2098 --bCsyhTFzCvuiizWE
2099 Content-Type: text/plain; charset=us-ascii
2100 Content-Disposition: inline
2102 test attachment binary
2104 --bCsyhTFzCvuiizWE
2105 Content-Type: application/octet-stream
2106 Content-Disposition: attachment; filename="main.dvi"
2107 Content-Transfer-Encoding: base64
2109 SnVzdCBhIHRlc3QgAQo=
2111 --bCsyhTFzCvuiizWE--
2112 ''')
2113 messages = self.db.issue.get('1', 'messages')
2114 messages.sort()
2115 file = self.db.file.getnode (self.db.msg.get(messages[-1], 'files')[0])
2116 self.assertEqual(file.name, 'main.dvi')
2117 self.assertEqual(file.content, 'Just a test \001\n')
2119 def testFollowupStupidQuoting(self):
2120 self.doNewIssue()
2122 self._handle_mail('''Content-Type: text/plain;
2123 charset="iso-8859-1"
2124 From: richard <richard@test.test>
2125 To: issue_tracker@your.tracker.email.domain.example
2126 Message-Id: <followup_dummy_id>
2127 In-Reply-To: <dummy_test_message_id>
2128 Subject: Re: "[issue1] Testing... "
2130 This is a followup
2131 ''')
2132 self.compareMessages(self._get_mail(),
2133 '''FROM: roundup-admin@your.tracker.email.domain.example
2134 TO: chef@bork.bork.bork
2135 Content-Type: text/plain; charset="utf-8"
2136 Subject: [issue1] Testing...
2137 To: chef@bork.bork.bork
2138 From: richard <issue_tracker@your.tracker.email.domain.example>
2139 Reply-To: Roundup issue tracker
2140 <issue_tracker@your.tracker.email.domain.example>
2141 MIME-Version: 1.0
2142 Message-Id: <followup_dummy_id>
2143 In-Reply-To: <dummy_test_message_id>
2144 X-Roundup-Name: Roundup issue tracker
2145 X-Roundup-Loop: hello
2146 X-Roundup-Issue-Status: chatting
2147 Content-Transfer-Encoding: quoted-printable
2150 richard <richard@test.test> added the comment:
2152 This is a followup
2154 ----------
2155 status: unread -> chatting
2157 _______________________________________________________________________
2158 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
2159 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
2160 _______________________________________________________________________
2161 ''')
2163 def testEmailQuoting(self):
2164 self.instance.config.EMAIL_KEEP_QUOTED_TEXT = 'no'
2165 self.innerTestQuoting('''This is a followup
2166 ''')
2168 def testEmailQuotingRemove(self):
2169 self.instance.config.EMAIL_KEEP_QUOTED_TEXT = 'yes'
2170 self.innerTestQuoting('''Blah blah wrote:
2171 > Blah bklaskdfj sdf asdf jlaskdf skj sdkfjl asdf
2172 > skdjlkjsdfalsdkfjasdlfkj dlfksdfalksd fj
2173 >
2175 This is a followup
2176 ''')
2178 def innerTestQuoting(self, expect):
2179 nodeid = self.doNewIssue()
2181 messages = self.db.issue.get(nodeid, 'messages')
2183 self._handle_mail('''Content-Type: text/plain;
2184 charset="iso-8859-1"
2185 From: richard <richard@test.test>
2186 To: issue_tracker@your.tracker.email.domain.example
2187 Message-Id: <followup_dummy_id>
2188 In-Reply-To: <dummy_test_message_id>
2189 Subject: Re: [issue1] Testing...
2191 Blah blah wrote:
2192 > Blah bklaskdfj sdf asdf jlaskdf skj sdkfjl asdf
2193 > skdjlkjsdfalsdkfjasdlfkj dlfksdfalksd fj
2194 >
2196 This is a followup
2197 ''')
2198 # figure the new message id
2199 newmessages = self.db.issue.get(nodeid, 'messages')
2200 for msg in messages:
2201 newmessages.remove(msg)
2202 messageid = newmessages[0]
2204 self.compareMessages(self.db.msg.get(messageid, 'content'), expect)
2206 def testUserLookup(self):
2207 i = self.db.user.create(username='user1', address='user1@foo.com')
2208 self.assertEqual(uidFromAddress(self.db, ('', 'user1@foo.com'), 0), i)
2209 self.assertEqual(uidFromAddress(self.db, ('', 'USER1@foo.com'), 0), i)
2210 i = self.db.user.create(username='user2', address='USER2@foo.com')
2211 self.assertEqual(uidFromAddress(self.db, ('', 'USER2@foo.com'), 0), i)
2212 self.assertEqual(uidFromAddress(self.db, ('', 'user2@foo.com'), 0), i)
2214 def testUserAlternateLookup(self):
2215 i = self.db.user.create(username='user1', address='user1@foo.com',
2216 alternate_addresses='user1@bar.com')
2217 self.assertEqual(uidFromAddress(self.db, ('', 'user1@bar.com'), 0), i)
2218 self.assertEqual(uidFromAddress(self.db, ('', 'USER1@bar.com'), 0), i)
2220 def testUserAlternateSubstringNomatch(self):
2221 i = self.db.user.create(username='user1', address='user1@foo.com',
2222 alternate_addresses='x-user1@bar.com')
2223 self.assertEqual(uidFromAddress(self.db, ('', 'user1@bar.com'), 0), 0)
2224 self.assertEqual(uidFromAddress(self.db, ('', 'USER1@bar.com'), 0), 0)
2226 def testUserCreate(self):
2227 i = uidFromAddress(self.db, ('', 'user@foo.com'), 1)
2228 self.assertNotEqual(uidFromAddress(self.db, ('', 'user@bar.com'), 1), i)
2230 def testRFC2822(self):
2231 ascii_header = "[issue243] This is a \"test\" - with 'quotation' marks"
2232 unicode_header = '[issue244] \xd0\xb0\xd0\xbd\xd0\xb4\xd1\x80\xd0\xb5\xd0\xb9'
2233 unicode_encoded = '=?utf-8?q?[issue244]_=D0=B0=D0=BD=D0=B4=D1=80=D0=B5=D0=B9?='
2234 self.assertEqual(rfc2822.encode_header(ascii_header), ascii_header)
2235 self.assertEqual(rfc2822.encode_header(unicode_header), unicode_encoded)
2237 def testRegistrationConfirmation(self):
2238 otk = "Aj4euk4LZSAdwePohj90SME5SpopLETL"
2239 self.db.getOTKManager().set(otk, username='johannes')
2240 self._handle_mail('''Content-Type: text/plain;
2241 charset="iso-8859-1"
2242 From: Chef <chef@bork.bork.bork>
2243 To: issue_tracker@your.tracker.email.domain.example
2244 Cc: richard@test.test
2245 Message-Id: <dummy_test_message_id>
2246 Subject: Re: Complete your registration to Roundup issue tracker
2247 -- key %s
2249 This is a test confirmation of registration.
2250 ''' % otk)
2251 self.db.user.lookup('johannes')
2253 def testFollowupOnNonIssue(self):
2254 self.db.keyword.create(name='Foo')
2255 self._handle_mail('''Content-Type: text/plain;
2256 charset="iso-8859-1"
2257 From: richard <richard@test.test>
2258 To: issue_tracker@your.tracker.email.domain.example
2259 Message-Id: <followup_dummy_id>
2260 In-Reply-To: <dummy_test_message_id>
2261 Subject: [keyword1] Testing... [name=Bar]
2263 ''')
2264 self.assertEqual(self.db.keyword.get('1', 'name'), 'Bar')
2266 def testResentFrom(self):
2267 nodeid = self._handle_mail('''Content-Type: text/plain;
2268 charset="iso-8859-1"
2269 From: Chef <chef@bork.bork.bork>
2270 Resent-From: mary <mary@test.test>
2271 To: issue_tracker@your.tracker.email.domain.example
2272 Cc: richard@test.test
2273 Message-Id: <dummy_test_message_id>
2274 Subject: [issue] Testing...
2276 This is a test submission of a new issue.
2277 ''')
2278 assert not os.path.exists(SENDMAILDEBUG)
2279 l = self.db.issue.get(nodeid, 'nosy')
2280 l.sort()
2281 self.assertEqual(l, [self.richard_id, self.mary_id])
2282 return nodeid
2284 def testDejaVu(self):
2285 self.assertRaises(IgnoreLoop, self._handle_mail,
2286 '''Content-Type: text/plain;
2287 charset="iso-8859-1"
2288 From: Chef <chef@bork.bork.bork>
2289 X-Roundup-Loop: hello
2290 To: issue_tracker@your.tracker.email.domain.example
2291 Cc: richard@test.test
2292 Message-Id: <dummy_test_message_id>
2293 Subject: Re: [issue] Testing...
2295 Hi, I've been mis-configured to loop messages back to myself.
2296 ''')
2298 def testItsBulkStupid(self):
2299 self.assertRaises(IgnoreBulk, self._handle_mail,
2300 '''Content-Type: text/plain;
2301 charset="iso-8859-1"
2302 From: Chef <chef@bork.bork.bork>
2303 Precedence: bulk
2304 To: issue_tracker@your.tracker.email.domain.example
2305 Cc: richard@test.test
2306 Message-Id: <dummy_test_message_id>
2307 Subject: Re: [issue] Testing...
2309 Hi, I'm on holidays, and this is a dumb auto-responder.
2310 ''')
2312 def testAutoReplyEmailsAreIgnored(self):
2313 self.assertRaises(IgnoreBulk, self._handle_mail,
2314 '''Content-Type: text/plain;
2315 charset="iso-8859-1"
2316 From: Chef <chef@bork.bork.bork>
2317 To: issue_tracker@your.tracker.email.domain.example
2318 Cc: richard@test.test
2319 Message-Id: <dummy_test_message_id>
2320 Subject: Re: [issue] Out of office AutoReply: Back next week
2322 Hi, I am back in the office next week
2323 ''')
2325 def testNoSubject(self):
2326 self.assertRaises(MailUsageError, self._handle_mail,
2327 '''Content-Type: text/plain;
2328 charset="iso-8859-1"
2329 From: Chef <chef@bork.bork.bork>
2330 To: issue_tracker@your.tracker.email.domain.example
2331 Cc: richard@test.test
2332 Reply-To: chef@bork.bork.bork
2333 Message-Id: <dummy_test_message_id>
2335 ''')
2337 #
2338 # TEST FOR INVALID DESIGNATOR HANDLING
2339 #
2340 def testInvalidDesignator(self):
2341 self.assertRaises(MailUsageError, self._handle_mail,
2342 '''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 Subject: [frobulated] testing
2347 Cc: richard@test.test
2348 Reply-To: chef@bork.bork.bork
2349 Message-Id: <dummy_test_message_id>
2351 ''')
2352 self.assertRaises(MailUsageError, self._handle_mail,
2353 '''Content-Type: text/plain;
2354 charset="iso-8859-1"
2355 From: Chef <chef@bork.bork.bork>
2356 To: issue_tracker@your.tracker.email.domain.example
2357 Subject: [issue12345] testing
2358 Cc: richard@test.test
2359 Reply-To: chef@bork.bork.bork
2360 Message-Id: <dummy_test_message_id>
2362 ''')
2364 def testInvalidClassLoose(self):
2365 self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'loose'
2366 nodeid = self._handle_mail('''Content-Type: text/plain;
2367 charset="iso-8859-1"
2368 From: Chef <chef@bork.bork.bork>
2369 To: issue_tracker@your.tracker.email.domain.example
2370 Subject: [frobulated] testing
2371 Cc: richard@test.test
2372 Reply-To: chef@bork.bork.bork
2373 Message-Id: <dummy_test_message_id>
2375 ''')
2376 assert not os.path.exists(SENDMAILDEBUG)
2377 self.assertEqual(self.db.issue.get(nodeid, 'title'),
2378 '[frobulated] testing')
2380 def testInvalidClassLooseReply(self):
2381 self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'loose'
2382 nodeid = self._handle_mail('''Content-Type: text/plain;
2383 charset="iso-8859-1"
2384 From: Chef <chef@bork.bork.bork>
2385 To: issue_tracker@your.tracker.email.domain.example
2386 Subject: Re: [frobulated] testing
2387 Cc: richard@test.test
2388 Reply-To: chef@bork.bork.bork
2389 Message-Id: <dummy_test_message_id>
2391 ''')
2392 assert not os.path.exists(SENDMAILDEBUG)
2393 self.assertEqual(self.db.issue.get(nodeid, 'title'),
2394 '[frobulated] testing')
2396 def testInvalidClassLoose(self):
2397 self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'loose'
2398 nodeid = self._handle_mail('''Content-Type: text/plain;
2399 charset="iso-8859-1"
2400 From: Chef <chef@bork.bork.bork>
2401 To: issue_tracker@your.tracker.email.domain.example
2402 Subject: [issue1234] testing
2403 Cc: richard@test.test
2404 Reply-To: chef@bork.bork.bork
2405 Message-Id: <dummy_test_message_id>
2407 ''')
2408 assert not os.path.exists(SENDMAILDEBUG)
2409 self.assertEqual(self.db.issue.get(nodeid, 'title'),
2410 '[issue1234] testing')
2412 def testClassLooseOK(self):
2413 self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'loose'
2414 self.db.keyword.create(name='Foo')
2415 nodeid = self._handle_mail('''Content-Type: text/plain;
2416 charset="iso-8859-1"
2417 From: Chef <chef@bork.bork.bork>
2418 To: issue_tracker@your.tracker.email.domain.example
2419 Subject: [keyword1] Testing... [name=Bar]
2420 Cc: richard@test.test
2421 Reply-To: chef@bork.bork.bork
2422 Message-Id: <dummy_test_message_id>
2424 ''')
2425 assert not os.path.exists(SENDMAILDEBUG)
2426 self.assertEqual(self.db.keyword.get('1', 'name'), 'Bar')
2428 def testClassStrictInvalid(self):
2429 self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'strict'
2430 self.instance.config.MAILGW_DEFAULT_CLASS = ''
2432 message = '''Content-Type: text/plain;
2433 charset="iso-8859-1"
2434 From: Chef <chef@bork.bork.bork>
2435 To: issue_tracker@your.tracker.email.domain.example
2436 Subject: Testing...
2437 Cc: richard@test.test
2438 Reply-To: chef@bork.bork.bork
2439 Message-Id: <dummy_test_message_id>
2441 '''
2442 self.assertRaises(MailUsageError, self._handle_mail, message)
2444 def testClassStrictValid(self):
2445 self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'strict'
2446 self.instance.config.MAILGW_DEFAULT_CLASS = ''
2448 nodeid = self._handle_mail('''Content-Type: text/plain;
2449 charset="iso-8859-1"
2450 From: Chef <chef@bork.bork.bork>
2451 To: issue_tracker@your.tracker.email.domain.example
2452 Subject: [issue] Testing...
2453 Cc: richard@test.test
2454 Reply-To: chef@bork.bork.bork
2455 Message-Id: <dummy_test_message_id>
2457 ''')
2459 assert not os.path.exists(SENDMAILDEBUG)
2460 self.assertEqual(self.db.issue.get(nodeid, 'title'), 'Testing...')
2462 #
2463 # TEST FOR INVALID COMMANDS HANDLING
2464 #
2465 def testInvalidCommands(self):
2466 self.assertRaises(MailUsageError, self._handle_mail,
2467 '''Content-Type: text/plain;
2468 charset="iso-8859-1"
2469 From: Chef <chef@bork.bork.bork>
2470 To: issue_tracker@your.tracker.email.domain.example
2471 Subject: testing [frobulated]
2472 Cc: richard@test.test
2473 Reply-To: chef@bork.bork.bork
2474 Message-Id: <dummy_test_message_id>
2476 ''')
2478 def testInvalidCommandPassthrough(self):
2479 self.instance.config.MAILGW_SUBJECT_SUFFIX_PARSING = 'none'
2480 nodeid = self._handle_mail('''Content-Type: text/plain;
2481 charset="iso-8859-1"
2482 From: Chef <chef@bork.bork.bork>
2483 To: issue_tracker@your.tracker.email.domain.example
2484 Subject: testing [frobulated]
2485 Cc: richard@test.test
2486 Reply-To: chef@bork.bork.bork
2487 Message-Id: <dummy_test_message_id>
2489 ''')
2490 assert not os.path.exists(SENDMAILDEBUG)
2491 self.assertEqual(self.db.issue.get(nodeid, 'title'),
2492 'testing [frobulated]')
2494 def testInvalidCommandPassthroughLoose(self):
2495 self.instance.config.MAILGW_SUBJECT_SUFFIX_PARSING = 'loose'
2496 nodeid = self._handle_mail('''Content-Type: text/plain;
2497 charset="iso-8859-1"
2498 From: Chef <chef@bork.bork.bork>
2499 To: issue_tracker@your.tracker.email.domain.example
2500 Subject: testing [frobulated]
2501 Cc: richard@test.test
2502 Reply-To: chef@bork.bork.bork
2503 Message-Id: <dummy_test_message_id>
2505 ''')
2506 assert not os.path.exists(SENDMAILDEBUG)
2507 self.assertEqual(self.db.issue.get(nodeid, 'title'),
2508 'testing [frobulated]')
2510 def testInvalidCommandPassthroughLooseOK(self):
2511 self.instance.config.MAILGW_SUBJECT_SUFFIX_PARSING = 'loose'
2512 nodeid = self._handle_mail('''Content-Type: text/plain;
2513 charset="iso-8859-1"
2514 From: Chef <chef@bork.bork.bork>
2515 To: issue_tracker@your.tracker.email.domain.example
2516 Subject: testing [assignedto=mary]
2517 Cc: richard@test.test
2518 Reply-To: chef@bork.bork.bork
2519 Message-Id: <dummy_test_message_id>
2521 ''')
2522 assert not os.path.exists(SENDMAILDEBUG)
2523 self.assertEqual(self.db.issue.get(nodeid, 'title'), 'testing')
2524 self.assertEqual(self.db.issue.get(nodeid, 'assignedto'), self.mary_id)
2526 def testCommandDelimiters(self):
2527 self.instance.config.MAILGW_SUBJECT_SUFFIX_DELIMITERS = '{}'
2528 nodeid = self._handle_mail('''Content-Type: text/plain;
2529 charset="iso-8859-1"
2530 From: Chef <chef@bork.bork.bork>
2531 To: issue_tracker@your.tracker.email.domain.example
2532 Subject: testing {assignedto=mary}
2533 Cc: richard@test.test
2534 Reply-To: chef@bork.bork.bork
2535 Message-Id: <dummy_test_message_id>
2537 ''')
2538 assert not os.path.exists(SENDMAILDEBUG)
2539 self.assertEqual(self.db.issue.get(nodeid, 'title'), 'testing')
2540 self.assertEqual(self.db.issue.get(nodeid, 'assignedto'), self.mary_id)
2542 def testPrefixDelimiters(self):
2543 self.instance.config.MAILGW_SUBJECT_SUFFIX_DELIMITERS = '{}'
2544 self.db.keyword.create(name='Foo')
2545 self._handle_mail('''Content-Type: text/plain;
2546 charset="iso-8859-1"
2547 From: richard <richard@test.test>
2548 To: issue_tracker@your.tracker.email.domain.example
2549 Message-Id: <followup_dummy_id>
2550 In-Reply-To: <dummy_test_message_id>
2551 Subject: {keyword1} Testing... {name=Bar}
2553 ''')
2554 assert not os.path.exists(SENDMAILDEBUG)
2555 self.assertEqual(self.db.keyword.get('1', 'name'), 'Bar')
2557 def testCommandDelimitersIgnore(self):
2558 self.instance.config.MAILGW_SUBJECT_SUFFIX_DELIMITERS = '{}'
2559 nodeid = self._handle_mail('''Content-Type: text/plain;
2560 charset="iso-8859-1"
2561 From: Chef <chef@bork.bork.bork>
2562 To: issue_tracker@your.tracker.email.domain.example
2563 Subject: testing [assignedto=mary]
2564 Cc: richard@test.test
2565 Reply-To: chef@bork.bork.bork
2566 Message-Id: <dummy_test_message_id>
2568 ''')
2569 assert not os.path.exists(SENDMAILDEBUG)
2570 self.assertEqual(self.db.issue.get(nodeid, 'title'),
2571 'testing [assignedto=mary]')
2572 self.assertEqual(self.db.issue.get(nodeid, 'assignedto'), None)
2574 def testReplytoMatch(self):
2575 self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'loose'
2576 nodeid = self.doNewIssue()
2577 nodeid2 = self._handle_mail('''Content-Type: text/plain;
2578 charset="iso-8859-1"
2579 From: Chef <chef@bork.bork.bork>
2580 To: issue_tracker@your.tracker.email.domain.example
2581 Message-Id: <dummy_test_message_id2>
2582 In-Reply-To: <dummy_test_message_id>
2583 Subject: Testing...
2585 Followup message.
2586 ''')
2588 nodeid3 = self._handle_mail('''Content-Type: text/plain;
2589 charset="iso-8859-1"
2590 From: Chef <chef@bork.bork.bork>
2591 To: issue_tracker@your.tracker.email.domain.example
2592 Message-Id: <dummy_test_message_id3>
2593 In-Reply-To: <dummy_test_message_id2>
2594 Subject: Testing...
2596 Yet another message in the same thread/issue.
2597 ''')
2599 self.assertEqual(nodeid, nodeid2)
2600 self.assertEqual(nodeid, nodeid3)
2602 def testHelpSubject(self):
2603 message = '''Content-Type: text/plain;
2604 charset="iso-8859-1"
2605 From: Chef <chef@bork.bork.bork>
2606 To: issue_tracker@your.tracker.email.domain.example
2607 Message-Id: <dummy_test_message_id2>
2608 In-Reply-To: <dummy_test_message_id>
2609 Subject: hElp
2612 '''
2613 self.assertRaises(MailUsageHelp, self._handle_mail, message)
2615 def testMaillistSubject(self):
2616 self.instance.config.MAILGW_SUBJECT_SUFFIX_DELIMITERS = '[]'
2617 self.db.keyword.create(name='Foo')
2618 self._handle_mail('''Content-Type: text/plain;
2619 charset="iso-8859-1"
2620 From: Chef <chef@bork.bork.bork>
2621 To: issue_tracker@your.tracker.email.domain.example
2622 Subject: [mailinglist-name] [keyword1] Testing.. [name=Bar]
2623 Cc: richard@test.test
2624 Reply-To: chef@bork.bork.bork
2625 Message-Id: <dummy_test_message_id>
2627 ''')
2629 assert not os.path.exists(SENDMAILDEBUG)
2630 self.assertEqual(self.db.keyword.get('1', 'name'), 'Bar')
2632 def testUnknownPrefixSubject(self):
2633 self.db.keyword.create(name='Foo')
2634 self._handle_mail('''Content-Type: text/plain;
2635 charset="iso-8859-1"
2636 From: Chef <chef@bork.bork.bork>
2637 To: issue_tracker@your.tracker.email.domain.example
2638 Subject: VeryStrangeRe: [keyword1] Testing.. [name=Bar]
2639 Cc: richard@test.test
2640 Reply-To: chef@bork.bork.bork
2641 Message-Id: <dummy_test_message_id>
2643 ''')
2645 assert not os.path.exists(SENDMAILDEBUG)
2646 self.assertEqual(self.db.keyword.get('1', 'name'), 'Bar')
2648 def testOneCharSubject(self):
2649 message = '''Content-Type: text/plain;
2650 charset="iso-8859-1"
2651 From: Chef <chef@bork.bork.bork>
2652 To: issue_tracker@your.tracker.email.domain.example
2653 Subject: b
2654 Cc: richard@test.test
2655 Reply-To: chef@bork.bork.bork
2656 Message-Id: <dummy_test_message_id>
2658 '''
2659 try:
2660 self._handle_mail(message)
2661 except MailUsageError:
2662 self.fail('MailUsageError raised')
2664 def testIssueidLast(self):
2665 nodeid1 = self.doNewIssue()
2666 nodeid2 = self._handle_mail('''Content-Type: text/plain;
2667 charset="iso-8859-1"
2668 From: mary <mary@test.test>
2669 To: issue_tracker@your.tracker.email.domain.example
2670 Message-Id: <followup_dummy_id>
2671 In-Reply-To: <dummy_test_message_id>
2672 Subject: New title [issue1]
2674 This is a second followup
2675 ''')
2677 assert nodeid1 == nodeid2
2678 self.assertEqual(self.db.issue.get(nodeid2, 'title'), "Testing...")
2680 def testSecurityMessagePermissionContent(self):
2681 id = self.doNewIssue()
2682 issue = self.db.issue.getnode (id)
2683 self.db.security.addRole(name='Nomsg')
2684 self.db.security.addPermissionToRole('Nomsg', 'Email Access')
2685 for cl in 'issue', 'file', 'keyword':
2686 for p in 'View', 'Edit', 'Create':
2687 self.db.security.addPermissionToRole('Nomsg', p, cl)
2688 self.db.user.set(self.mary_id, roles='Nomsg')
2689 nodeid = self._handle_mail('''Content-Type: text/plain;
2690 charset="iso-8859-1"
2691 From: Chef <chef@bork.bork.bork>
2692 To: issue_tracker@your.tracker.email.domain.example
2693 Message-Id: <dummy_test_message_id_2>
2694 Subject: [issue%(id)s] Testing... [nosy=+mary]
2696 Just a test reply
2697 '''%locals())
2698 assert os.path.exists(SENDMAILDEBUG)
2699 self.compareMessages(self._get_mail(),
2700 '''FROM: roundup-admin@your.tracker.email.domain.example
2701 TO: chef@bork.bork.bork, richard@test.test
2702 Content-Type: text/plain; charset="utf-8"
2703 Subject: [issue1] Testing...
2704 To: richard@test.test
2705 From: "Bork, Chef" <issue_tracker@your.tracker.email.domain.example>
2706 Reply-To: Roundup issue tracker
2707 <issue_tracker@your.tracker.email.domain.example>
2708 MIME-Version: 1.0
2709 Message-Id: <dummy_test_message_id_2>
2710 In-Reply-To: <dummy_test_message_id>
2711 X-Roundup-Name: Roundup issue tracker
2712 X-Roundup-Loop: hello
2713 X-Roundup-Issue-Status: chatting
2714 Content-Transfer-Encoding: quoted-printable
2717 Bork, Chef <chef@bork.bork.bork> added the comment:
2719 Just a test reply
2721 ----------
2722 nosy: +mary
2723 status: unread -> chatting
2725 _______________________________________________________________________
2726 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
2727 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
2728 _______________________________________________________________________
2729 ''')
2731 def testOutlookAttachment(self):
2732 message = '''X-MimeOLE: Produced By Microsoft Exchange V6.5
2733 Content-class: urn:content-classes:message
2734 MIME-Version: 1.0
2735 Content-Type: multipart/mixed;
2736 boundary="----_=_NextPart_001_01CACA65.40A51CBC"
2737 Subject: Example of a failed outlook attachment e-mail
2738 Date: Tue, 23 Mar 2010 01:43:44 -0700
2739 Message-ID: <CA37F17219784343816CA6613D2E339205E7D0F9@nrcwstexb1.nrc.ca>
2740 X-MS-Has-Attach: yes
2741 X-MS-TNEF-Correlator:
2742 Thread-Topic: Example of a failed outlook attachment e-mail
2743 Thread-Index: AcrKJo/t3pUBBwTpSwWNE3LE67UBDQ==
2744 From: "Hugh" <richard@test.test>
2745 To: <richard@test.test>
2746 X-OriginalArrivalTime: 23 Mar 2010 08:45:57.0350 (UTC) FILETIME=[41893860:01CACA65]
2748 This is a multi-part message in MIME format.
2750 ------_=_NextPart_001_01CACA65.40A51CBC
2751 Content-Type: multipart/alternative;
2752 boundary="----_=_NextPart_002_01CACA65.40A51CBC"
2755 ------_=_NextPart_002_01CACA65.40A51CBC
2756 Content-Type: text/plain;
2757 charset="us-ascii"
2758 Content-Transfer-Encoding: quoted-printable
2761 Hi Richard,
2763 I suppose this isn't the exact message that was sent but is a resend of
2764 one of my trial messages that failed. For your benefit I changed the
2765 subject line and am adding these words to the message body. Should
2766 still be as problematic, but if you like I can resend an exact copy of a
2767 failed message changing nothing except putting your address instead of
2768 our tracker.
2770 Thanks very much for taking time to look into this. Much appreciated.
2772 <<battery backup>>=20
2774 ------_=_NextPart_002_01CACA65.40A51CBC
2775 Content-Type: text/html;
2776 charset="us-ascii"
2777 Content-Transfer-Encoding: quoted-printable
2779 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
2780 <HTML>
2781 <HEAD>
2782 <META HTTP-EQUIV=3D"Content-Type" CONTENT=3D"text/html; =
2783 charset=3Dus-ascii">
2784 <META NAME=3D"Generator" CONTENT=3D"MS Exchange Server version =
2785 6.5.7654.12">
2786 <TITLE>Example of a failed outlook attachment e-mail</TITLE>
2787 </HEAD>
2788 <BODY>
2789 <!-- Converted from text/rtf format -->
2790 <BR>
2792 <P><FONT SIZE=3D2 FACE=3D"Arial">Hi Richard,</FONT>
2793 </P>
2795 <P><FONT SIZE=3D2 FACE=3D"Arial">I suppose this isn't the exact message =
2796 that was sent but is a resend of one of my trial messages that =
2797 failed. For your benefit I changed the subject line and am adding =
2798 these words to the message body. Should still be as problematic, =
2799 but if you like I can resend an exact copy of a failed message changing =
2800 nothing except putting your address instead of our tracker.</FONT></P>
2802 <P><FONT SIZE=3D2 FACE=3D"Arial">Thanks very much for taking time to =
2803 look into this. Much appreciated.</FONT>
2804 </P>
2805 <BR>
2807 <P><FONT FACE=3D"Arial" SIZE=3D2 COLOR=3D"#000000"> <<battery =
2808 backup>> </FONT>
2809 </P>
2811 </BODY>
2812 </HTML>
2813 ------_=_NextPart_002_01CACA65.40A51CBC--
2815 ------_=_NextPart_001_01CACA65.40A51CBC
2816 Content-Type: message/rfc822
2817 Content-Transfer-Encoding: 7bit
2819 X-MimeOLE: Produced By Microsoft Exchange V6.5
2820 MIME-Version: 1.0
2821 Content-Type: multipart/alternative;
2822 boundary="----_=_NextPart_003_01CAC15A.29717800"
2823 X-OriginalArrivalTime: 11 Mar 2010 20:33:51.0249 (UTC) FILETIME=[28FEE010:01CAC15A]
2824 Content-class: urn:content-classes:message
2825 Subject: battery backup
2826 Date: Thu, 11 Mar 2010 13:33:43 -0700
2827 Message-ID: <p06240809c7bf02f9624c@[128.114.22.203]>
2828 X-MS-Has-Attach:
2829 X-MS-TNEF-Correlator:
2830 Thread-Topic: battery backup
2831 Thread-Index: AcrBWimtulTrSvBdQ2CcfZ8lyQdxmQ==
2832 From: "Jerry" <jerry@test.test>
2833 To: "Hugh" <hugh@test.test>
2835 This is a multi-part message in MIME format.
2837 ------_=_NextPart_003_01CAC15A.29717800
2838 Content-Type: text/plain;
2839 charset="iso-8859-1"
2840 Content-Transfer-Encoding: quoted-printable
2842 Dear Hugh,
2843 A car batter has an energy capacity of ~ 500Wh. A UPS=20
2844 battery is worse than this.
2846 if we need to provied 100kW for 30 minutes that will take 100 car=20
2847 batteries. This seems like an awful lot of batteries.
2849 Of course I like your idea of making the time 1 minute, so we get to=20
2850 a more modest number of batteries
2852 Jerry
2855 ------_=_NextPart_003_01CAC15A.29717800
2856 Content-Type: text/html;
2857 charset="iso-8859-1"
2858 Content-Transfer-Encoding: quoted-printable
2860 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
2861 <HTML>
2862 <HEAD>
2863 <META HTTP-EQUIV=3D"Content-Type" CONTENT=3D"text/html; =
2864 charset=3Diso-8859-1">
2865 <META NAME=3D"Generator" CONTENT=3D"MS Exchange Server version =
2866 6.5.7654.12">
2867 <TITLE>battery backup</TITLE>
2868 </HEAD>
2869 <BODY>
2870 <!-- Converted from text/plain format -->
2872 <P><FONT SIZE=3D2>Dear Hugh,</FONT>
2874 <BR> <FONT SIZE=3D2>A car =
2875 batter has an energy capacity of ~ 500Wh. A UPS </FONT>
2877 <BR><FONT SIZE=3D2>battery is worse than this.</FONT>
2878 </P>
2880 <P><FONT SIZE=3D2>if we need to provied 100kW for 30 minutes that will =
2881 take 100 car </FONT>
2883 <BR><FONT SIZE=3D2>batteries. This seems like an awful lot of =
2884 batteries.</FONT>
2885 </P>
2887 <P><FONT SIZE=3D2>Of course I like your idea of making the time 1 =
2888 minute, so we get to </FONT>
2890 <BR><FONT SIZE=3D2>a more modest number of batteries</FONT>
2891 </P>
2893 <P><FONT SIZE=3D2>Jerry</FONT>
2894 </P>
2896 </BODY>
2897 </HTML>
2898 ------_=_NextPart_003_01CAC15A.29717800--
2900 ------_=_NextPart_001_01CACA65.40A51CBC--
2901 '''
2902 nodeid = self._handle_mail(message)
2903 assert not os.path.exists(SENDMAILDEBUG)
2904 msgid = self.db.issue.get(nodeid, 'messages')[0]
2905 self.assert_(self.db.msg.get(msgid, 'content').startswith('Hi Richard'))
2906 self.assertEqual(self.db.msg.get(msgid, 'files'), ['1', '2'])
2907 fileid = self.db.msg.get(msgid, 'files')[0]
2908 self.assertEqual(self.db.file.get(fileid, 'type'), 'text/html')
2909 fileid = self.db.msg.get(msgid, 'files')[1]
2910 self.assertEqual(self.db.file.get(fileid, 'type'), 'message/rfc822')
2912 def testForwardedMessageAttachment(self):
2913 message = '''Return-Path: <rgg@test.test>
2914 Received: from localhost(127.0.0.1), claiming to be "[115.130.26.69]"
2915 via SMTP by localhost, id smtpdAAApLaWrq; Tue Apr 13 23:10:05 2010
2916 Message-ID: <4BC4F9C7.50409@test.test>
2917 Date: Wed, 14 Apr 2010 09:09:59 +1000
2918 From: Rupert Goldie <rgg@test.test>
2919 User-Agent: Thunderbird 2.0.0.24 (Windows/20100228)
2920 MIME-Version: 1.0
2921 To: ekit issues <issues@test.test>
2922 Subject: [Fwd: PHP ERROR (fb)] post limit reached
2923 Content-Type: multipart/mixed; boundary="------------000807090608060304010403"
2925 This is a multi-part message in MIME format.
2926 --------------000807090608060304010403
2927 Content-Type: text/plain; charset=ISO-8859-1; format=flowed
2928 Content-Transfer-Encoding: 7bit
2930 Catch this exception and log it without emailing.
2932 --------------000807090608060304010403
2933 Content-Type: message/rfc822; name="PHP ERROR (fb).eml"
2934 Content-Transfer-Encoding: 7bit
2935 Content-Disposition: inline; filename="PHP ERROR (fb).eml"
2937 Return-Path: <ektravj@test.test>
2938 X-Sieve: CMU Sieve 2.2
2939 via SMTP by crown.off.ekorp.com, id smtpdAAA1JaW1o; Tue Apr 13 23:01:04 2010
2940 X-Virus-Scanned: by amavisd-new at ekit.com
2941 To: facebook-errors@test.test
2942 From: ektravj@test.test
2943 Subject: PHP ERROR (fb)
2944 Message-Id: <20100413230100.D601D27E84@mail2.elax3.ekorp.com>
2945 Date: Tue, 13 Apr 2010 23:01:00 +0000 (UTC)
2947 [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
2948 Stack trace:
2949 #0 /app/01/www/virtual/fb.ekit.com/htdocs/gateway/ekit/feed/index.php(178): fb_exceptions(Object(FacebookRestClientException))
2950 #1 {main}
2951 thrown in /app/01/www/virtual/fb.ekit.com/htdocs/includes/functions.php on line 280
2954 --------------000807090608060304010403--
2955 '''
2956 nodeid = self._handle_mail(message)
2957 assert not os.path.exists(SENDMAILDEBUG)
2958 msgid = self.db.issue.get(nodeid, 'messages')[0]
2959 self.assertEqual(self.db.msg.get(msgid, 'content'),
2960 'Catch this exception and log it without emailing.')
2961 self.assertEqual(self.db.msg.get(msgid, 'files'), ['1'])
2962 fileid = self.db.msg.get(msgid, 'files')[0]
2963 self.assertEqual(self.db.file.get(fileid, 'type'), 'message/rfc822')
2965 pgp_test_key = """
2966 -----BEGIN PGP PRIVATE KEY BLOCK-----
2967 Version: GnuPG v1.4.10 (GNU/Linux)
2969 lQOYBE6NqtsBCADG3UUMYxjwUOpDDVvr0Y8qkvKsgdF79en1zfHtRYlmZc+EJxg8
2970 53CCFGReQWJwOjyP3/SLJwJqfiPR7MAYAqJsm/4U2lxF7sIlEnlrRpFuvB625KOQ
2971 oedCkI4nLa+4QAXHxVX2qLx7es3r2JAoitZLX7ZtUB7qGSRh98DmdAgCY3CFN7iZ
2972 w6xpvIU+LNbsHSo1sf8VP6z7NHQFacgrVvLyRJ4C5lTPU42iM5E6HKxYFExNV3Rn
2973 +2G0bsuiifHV6nJQD73onjwcC6tU97W779dllHlhG3SSP0KlnwmCCvPMlQvROk0A
2974 rLyzKWcUpZwK1aLRYByjFMH9WYXRkhf08bkDABEBAAEAB/9dcmSb6YUyiBNM5t4m
2975 9hZcXykBvw79PRVvmBLy+BYUtArLgsN0+xx3Q7XWRMtJCVSkFw0GxpHwEM4sOyAZ
2976 KEPC3ZqLmgB6LDO2z/OWYVa9vlCAiPgDYtEVCnCCIInN/ue4dBZtDeVj8NUK2n0D
2977 UBpa2OMUgu3D+4SJNK7EnAmXdOaP6yfe6SXwcQfti8UoSFMJRkQkbY1rm/6iPfON
2978 t2RBAc7jW4eRzdciWCfvJfMSj9cqxTBQWz5vVadeY9Bm/IKw1HiKNBrJratq2v+D
2979 VGr0EkE9oOa5zbgZt2CFvknE4YhGmv81xFdK5GXr8L7nluZrePMblWbkI2ICTbV0
2980 RKLhBADYLvyDFX3cCoFzWmCl5L32G6LLfTt0yU0eUHcAzXd7QjOZN289HWYEmdVi
2981 kpxQPDxhWz+m8qt0HJGFl2+BKpZJBaT/L5AcqTBODxarxCSBTIVhCjD/46XvLY0h
2982 b2ZnG8HSLyFdRj07vk+qTvcF58qUuYFSLIF2t2imTCR/PwR/LwQA632vn2/7KIHj
2983 DR0O+G9eccTtAfX4TN4Q4Ua3WByClLZu/LSAenCLZ1CHVABEH6dwwjEARLeNUdLi
2984 Xy5KKlpr2vkoh96fnw0r2yg7dlBXq4yQKjJBXwNaKpuvqgzd8en0zJGLXxzt0NT3
2985 H+QNIP2WZMJSDQcDh3HhQrH0IeNdDm0D/iyJgSMXvqjm+KhYIa3xiloQsCRlDNm+
2986 XC7Eo5hsjvBaIKba6o9oL9oEiSVUFryPWKWIpi0P7/F5voJL6KFSZTor3x3o9CcC
2987 qHyqMHfNL23EAVJulySfPYLC7S3QB+tCBLXmKxb/YXCSLVi/UDzVgvWN6KIknZg2
2988 6uDLUzPbzDGjOZ20K1JvdW5kdXAgVGVzdGtleSA8cm91bmR1cC1hZG1pbkBleGFt
2989 cGxlLmNvbT6JATgEEwECACIFAk6NqtsCGwMGCwkIBwMCBhUIAgkKCwQWAgMBAh4B
2990 AheAAAoJEFrc/VYxw4dBG7oIAMCU9sRjK0dS7z/IGJ8KcCOQNN674AooJLn+J9Ew
2991 BT6/WxMY13nm/iK0uX2sOGnnXdg1PJ15IvD8zB5wXLbe25t6oRl5G58vmeKEyjc8
2992 QTB43/c8EsqY1ob7EVcuhrJCSS/JM8ApzQyXrh2QNmS+mBCJcx74MeipE6mNVT9j
2993 VscizixdFjqvJLkbW1kGac3Wj+c3ICNUIp0lbwb+Ve2rXlU+iXHEDqaVJDMEppme
2994 gDiZl+bKYrqljhZkH9Slv55uqqXUSg1SmTm/2orHUdAmDc6Y6azKNqQEqD2B0JyT
2995 jTJQJVMl5Oln63aZDCTxHkoqn8q06OjLJRD4on7jlanZEladA5gETo2q2wEIALEF
2996 poVkZrnqme2M8FObrQyVB+ZYT2mox56WLyInbxVFDg20qqIvQfVE0P69Yuf1OXkj
2997 q7bNI03Jvo+uzxpztOKPDo7tnbQ7bXbOmq3n4wUoN29NMrYNg6tF1ubEv1WwYUMw
2998 7LfF4BLMETXpT0JElV1+awfP9rrGiyWkH4enG612HT+1OoA0R0nNH0kslD6OhdoR
2999 VDqkyiCmdY9x176EhzhL3vCoN6ywRVTfFbAJiMv9UDzxs0SStmVOK/l5XLfWQO6f
3000 9boAHihpnxEfPIJhsD+FpVKVf3g85qWAjh2BfuzdW79vjLBdTHJQxg4HdhliWbXg
3001 PjjrVEgWEFVc+NDlNb0AEQEAAQAH/A1a6sbniI8q3DVoIP19zN7FI5UaQSuB2Jrl
3002 +Q+vlUQv3dvk2cwQmqj2vyRo2gcRS3u7LYpGDGLNqfshv22JyzId2YWo9vE7sTTP
3003 E4EJRz8CsLlMmVsoxoVBE0cnvXOpMef6z0ZyFEdMGVmi4iA9bQi3r+V6qBehQQA0
3004 U034VTCPN4yvWyq6TWsABesOx48nkQ5TlduIq2ZGNCR8Vd1fe6vGM7YXyQWxy5ke
3005 guqmph73H2bOB6hSuUnyBFKtinrF9MbCGA0PqheUVqy0p7og6x/pEoAVkKBJ9Ki+
3006 ePuQtBl5h9e3SbiN+r7aa6T0Ygx/7igl4eWPfvJYIXYXc4aKiwEEANEa5rBoN7Ta
3007 ED+R47Rg9w/EW3VDQ6R3Szy1rvIKjC6JlDyKlGgTeWEFjDeTwCB4xU7YtxVpt6bk
3008 b7RBtDkRck2+DwnscutA7Uxn267UxzNUd1IxhUccRFRfRS7OEnmlVmaLUnOeHHwe
3009 OrZyRSiNVnh0QABEJnwNjX4m139v6YD9BADYuM5XCawI63pYa3/l7UX9H5EH95OZ
3010 G9Hw7pXQ/YJYerSxRx+2q0+koRcdoby1TVaRrdDC+kOm3PI7e66S5rnaZ1FZeYQP
3011 nVYzyGqNnsvncs24kYBL8DYaDDfdm7vfzSEqia0VNqZ4TMbwJLk5f5Ys4WOF791G
3012 LPJgrAPG1jgDwQQAovKbw0u6blIUKsUYOLsviaLCyFC9DwaHqIZwjy8omnh7MaKE
3013 7+MXxJpfcVqFifj3CmqMdSmTfkgbKQPAI46Q1OKWvkvUxEvi7WATo4taEXupRFL5
3014 jnL8c4h46z8UpMX2CMwWU0k1Et/zlBoYy7gNON7tF2/uuN18zWFBlD72HuM9HIkB
3015 HwQYAQIACQUCTo2q2wIbDAAKCRBa3P1WMcOHQYI+CACDXJf1e695LpcsrVxKgiQr
3016 9fTbNJYB+tjbnd9vas92Gz1wZcQV9RjLkYQeEbOpWQud/1UeLRsFECMj7kbgAEqz
3017 7fIO4SeN8hFEvvZ+lI0AoBi4XvuUcCm5kvAodvmF8M9kQiUzF1gm+R9QQeJFDLpW
3018 8Gg7J3V3qM+N0FuXrypYcsEv7n/RJ1n+lhTW5hFzKBlNL4WrAhY/QsXEbmdsa478
3019 tzuHlETtjMm4g4DgppUdlCMegcpjjC9zKsN5xFOQmNMTO/6rPFUqk3k3T6I0LV4O
3020 zm4xNC+wwAA69ibnbrY1NR019et7RYW+qBudGbpJB1ABzkf/NsaCj6aTaubt7PZP
3021 =3uFZ
3022 -----END PGP PRIVATE KEY BLOCK-----
3023 """
3025 john_doe_key = """
3026 -----BEGIN PGP PRIVATE KEY BLOCK-----
3027 Version: GnuPG v1.4.10 (GNU/Linux)
3029 lQHYBE6NwvABBACxg7QqV2qHywwM3wae6HAHJVEo7EeYA6Lv0pZlW3Aw4CCCnpgJ
3030 jA7CekGFcmGmoCaN9ezuVAPTgUlK4yt8a7P6cT0vw1q341Om9IEKAu59RpNZN/H9
3031 6GfZ95bU51W/hdTFysH1DRwbCR3MowvLeA6Pk4cZlPsYHD0SD3De2i1BewARAQAB
3032 AAP+IRi4L6jKwPS3k3LFrj0SHhL0Fdgv5QTQjTxLNCyfN02iYhglqqoFWncm3jWc
3033 RU/YwGEYwrrBV97kBmVihzkhfgFRsxynE9PMGKKEAuRcAl21RPJDFA6Dlnp6M2No
3034 rR6eoAhrlZ8+KsK9JaXSMalzO/Yh4u3mOinq3f3XL96wAEkCAMAxeZMF5pnXARNR
3035 Y7u2clhNNnLuf+BzpENCFMaWzWPyTcvbf4xNK7ZHPxFVZpX5/qAPJ8rnTaOTHxnN
3036 5PgqbO8CAOxyrTw/muakTJLg+FXdn8BgxZGJXMT7KmkU9SReefjo7c1WlnZxKIAy
3037 6vLIG8WMGpdfCFDve0YLr/GGyDtOjDUB/RN3gn6qnAJThBnVk2wESZVx41fihbIF
3038 ACCKc9heFskzwurtvvp+bunM3quwrSH1hWvxiWJlDmGSn8zQFypGChifgLQZSm9o
3039 biBEb2UgPGpvaG5AdGVzdC50ZXN0Poi4BBMBAgAiBQJOjcLwAhsDBgsJCAcDAgYV
3040 CAIJCgsEFgIDAQIeAQIXgAAKCRC/z7qg+FujnPWiA/9T5SOGraRNIVVIyvJvYwkG
3041 OTAfQ0K3QMlLoQMPmaEbx9Q+isF15M9sOMcl1XGO4UNWuCPIIN8z/y/OLgAB0ZuL
3042 GlnAPPOOZ+MlaUXiMYo8oi416QZrMDf2H/Nkc10csiXm+zMl8RqeIQBEeljNyJ+t
3043 MG1EWn/PHTwFTd/VePuQdJ0B2AROjcLwAQQApw+72jKy0/wqg5SAtnVSkA1F3Jna
3044 /OG+ufz5dX57jkMFRvFoksWIWqHmiCjdE5QV8j+XTnjElhLsmrgjl7aAFveb30R6
3045 ImmcpKMN31vAp4RZlnyYbYUCY4IXFuz3n1CaUL+mRx5yNJykrZNfpWNf2pwozkZq
3046 lcDI69ymIW5acXUAEQEAAQAD/R7Jdf98l1scngMYo228ikYUxBqm2eX/fiQNXDWM
3047 ZR2u+TJ9O53MvFejfXX7Pd6lTDQUBwDFncjgXO0YYSrMzabhqpqoKLqOIpZmBuWC
3048 Hh1lvcFoIYoDR2LkiJ9EPBUEVUBDsUO8ajkILEE3G+DDpCaf9Vo82lCVyhDESqyt
3049 v4lxAgDOLpoq1Whv5Ejr6FifTWytCiQjH2P1SmePlQmy6oEJRUYA1t4zYrzCJUX8
3050 VAvPjh9JXilP6mhDbyQArWllewV9AgDPbVOf75ktRwfhje26tZsukqWYJCc1XvoH
3051 3PTzA7vH1HZZq7dvxa87PiSnkOLEsIAsI+4jpeMxpPlQRxUvHf1ZAf9rK3v3HMJ/
3052 2xVzwK24Oaj+g2O7D/fdqtLFGe5S5JobnTyp9xArDAhaZ/AKfDMYjUIKMP+bdNAf
3053 y8fQUtuawFltm1GInwQYAQIACQUCTo3C8AIbDAAKCRC/z7qg+FujnDzYA/9EU6Pv
3054 Ci1+DCtxjnq7IOvOjqExhFNGvN9Dw17Tl8HcyW3if9v5RxeSWYKl0DhzVdzMQgH/
3055 78q4F4W1q2IkB7SCpXizHLIc3eh8iZkbWZE+CGPvTpqyF03Yi16qhxpAbkGs2Yhq
3056 jTx5oJ4CL5fybBOZLg+BTlK4HIee6xEcbNoq+A==
3057 =ZKBW
3058 -----END PGP PRIVATE KEY BLOCK-----
3059 """
3061 ownertrust = """
3062 723762CD5A5FECB76DC72DF85ADCFD5631C38741:6:
3063 2940C247A1FBAD508A1AF24BBFCFBAA0F85BA39C:6:
3064 """
3066 class MailgwPGPTestCase(MailgwTestAbstractBase):
3067 pgphome = 'pgp-test-home'
3068 def setUp(self):
3069 MailgwTestAbstractBase.setUp(self)
3070 self.db.security.addRole (name = 'pgp', description = 'PGP Role')
3071 self.instance.config['PGP_HOMEDIR'] = self.pgphome
3072 self.instance.config['PGP_ROLES'] = 'pgp'
3073 self.instance.config['PGP_ENABLE'] = True
3074 self.db.user.set(self.john_id, roles='User,pgp')
3075 os.mkdir(self.pgphome)
3076 os.environ['GNUPGHOME'] = self.pgphome
3077 ctx = pyme.core.Context()
3078 key = pyme.core.Data(pgp_test_key)
3079 ctx.op_import(key)
3080 key = pyme.core.Data(john_doe_key)
3081 ctx.op_import(key)
3082 # trust-modelling with pyme isn't working in 0.8.1
3083 # based on libgpgme11 1.2.0, also tried in C -- same thing.
3084 otrust = os.popen ('gpg --import-ownertrust 2> /dev/null', 'w')
3085 otrust.write(ownertrust)
3086 otrust.close()
3088 def tearDown(self):
3089 MailgwTestAbstractBase.tearDown(self)
3090 if os.path.exists(self.pgphome):
3091 shutil.rmtree(self.pgphome)
3093 def testUnsignedMessage(self):
3094 self.assertRaises(MailUsageError, self._handle_mail,
3095 '''Content-Type: text/plain;
3096 charset="iso-8859-1"
3097 From: John Doe <john@test.test>
3098 To: issue_tracker@your.tracker.email.domain.example
3099 Message-Id: <dummy_test_message_id>
3100 Subject: [issue] Testing non-signed message...
3102 This is no pgp signed message.
3103 ''')
3105 def testSignedMessage(self):
3106 nodeid = self._handle_mail('''Content-Disposition: inline
3107 From: John Doe <john@test.test>
3108 To: issue_tracker@your.tracker.email.domain.example
3109 Subject: [issue] Testing signed message...
3110 Content-Type: multipart/signed; micalg=pgp-sha1;
3111 protocol="application/pgp-signature"; boundary="cWoXeonUoKmBZSoM"
3114 --cWoXeonUoKmBZSoM
3115 Content-Type: text/plain; charset=us-ascii
3116 Content-Disposition: inline
3118 This is a pgp signed message.
3120 --cWoXeonUoKmBZSoM
3121 Content-Type: application/pgp-signature; name="signature.asc"
3122 Content-Description: Digital signature
3123 Content-Disposition: inline
3125 -----BEGIN PGP SIGNATURE-----
3126 Version: GnuPG v1.4.10 (GNU/Linux)
3128 iJwEAQECAAYFAk6N4A4ACgkQv8+6oPhbo5x5nAP/d7R7SxTvLoVESI+1r7eDXp1J
3129 LvBVU2EF3YFYKBHMLcWmjG92fNjnHX6NENTEhTeBynba5IPEwUfITC+7PmgPmQkA
3130 VXnFZnwraHxsYgyFsVFN1kkTSbwRUlWl9+nTEsr0yBLTpZN0QSIDcwu+i/xVcg+t
3131 ZQ4K6R3m3AOw7BLdvZs=
3132 =wpYk
3133 -----END PGP SIGNATURE-----
3135 --cWoXeonUoKmBZSoM--
3136 ''')
3137 m = self.db.issue.get (nodeid, 'messages') [0]
3138 self.assertEqual(self.db.msg.get(m, 'content'),
3139 'This is a pgp signed message.')
3141 def test_suite():
3142 suite = unittest.TestSuite()
3143 suite.addTest(unittest.makeSuite(MailgwTestCase))
3144 if pyme is not None:
3145 suite.addTest(unittest.makeSuite(MailgwPGPTestCase))
3146 else:
3147 print "Skipping PGP tests"
3148 return suite
3150 if __name__ == '__main__':
3151 runner = unittest.TextTestRunner()
3152 unittest.main(testRunner=runner)
3154 # vim: set filetype=python sts=4 sw=4 et si :