1 # -*- encoding: utf-8 -*-
2 #
3 # Copyright (c) 2001 Richard Jones, richard@bofh.asn.au.
4 # This module is free software, and you may redistribute it and/or modify
5 # under the same terms as Python, so long as this copyright message and
6 # disclaimer are retained in their original form.
7 #
8 # This module is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11 #
12 # $Id: test_mailgw.py,v 1.96 2008-08-19 01:40:59 richard Exp $
14 # TODO: test bcc
16 import unittest, tempfile, os, shutil, errno, imp, sys, difflib, rfc822, time
18 from cStringIO import StringIO
20 if not os.environ.has_key('SENDMAILDEBUG'):
21 os.environ['SENDMAILDEBUG'] = 'mail-test.log'
22 SENDMAILDEBUG = os.environ['SENDMAILDEBUG']
24 from roundup import mailgw, i18n, roundupdb
25 from roundup.mailgw import MailGW, Unauthorized, uidFromAddress, \
26 parseContent, IgnoreLoop, IgnoreBulk, MailUsageError, MailUsageHelp
27 from roundup import init, instance, password, rfc2822, __version__
28 from roundup.anypy.sets_ import set
30 #import db_test_base
31 import memorydb
33 class Message(rfc822.Message):
34 """String-based Message class with equivalence test."""
35 def __init__(self, s):
36 rfc822.Message.__init__(self, StringIO(s.strip()))
38 def __eq__(self, other):
39 return (self.dict == other.dict and
40 self.fp.read() == other.fp.read())
42 class Tracker(object):
43 def open(self, journaltag):
44 return self.db
46 class DiffHelper:
47 def compareMessages(self, new, old):
48 """Compare messages for semantic equivalence."""
49 new, old = Message(new), Message(old)
51 # all Roundup-generated messages have "Precedence: bulk"
52 old['Precedence'] = 'bulk'
54 # don't try to compare the date
55 del new['date'], old['date']
57 if not new == old:
58 res = []
60 replace = {}
61 for key in new.keys():
62 if key.startswith('from '):
63 # skip the unix from line
64 continue
65 if key.lower() == 'x-roundup-version':
66 # version changes constantly, so handle it specially
67 if new[key] != __version__:
68 res.append(' %s: %r != %r' % (key, __version__,
69 new[key]))
70 elif key.lower() == 'content-type' and 'boundary=' in new[key]:
71 # handle mime messages
72 newmime = new[key].split('=',1)[-1].strip('"')
73 oldmime = old.get(key, '').split('=',1)[-1].strip('"')
74 replace ['--' + newmime] = '--' + oldmime
75 replace ['--' + newmime + '--'] = '--' + oldmime + '--'
76 elif new.get(key, '') != old.get(key, ''):
77 res.append(' %s: %r != %r' % (key, old.get(key, ''),
78 new.get(key, '')))
80 body_diff = self.compareStrings(new.fp.read(), old.fp.read(),
81 replace=replace)
82 if body_diff:
83 res.append('')
84 res.extend(body_diff)
86 if res:
87 res.insert(0, 'Generated message not correct (diff follows, expected vs. actual):')
88 raise AssertionError, '\n'.join(res)
90 def compareStrings(self, s2, s1, replace={}):
91 '''Note the reversal of s2 and s1 - difflib.SequenceMatcher wants
92 the first to be the "original" but in the calls in this file,
93 the second arg is the original. Ho hum.
94 Do replacements over the replace dict -- used for mime boundary
95 '''
96 l1 = s1.strip().split('\n')
97 l2 = [replace.get(i,i) for i in s2.strip().split('\n')]
98 if l1 == l2:
99 return
100 s = difflib.SequenceMatcher(None, l1, l2)
101 res = []
102 for value, s1s, s1e, s2s, s2e in s.get_opcodes():
103 if value == 'equal':
104 for i in range(s1s, s1e):
105 res.append(' %s'%l1[i])
106 elif value == 'delete':
107 for i in range(s1s, s1e):
108 res.append('- %s'%l1[i])
109 elif value == 'insert':
110 for i in range(s2s, s2e):
111 res.append('+ %s'%l2[i])
112 elif value == 'replace':
113 for i, j in zip(range(s1s, s1e), range(s2s, s2e)):
114 res.append('- %s'%l1[i])
115 res.append('+ %s'%l2[j])
117 return res
119 class MailgwTestCase(unittest.TestCase, DiffHelper):
120 count = 0
121 schema = 'classic'
122 def setUp(self):
123 self.old_translate_ = mailgw._
124 roundupdb._ = mailgw._ = i18n.get_translation(language='C').gettext
125 MailgwTestCase.count = MailgwTestCase.count + 1
127 # and open the database / "instance"
128 self.db = memorydb.create('admin')
129 self.instance = Tracker()
130 self.instance.db = self.db
131 self.instance.config = self.db.config
132 self.instance.MailGW = MailGW
134 self.chef_id = self.db.user.create(username='Chef',
135 address='chef@bork.bork.bork', realname='Bork, Chef', roles='User')
136 self.richard_id = self.db.user.create(username='richard',
137 address='richard@test.test', roles='User')
138 self.mary_id = self.db.user.create(username='mary',
139 address='mary@test.test', roles='User', realname='Contrary, Mary')
140 self.john_id = self.db.user.create(username='john',
141 address='john@test.test', roles='User', realname='John Doe',
142 alternate_addresses='jondoe@test.test\njohn.doe@test.test')
143 self.rgg_id = self.db.user.create(username='rgg',
144 address='rgg@test.test', roles='User')
146 def tearDown(self):
147 roundupdb._ = mailgw._ = self.old_translate_
148 if os.path.exists(SENDMAILDEBUG):
149 os.remove(SENDMAILDEBUG)
150 self.db.close()
152 def _create_mailgw(self, message, args=()):
153 class MailGW(self.instance.MailGW):
154 def handle_message(self, message):
155 return self._handle_message(message)
156 handler = MailGW(self.instance, args)
157 handler.db = self.db
158 return handler
160 def _handle_mail(self, message, args=()):
161 handler = self._create_mailgw(message, args)
162 handler.trapExceptions = 0
163 return handler.main(StringIO(message))
165 def _get_mail(self):
166 f = open(SENDMAILDEBUG)
167 try:
168 return f.read()
169 finally:
170 f.close()
172 def testEmptyMessage(self):
173 nodeid = self._handle_mail('''Content-Type: text/plain;
174 charset="iso-8859-1"
175 From: Chef <chef@bork.bork.bork>
176 To: issue_tracker@your.tracker.email.domain.example
177 Cc: richard@test.test
178 Reply-To: chef@bork.bork.bork
179 Message-Id: <dummy_test_message_id>
180 Subject: [issue] Testing...
182 ''')
183 assert not os.path.exists(SENDMAILDEBUG)
184 self.assertEqual(self.db.issue.get(nodeid, 'title'), 'Testing...')
186 def testMessageWithFromInIt(self):
187 nodeid = self._handle_mail('''Content-Type: text/plain;
188 charset="iso-8859-1"
189 From: Chef <chef@bork.bork.bork>
190 To: issue_tracker@your.tracker.email.domain.example
191 Cc: richard@test.test
192 Reply-To: chef@bork.bork.bork
193 Message-Id: <dummy_test_message_id>
194 Subject: [issue] Testing...
196 From here to there!
197 ''')
198 assert not os.path.exists(SENDMAILDEBUG)
199 msgid = self.db.issue.get(nodeid, 'messages')[0]
200 self.assertEqual(self.db.msg.get(msgid, 'content'), 'From here to there!')
202 def testNoMessageId(self):
203 self.instance.config['MAIL_DOMAIN'] = 'example.com'
204 nodeid = self._handle_mail('''Content-Type: text/plain;
205 charset="iso-8859-1"
206 From: Chef <chef@bork.bork.bork>
207 To: issue_tracker@your.tracker.email.domain.example
208 Cc: richard@test.test
209 Reply-To: chef@bork.bork.bork
210 Subject: [issue] Testing...
212 Hi there!
213 ''')
214 assert not os.path.exists(SENDMAILDEBUG)
215 msgid = self.db.issue.get(nodeid, 'messages')[0]
216 messageid = self.db.msg.get(msgid, 'messageid')
217 x1, x2 = messageid.split('@')
218 self.assertEqual(x2, 'example.com>')
219 x = x1.split('.')[-1]
220 self.assertEqual(x, 'issueNone')
221 nodeid = self._handle_mail('''Content-Type: text/plain;
222 charset="iso-8859-1"
223 From: Chef <chef@bork.bork.bork>
224 To: issue_tracker@your.tracker.email.domain.example
225 Subject: [issue%(nodeid)s] Testing...
227 Just a test reply
228 '''%locals())
229 msgid = self.db.issue.get(nodeid, 'messages')[-1]
230 messageid = self.db.msg.get(msgid, 'messageid')
231 x1, x2 = messageid.split('@')
232 self.assertEqual(x2, 'example.com>')
233 x = x1.split('.')[-1]
234 self.assertEqual(x, "issue%s"%nodeid)
236 def testOptions(self):
237 nodeid = self._handle_mail('''Content-Type: text/plain;
238 charset="iso-8859-1"
239 From: Chef <chef@bork.bork.bork>
240 To: issue_tracker@your.tracker.email.domain.example
241 Message-Id: <dummy_test_message_id>
242 Reply-To: chef@bork.bork.bork
243 Subject: [issue] Testing...
245 Hi there!
246 ''', (('-C', 'issue'), ('-S', 'status=chatting;priority=critical')))
247 self.assertEqual(self.db.issue.get(nodeid, 'status'), '3')
248 self.assertEqual(self.db.issue.get(nodeid, 'priority'), '1')
250 def testOptionsMulti(self):
251 nodeid = self._handle_mail('''Content-Type: text/plain;
252 charset="iso-8859-1"
253 From: Chef <chef@bork.bork.bork>
254 To: issue_tracker@your.tracker.email.domain.example
255 Message-Id: <dummy_test_message_id>
256 Reply-To: chef@bork.bork.bork
257 Subject: [issue] Testing...
259 Hi there!
260 ''', (('-C', 'issue'), ('-S', 'status=chatting'), ('-S', 'priority=critical')))
261 self.assertEqual(self.db.issue.get(nodeid, 'status'), '3')
262 self.assertEqual(self.db.issue.get(nodeid, 'priority'), '1')
264 def testOptionClass(self):
265 nodeid = self._handle_mail('''Content-Type: text/plain;
266 charset="iso-8859-1"
267 From: Chef <chef@bork.bork.bork>
268 To: issue_tracker@your.tracker.email.domain.example
269 Message-Id: <dummy_test_message_id>
270 Reply-To: chef@bork.bork.bork
271 Subject: [issue] Testing... [status=chatting;priority=critical]
273 Hi there!
274 ''', (('-c', 'issue'),))
275 self.assertEqual(self.db.issue.get(nodeid, 'title'), 'Testing...')
276 self.assertEqual(self.db.issue.get(nodeid, 'status'), '3')
277 self.assertEqual(self.db.issue.get(nodeid, 'priority'), '1')
279 def doNewIssue(self):
280 nodeid = self._handle_mail('''Content-Type: text/plain;
281 charset="iso-8859-1"
282 From: Chef <chef@bork.bork.bork>
283 To: issue_tracker@your.tracker.email.domain.example
284 Cc: richard@test.test
285 Message-Id: <dummy_test_message_id>
286 Subject: [issue] Testing...
288 This is a test submission of a new issue.
289 ''')
290 assert not os.path.exists(SENDMAILDEBUG)
291 l = self.db.issue.get(nodeid, 'nosy')
292 l.sort()
293 self.assertEqual(l, [self.chef_id, self.richard_id])
294 return nodeid
296 def testNewIssue(self):
297 self.doNewIssue()
299 def testNewIssueNosy(self):
300 self.instance.config.ADD_AUTHOR_TO_NOSY = 'yes'
301 nodeid = self._handle_mail('''Content-Type: text/plain;
302 charset="iso-8859-1"
303 From: Chef <chef@bork.bork.bork>
304 To: issue_tracker@your.tracker.email.domain.example
305 Cc: richard@test.test
306 Message-Id: <dummy_test_message_id>
307 Subject: [issue] Testing...
309 This is a test submission of a new issue.
310 ''')
311 assert not os.path.exists(SENDMAILDEBUG)
312 l = self.db.issue.get(nodeid, 'nosy')
313 l.sort()
314 self.assertEqual(l, [self.chef_id, self.richard_id])
316 def testAlternateAddress(self):
317 self._handle_mail('''Content-Type: text/plain;
318 charset="iso-8859-1"
319 From: John Doe <john.doe@test.test>
320 To: issue_tracker@your.tracker.email.domain.example
321 Message-Id: <dummy_test_message_id>
322 Subject: [issue] Testing...
324 This is a test submission of a new issue.
325 ''')
326 userlist = self.db.user.list()
327 assert not os.path.exists(SENDMAILDEBUG)
328 self.assertEqual(userlist, self.db.user.list(),
329 "user created when it shouldn't have been")
331 def testNewIssueNoClass(self):
332 self._handle_mail('''Content-Type: text/plain;
333 charset="iso-8859-1"
334 From: Chef <chef@bork.bork.bork>
335 To: issue_tracker@your.tracker.email.domain.example
336 Cc: richard@test.test
337 Message-Id: <dummy_test_message_id>
338 Subject: Testing...
340 This is a test submission of a new issue.
341 ''')
342 assert not os.path.exists(SENDMAILDEBUG)
344 def testNewIssueAuthMsg(self):
345 # TODO: fix the damn config - this is apalling
346 self.db.config.MESSAGES_TO_AUTHOR = 'yes'
347 self._handle_mail('''Content-Type: text/plain;
348 charset="iso-8859-1"
349 From: Chef <chef@bork.bork.bork>
350 To: issue_tracker@your.tracker.email.domain.example
351 Message-Id: <dummy_test_message_id>
352 Subject: [issue] Testing... [nosy=mary; assignedto=richard]
354 This is a test submission of a new issue.
355 ''')
356 self.compareMessages(self._get_mail(),
357 '''FROM: roundup-admin@your.tracker.email.domain.example
358 TO: chef@bork.bork.bork, mary@test.test, richard@test.test
359 Content-Type: text/plain; charset="utf-8"
360 Subject: [issue1] Testing...
361 To: chef@bork.bork.bork, mary@test.test, richard@test.test
362 From: "Bork, Chef" <issue_tracker@your.tracker.email.domain.example>
363 Reply-To: Roundup issue tracker
364 <issue_tracker@your.tracker.email.domain.example>
365 MIME-Version: 1.0
366 Message-Id: <dummy_test_message_id>
367 X-Roundup-Name: Roundup issue tracker
368 X-Roundup-Loop: hello
369 X-Roundup-Issue-Status: unread
370 Content-Transfer-Encoding: quoted-printable
373 New submission from Bork, Chef <chef@bork.bork.bork>:
375 This is a test submission of a new issue.
377 ----------
378 assignedto: richard
379 messages: 1
380 nosy: Chef, mary, richard
381 status: unread
382 title: Testing...
384 _______________________________________________________________________
385 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
386 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
387 _______________________________________________________________________
388 ''')
390 def testNewIssueNoAuthorInfo(self):
391 self.db.config.MAIL_ADD_AUTHORINFO = 'no'
392 self._handle_mail('''Content-Type: text/plain;
393 charset="iso-8859-1"
394 From: Chef <chef@bork.bork.bork>
395 To: issue_tracker@your.tracker.email.domain.example
396 Message-Id: <dummy_test_message_id>
397 Subject: [issue] Testing... [nosy=mary; assignedto=richard]
399 This is a test submission of a new issue.
400 ''')
401 self.compareMessages(self._get_mail(),
402 '''FROM: roundup-admin@your.tracker.email.domain.example
403 TO: chef@bork.bork.bork, mary@test.test, richard@test.test
404 Content-Type: text/plain; charset="utf-8"
405 Subject: [issue1] Testing...
406 To: mary@test.test, richard@test.test
407 From: "Bork, Chef" <issue_tracker@your.tracker.email.domain.example>
408 Reply-To: Roundup issue tracker
409 <issue_tracker@your.tracker.email.domain.example>
410 MIME-Version: 1.0
411 Message-Id: <dummy_test_message_id>
412 X-Roundup-Name: Roundup issue tracker
413 X-Roundup-Loop: hello
414 X-Roundup-Issue-Status: unread
415 Content-Transfer-Encoding: quoted-printable
417 This is a test submission of a new issue.
419 ----------
420 assignedto: richard
421 messages: 1
422 nosy: Chef, mary, richard
423 status: unread
424 title: Testing...
426 _______________________________________________________________________
427 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
428 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
429 _______________________________________________________________________
430 ''')
432 def testNewIssueNoAuthorEmail(self):
433 self.db.config.MAIL_ADD_AUTHOREMAIL = 'no'
434 self._handle_mail('''Content-Type: text/plain;
435 charset="iso-8859-1"
436 From: Chef <chef@bork.bork.bork>
437 To: issue_tracker@your.tracker.email.domain.example
438 Message-Id: <dummy_test_message_id>
439 Subject: [issue] Testing... [nosy=mary; assignedto=richard]
441 This is a test submission of a new issue.
442 ''')
443 self.compareMessages(self._get_mail(),
444 '''FROM: roundup-admin@your.tracker.email.domain.example
445 TO: chef@bork.bork.bork, mary@test.test, richard@test.test
446 Content-Type: text/plain; charset="utf-8"
447 Subject: [issue1] Testing...
448 To: mary@test.test, richard@test.test
449 From: "Bork, Chef" <issue_tracker@your.tracker.email.domain.example>
450 Reply-To: Roundup issue tracker
451 <issue_tracker@your.tracker.email.domain.example>
452 MIME-Version: 1.0
453 Message-Id: <dummy_test_message_id>
454 X-Roundup-Name: Roundup issue tracker
455 X-Roundup-Loop: hello
456 X-Roundup-Issue-Status: unread
457 Content-Transfer-Encoding: quoted-printable
459 New submission from Bork, Chef:
461 This is a test submission of a new issue.
463 ----------
464 assignedto: richard
465 messages: 1
466 nosy: Chef, mary, richard
467 status: unread
468 title: Testing...
470 _______________________________________________________________________
471 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
472 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
473 _______________________________________________________________________
474 ''')
476 multipart_msg = '''From: mary <mary@test.test>
477 To: issue_tracker@your.tracker.email.domain.example
478 Message-Id: <followup_dummy_id>
479 In-Reply-To: <dummy_test_message_id>
480 Subject: [issue1] Testing...
481 Content-Type: multipart/mixed; boundary="bxyzzy"
482 Content-Disposition: inline
485 --bxyzzy
486 Content-Type: multipart/alternative; boundary="bCsyhTFzCvuiizWE"
487 Content-Disposition: inline
489 --bCsyhTFzCvuiizWE
490 Content-Type: text/plain; charset=us-ascii
491 Content-Disposition: inline
493 test attachment first text/plain
495 --bCsyhTFzCvuiizWE
496 Content-Type: application/octet-stream
497 Content-Disposition: attachment; filename="first.dvi"
498 Content-Transfer-Encoding: base64
500 SnVzdCBhIHRlc3QgAQo=
502 --bCsyhTFzCvuiizWE
503 Content-Type: text/plain; charset=us-ascii
504 Content-Disposition: inline
506 test attachment second text/plain
508 --bCsyhTFzCvuiizWE
509 Content-Type: text/html
510 Content-Disposition: inline
512 <html>
513 to be ignored.
514 </html>
516 --bCsyhTFzCvuiizWE--
518 --bxyzzy
519 Content-Type: multipart/alternative; boundary="bCsyhTFzCvuiizWF"
520 Content-Disposition: inline
522 --bCsyhTFzCvuiizWF
523 Content-Type: text/plain; charset=us-ascii
524 Content-Disposition: inline
526 test attachment third text/plain
528 --bCsyhTFzCvuiizWF
529 Content-Type: application/octet-stream
530 Content-Disposition: attachment; filename="second.dvi"
531 Content-Transfer-Encoding: base64
533 SnVzdCBhIHRlc3QK
535 --bCsyhTFzCvuiizWF--
537 --bxyzzy--
538 '''
540 multipart_msg_latin1 = '''From: mary <mary@test.test>
541 To: issue_tracker@your.tracker.email.domain.example
542 Message-Id: <followup_dummy_id>
543 In-Reply-To: <dummy_test_message_id>
544 Subject: [issue1] Testing...
545 Content-Type: multipart/alternative; boundary=001485f339f8f361fb049188dbba
548 --001485f339f8f361fb049188dbba
549 Content-Type: text/plain; charset=ISO-8859-1
550 Content-Transfer-Encoding: quoted-printable
552 umlaut =E4=F6=FC=C4=D6=DC=DF
554 --001485f339f8f361fb049188dbba
555 Content-Type: text/html; charset=ISO-8859-1
556 Content-Transfer-Encoding: quoted-printable
558 <html>umlaut =E4=F6=FC=C4=D6=DC=DF</html>
560 --001485f339f8f361fb049188dbba--
561 '''
563 multipart_msg_rfc822 = '''From: mary <mary@test.test>
564 To: issue_tracker@your.tracker.email.domain.example
565 Message-Id: <followup_dummy_id>
566 In-Reply-To: <dummy_test_message_id>
567 Subject: [issue1] Testing...
568 Content-Type: multipart/mixed; boundary=001485f339f8f361fb049188dbba
570 This is a multi-part message in MIME format.
571 --001485f339f8f361fb049188dbba
572 Content-Type: text/plain; charset=ISO-8859-15
573 Content-Transfer-Encoding: 7bit
575 First part: Text
577 --001485f339f8f361fb049188dbba
578 Content-Type: message/rfc822; name="Fwd: Original email subject.eml"
579 Content-Transfer-Encoding: 7bit
580 Content-Disposition: attachment; filename="Fwd: Original email subject.eml"
582 Message-Id: <followup_dummy_id_2>
583 In-Reply-To: <dummy_test_message_id_2>
584 MIME-Version: 1.0
585 Subject: Fwd: Original email subject
586 Date: Mon, 23 Aug 2010 08:23:33 +0200
587 Content-Type: multipart/alternative; boundary="090500050101020406060002"
589 This is a multi-part message in MIME format.
590 --090500050101020406060002
591 Content-Type: text/plain; charset=ISO-8859-15; format=flowed
592 Content-Transfer-Encoding: 7bit
594 some text in inner email
595 ========================
597 --090500050101020406060002
598 Content-Type: text/html; charset=ISO-8859-15
599 Content-Transfer-Encoding: 7bit
601 <html>
602 some text in inner email
603 ========================
604 </html>
606 --090500050101020406060002--
608 --001485f339f8f361fb049188dbba--
609 '''
611 def testMultipartKeepAlternatives(self):
612 self.doNewIssue()
613 self._handle_mail(self.multipart_msg)
614 messages = self.db.issue.get('1', 'messages')
615 messages.sort()
616 msg = self.db.msg.getnode (messages[-1])
617 assert(len(msg.files) == 5)
618 names = {0 : 'first.dvi', 4 : 'second.dvi'}
619 content = {3 : 'test attachment third text/plain\n',
620 4 : 'Just a test\n'}
621 for n, id in enumerate (msg.files):
622 f = self.db.file.getnode (id)
623 self.assertEqual(f.name, names.get (n, 'unnamed'))
624 if n in content :
625 self.assertEqual(f.content, content [n])
626 self.assertEqual(msg.content, 'test attachment second text/plain')
628 def testMultipartKeepFiles(self):
629 self.doNewIssue()
630 self._handle_mail(self.multipart_msg)
631 messages = self.db.issue.get('1', 'messages')
632 messages.sort()
633 msg = self.db.msg.getnode (messages[-1])
634 assert(len(msg.files) == 5)
635 issue = self.db.issue.getnode ('1')
636 assert(len(issue.files) == 5)
637 names = {0 : 'first.dvi', 4 : 'second.dvi'}
638 content = {3 : 'test attachment third text/plain\n',
639 4 : 'Just a test\n'}
640 for n, id in enumerate (msg.files):
641 f = self.db.file.getnode (id)
642 self.assertEqual(f.name, names.get (n, 'unnamed'))
643 if n in content :
644 self.assertEqual(f.content, content [n])
645 self.assertEqual(msg.content, 'test attachment second text/plain')
646 self._handle_mail('''From: mary <mary@test.test>
647 To: issue_tracker@your.tracker.email.domain.example
648 Message-Id: <followup_dummy_id2>
649 In-Reply-To: <dummy_test_message_id>
650 Subject: [issue1] Testing...
652 This ist a message without attachment
653 ''')
654 issue = self.db.issue.getnode ('1')
655 assert(len(issue.files) == 5)
656 self.assertEqual(issue.files, ['1', '2', '3', '4', '5'])
658 def testMultipartDropAlternatives(self):
659 self.doNewIssue()
660 self.db.config.MAILGW_IGNORE_ALTERNATIVES = True
661 self._handle_mail(self.multipart_msg)
662 messages = self.db.issue.get('1', 'messages')
663 messages.sort()
664 msg = self.db.msg.getnode (messages[-1])
665 assert(len(msg.files) == 2)
666 names = {1 : 'second.dvi'}
667 content = {0 : 'test attachment third text/plain\n',
668 1 : 'Just a test\n'}
669 for n, id in enumerate (msg.files):
670 f = self.db.file.getnode (id)
671 self.assertEqual(f.name, names.get (n, 'unnamed'))
672 if n in content :
673 self.assertEqual(f.content, content [n])
674 self.assertEqual(msg.content, 'test attachment second text/plain')
676 def testMultipartCharsetUTF8NoAttach(self):
677 c = 'umlaut \xc3\xa4\xc3\xb6\xc3\xbc\xc3\x84\xc3\x96\xc3\x9c\xc3\x9f'
678 self.doNewIssue()
679 self.db.config.NOSY_MAX_ATTACHMENT_SIZE = 0
680 self._handle_mail(self.multipart_msg_latin1)
681 messages = self.db.issue.get('1', 'messages')
682 messages.sort()
683 msg = self.db.msg.getnode (messages[-1])
684 assert(len(msg.files) == 1)
685 name = 'unnamed'
686 content = '<html>' + c + '</html>\n'
687 for n, id in enumerate (msg.files):
688 f = self.db.file.getnode (id)
689 self.assertEqual(f.name, name)
690 self.assertEqual(f.content, content)
691 self.assertEqual(msg.content, c)
692 self.compareMessages(self._get_mail(),
693 '''FROM: roundup-admin@your.tracker.email.domain.example
694 TO: chef@bork.bork.bork, richard@test.test
695 Content-Type: text/plain; charset="utf-8"
696 Subject: [issue1] Testing...
697 To: chef@bork.bork.bork, richard@test.test
698 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
699 Reply-To: Roundup issue tracker
700 <issue_tracker@your.tracker.email.domain.example>
701 MIME-Version: 1.0
702 Message-Id: <followup_dummy_id>
703 In-Reply-To: <dummy_test_message_id>
704 X-Roundup-Name: Roundup issue tracker
705 X-Roundup-Loop: hello
706 X-Roundup-Issue-Status: chatting
707 X-Roundup-Issue-Files: unnamed
708 Content-Transfer-Encoding: quoted-printable
711 Contrary, Mary <mary@test.test> added the comment:
713 umlaut =C3=A4=C3=B6=C3=BC=C3=84=C3=96=C3=9C=C3=9F
714 File 'unnamed' not attached - you can download it from http://tracker.examp=
715 le/cgi-bin/roundup.cgi/bugs/file1.
717 ----------
718 status: unread -> chatting
720 _______________________________________________________________________
721 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
722 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
723 _______________________________________________________________________
724 ''')
726 def testMultipartCharsetLatin1NoAttach(self):
727 c = 'umlaut \xc3\xa4\xc3\xb6\xc3\xbc\xc3\x84\xc3\x96\xc3\x9c\xc3\x9f'
728 self.doNewIssue()
729 self.db.config.NOSY_MAX_ATTACHMENT_SIZE = 0
730 self.db.config.MAIL_CHARSET = 'iso-8859-1'
731 self._handle_mail(self.multipart_msg_latin1)
732 messages = self.db.issue.get('1', 'messages')
733 messages.sort()
734 msg = self.db.msg.getnode (messages[-1])
735 assert(len(msg.files) == 1)
736 name = 'unnamed'
737 content = '<html>' + c + '</html>\n'
738 for n, id in enumerate (msg.files):
739 f = self.db.file.getnode (id)
740 self.assertEqual(f.name, name)
741 self.assertEqual(f.content, content)
742 self.assertEqual(msg.content, c)
743 self.compareMessages(self._get_mail(),
744 '''FROM: roundup-admin@your.tracker.email.domain.example
745 TO: chef@bork.bork.bork, richard@test.test
746 Content-Type: text/plain; charset="iso-8859-1"
747 Subject: [issue1] Testing...
748 To: chef@bork.bork.bork, richard@test.test
749 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
750 Reply-To: Roundup issue tracker
751 <issue_tracker@your.tracker.email.domain.example>
752 MIME-Version: 1.0
753 Message-Id: <followup_dummy_id>
754 In-Reply-To: <dummy_test_message_id>
755 X-Roundup-Name: Roundup issue tracker
756 X-Roundup-Loop: hello
757 X-Roundup-Issue-Status: chatting
758 X-Roundup-Issue-Files: unnamed
759 Content-Transfer-Encoding: quoted-printable
762 Contrary, Mary <mary@test.test> added the comment:
764 umlaut =E4=F6=FC=C4=D6=DC=DF
765 File 'unnamed' not attached - you can download it from http://tracker.examp=
766 le/cgi-bin/roundup.cgi/bugs/file1.
768 ----------
769 status: unread -> chatting
771 _______________________________________________________________________
772 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
773 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
774 _______________________________________________________________________
775 ''')
777 def testMultipartCharsetUTF8AttachFile(self):
778 c = 'umlaut \xc3\xa4\xc3\xb6\xc3\xbc\xc3\x84\xc3\x96\xc3\x9c\xc3\x9f'
779 self.doNewIssue()
780 self._handle_mail(self.multipart_msg_latin1)
781 messages = self.db.issue.get('1', 'messages')
782 messages.sort()
783 msg = self.db.msg.getnode (messages[-1])
784 assert(len(msg.files) == 1)
785 name = 'unnamed'
786 content = '<html>' + c + '</html>\n'
787 for n, id in enumerate (msg.files):
788 f = self.db.file.getnode (id)
789 self.assertEqual(f.name, name)
790 self.assertEqual(f.content, content)
791 self.assertEqual(msg.content, c)
792 self.compareMessages(self._get_mail(),
793 '''FROM: roundup-admin@your.tracker.email.domain.example
794 TO: chef@bork.bork.bork, richard@test.test
795 Content-Type: multipart/mixed; boundary="utf-8"
796 Subject: [issue1] Testing...
797 To: chef@bork.bork.bork, richard@test.test
798 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
799 Reply-To: Roundup issue tracker
800 <issue_tracker@your.tracker.email.domain.example>
801 MIME-Version: 1.0
802 Message-Id: <followup_dummy_id>
803 In-Reply-To: <dummy_test_message_id>
804 X-Roundup-Name: Roundup issue tracker
805 X-Roundup-Loop: hello
806 X-Roundup-Issue-Status: chatting
807 X-Roundup-Issue-Files: unnamed
808 Content-Transfer-Encoding: quoted-printable
811 --utf-8
812 MIME-Version: 1.0
813 Content-Type: text/plain; charset="utf-8"
814 Content-Transfer-Encoding: quoted-printable
817 Contrary, Mary <mary@test.test> added the comment:
819 umlaut =C3=A4=C3=B6=C3=BC=C3=84=C3=96=C3=9C=C3=9F
821 ----------
822 status: unread -> chatting
824 _______________________________________________________________________
825 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
826 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
827 _______________________________________________________________________
828 --utf-8
829 Content-Type: text/html
830 MIME-Version: 1.0
831 Content-Transfer-Encoding: base64
832 Content-Disposition: attachment;
833 filename="unnamed"
835 PGh0bWw+dW1sYXV0IMOkw7bDvMOEw5bDnMOfPC9odG1sPgo=
837 --utf-8--
838 ''')
840 def testMultipartCharsetLatin1AttachFile(self):
841 c = 'umlaut \xc3\xa4\xc3\xb6\xc3\xbc\xc3\x84\xc3\x96\xc3\x9c\xc3\x9f'
842 self.doNewIssue()
843 self.db.config.MAIL_CHARSET = 'iso-8859-1'
844 self._handle_mail(self.multipart_msg_latin1)
845 messages = self.db.issue.get('1', 'messages')
846 messages.sort()
847 msg = self.db.msg.getnode (messages[-1])
848 assert(len(msg.files) == 1)
849 name = 'unnamed'
850 content = '<html>' + c + '</html>\n'
851 for n, id in enumerate (msg.files):
852 f = self.db.file.getnode (id)
853 self.assertEqual(f.name, name)
854 self.assertEqual(f.content, content)
855 self.assertEqual(msg.content, c)
856 self.compareMessages(self._get_mail(),
857 '''FROM: roundup-admin@your.tracker.email.domain.example
858 TO: chef@bork.bork.bork, richard@test.test
859 Content-Type: multipart/mixed; boundary="utf-8"
860 Subject: [issue1] Testing...
861 To: chef@bork.bork.bork, richard@test.test
862 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
863 Reply-To: Roundup issue tracker
864 <issue_tracker@your.tracker.email.domain.example>
865 MIME-Version: 1.0
866 Message-Id: <followup_dummy_id>
867 In-Reply-To: <dummy_test_message_id>
868 X-Roundup-Name: Roundup issue tracker
869 X-Roundup-Loop: hello
870 X-Roundup-Issue-Status: chatting
871 X-Roundup-Issue-Files: unnamed
872 Content-Transfer-Encoding: quoted-printable
875 --utf-8
876 MIME-Version: 1.0
877 Content-Type: text/plain; charset="iso-8859-1"
878 Content-Transfer-Encoding: quoted-printable
881 Contrary, Mary <mary@test.test> added the comment:
883 umlaut =E4=F6=FC=C4=D6=DC=DF
885 ----------
886 status: unread -> chatting
888 _______________________________________________________________________
889 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
890 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
891 _______________________________________________________________________
892 --utf-8
893 Content-Type: text/html
894 MIME-Version: 1.0
895 Content-Transfer-Encoding: base64
896 Content-Disposition: attachment;
897 filename="unnamed"
899 PGh0bWw+dW1sYXV0IMOkw7bDvMOEw5bDnMOfPC9odG1sPgo=
901 --utf-8--
902 ''')
904 def testMultipartRFC822(self):
905 self.doNewIssue()
906 self._handle_mail(self.multipart_msg_rfc822)
907 messages = self.db.issue.get('1', 'messages')
908 messages.sort()
909 msg = self.db.msg.getnode (messages[-1])
910 assert(len(msg.files) == 1)
911 name = "Fwd: Original email subject.eml"
912 for n, id in enumerate (msg.files):
913 f = self.db.file.getnode (id)
914 self.assertEqual(f.name, name)
915 self.assertEqual(msg.content, 'First part: Text')
916 self.compareMessages(self._get_mail(),
917 '''TO: chef@bork.bork.bork, richard@test.test
918 Content-Type: text/plain; charset="utf-8"
919 Subject: [issue1] Testing...
920 To: chef@bork.bork.bork, richard@test.test
921 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
922 Reply-To: Roundup issue tracker
923 <issue_tracker@your.tracker.email.domain.example>
924 MIME-Version: 1.0
925 Message-Id: <followup_dummy_id>
926 In-Reply-To: <dummy_test_message_id>
927 X-Roundup-Name: Roundup issue tracker
928 X-Roundup-Loop: hello
929 X-Roundup-Issue-Status: chatting
930 X-Roundup-Issue-Files: Fwd: Original email subject.eml
931 Content-Transfer-Encoding: quoted-printable
934 --utf-8
935 MIME-Version: 1.0
936 Content-Type: text/plain; charset="utf-8"
937 Content-Transfer-Encoding: quoted-printable
940 Contrary, Mary <mary@test.test> added the comment:
942 First part: Text
944 ----------
945 status: unread -> chatting
947 _______________________________________________________________________
948 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
949 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
950 _______________________________________________________________________
951 --utf-8
952 Content-Type: message/rfc822
953 MIME-Version: 1.0
954 Content-Disposition: attachment;
955 filename="Fwd: Original email subject.eml"
957 Message-Id: <followup_dummy_id_2>
958 In-Reply-To: <dummy_test_message_id_2>
959 MIME-Version: 1.0
960 Subject: Fwd: Original email subject
961 Date: Mon, 23 Aug 2010 08:23:33 +0200
962 Content-Type: multipart/alternative; boundary="090500050101020406060002"
964 This is a multi-part message in MIME format.
965 --090500050101020406060002
966 Content-Type: text/plain; charset=ISO-8859-15; format=flowed
967 Content-Transfer-Encoding: 7bit
969 some text in inner email
970 ========================
972 --090500050101020406060002
973 Content-Type: text/html; charset=ISO-8859-15
974 Content-Transfer-Encoding: 7bit
976 <html>
977 some text in inner email
978 ========================
979 </html>
981 --090500050101020406060002--
983 --utf-8--
984 ''')
986 def testMultipartRFC822Unpack(self):
987 self.doNewIssue()
988 self.db.config.MAILGW_UNPACK_RFC822 = True
989 self._handle_mail(self.multipart_msg_rfc822)
990 messages = self.db.issue.get('1', 'messages')
991 messages.sort()
992 msg = self.db.msg.getnode (messages[-1])
993 self.assertEqual(len(msg.files), 2)
994 t = 'some text in inner email\n========================\n'
995 content = {0 : t, 1 : '<html>\n' + t + '</html>\n'}
996 for n, id in enumerate (msg.files):
997 f = self.db.file.getnode (id)
998 self.assertEqual(f.name, 'unnamed')
999 if n in content :
1000 self.assertEqual(f.content, content [n])
1001 self.assertEqual(msg.content, 'First part: Text')
1003 def testSimpleFollowup(self):
1004 self.doNewIssue()
1005 self._handle_mail('''Content-Type: text/plain;
1006 charset="iso-8859-1"
1007 From: mary <mary@test.test>
1008 To: issue_tracker@your.tracker.email.domain.example
1009 Message-Id: <followup_dummy_id>
1010 In-Reply-To: <dummy_test_message_id>
1011 Subject: [issue1] Testing...
1013 This is a second followup
1014 ''')
1015 self.compareMessages(self._get_mail(),
1016 '''FROM: roundup-admin@your.tracker.email.domain.example
1017 TO: chef@bork.bork.bork, richard@test.test
1018 Content-Type: text/plain; charset="utf-8"
1019 Subject: [issue1] Testing...
1020 To: chef@bork.bork.bork, richard@test.test
1021 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
1022 Reply-To: Roundup issue tracker
1023 <issue_tracker@your.tracker.email.domain.example>
1024 MIME-Version: 1.0
1025 Message-Id: <followup_dummy_id>
1026 In-Reply-To: <dummy_test_message_id>
1027 X-Roundup-Name: Roundup issue tracker
1028 X-Roundup-Loop: hello
1029 X-Roundup-Issue-Status: chatting
1030 Content-Transfer-Encoding: quoted-printable
1033 Contrary, Mary <mary@test.test> added the comment:
1035 This is a second followup
1037 ----------
1038 status: unread -> chatting
1040 _______________________________________________________________________
1041 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1042 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1043 _______________________________________________________________________
1044 ''')
1046 def testFollowup(self):
1047 self.doNewIssue()
1049 self._handle_mail('''Content-Type: text/plain;
1050 charset="iso-8859-1"
1051 From: richard <richard@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... [assignedto=mary; nosy=+john]
1057 This is a followup
1058 ''')
1059 l = self.db.issue.get('1', 'nosy')
1060 l.sort()
1061 self.assertEqual(l, [self.chef_id, self.richard_id, self.mary_id,
1062 self.john_id])
1064 self.compareMessages(self._get_mail(),
1065 '''FROM: roundup-admin@your.tracker.email.domain.example
1066 TO: chef@bork.bork.bork, john@test.test, mary@test.test
1067 Content-Type: text/plain; charset="utf-8"
1068 Subject: [issue1] Testing...
1069 To: chef@bork.bork.bork, john@test.test, mary@test.test
1070 From: richard <issue_tracker@your.tracker.email.domain.example>
1071 Reply-To: Roundup issue tracker
1072 <issue_tracker@your.tracker.email.domain.example>
1073 MIME-Version: 1.0
1074 Message-Id: <followup_dummy_id>
1075 In-Reply-To: <dummy_test_message_id>
1076 X-Roundup-Name: Roundup issue tracker
1077 X-Roundup-Loop: hello
1078 X-Roundup-Issue-Status: chatting
1079 Content-Transfer-Encoding: quoted-printable
1082 richard <richard@test.test> added the comment:
1084 This is a followup
1086 ----------
1087 assignedto: -> mary
1088 nosy: +john, mary
1089 status: unread -> chatting
1091 _______________________________________________________________________
1092 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1093 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1094 _______________________________________________________________________
1095 ''')
1097 def testFollowupNoSubjectChange(self):
1098 self.db.config.MAILGW_SUBJECT_UPDATES_TITLE = 'no'
1099 self.doNewIssue()
1101 self._handle_mail('''Content-Type: text/plain;
1102 charset="iso-8859-1"
1103 From: richard <richard@test.test>
1104 To: issue_tracker@your.tracker.email.domain.example
1105 Message-Id: <followup_dummy_id>
1106 In-Reply-To: <dummy_test_message_id>
1107 Subject: [issue1] Wrzlbrmft... [assignedto=mary; nosy=+john]
1109 This is a followup
1110 ''')
1111 l = self.db.issue.get('1', 'nosy')
1112 l.sort()
1113 self.assertEqual(l, [self.chef_id, self.richard_id, self.mary_id,
1114 self.john_id])
1116 self.compareMessages(self._get_mail(),
1117 '''FROM: roundup-admin@your.tracker.email.domain.example
1118 TO: chef@bork.bork.bork, john@test.test, mary@test.test
1119 Content-Type: text/plain; charset="utf-8"
1120 Subject: [issue1] Testing...
1121 To: chef@bork.bork.bork, john@test.test, mary@test.test
1122 From: richard <issue_tracker@your.tracker.email.domain.example>
1123 Reply-To: Roundup issue tracker
1124 <issue_tracker@your.tracker.email.domain.example>
1125 MIME-Version: 1.0
1126 Message-Id: <followup_dummy_id>
1127 In-Reply-To: <dummy_test_message_id>
1128 X-Roundup-Name: Roundup issue tracker
1129 X-Roundup-Loop: hello
1130 X-Roundup-Issue-Status: chatting
1131 Content-Transfer-Encoding: quoted-printable
1134 richard <richard@test.test> added the comment:
1136 This is a followup
1138 ----------
1139 assignedto: -> mary
1140 nosy: +john, mary
1141 status: unread -> chatting
1143 _______________________________________________________________________
1144 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1145 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1146 _______________________________________________________________________
1147 ''')
1148 self.assertEqual(self.db.issue.get('1','title'), 'Testing...')
1150 def testFollowupExplicitSubjectChange(self):
1151 self.doNewIssue()
1153 self._handle_mail('''Content-Type: text/plain;
1154 charset="iso-8859-1"
1155 From: richard <richard@test.test>
1156 To: issue_tracker@your.tracker.email.domain.example
1157 Message-Id: <followup_dummy_id>
1158 In-Reply-To: <dummy_test_message_id>
1159 Subject: [issue1] Wrzlbrmft... [assignedto=mary; nosy=+john; title=new title]
1161 This is a followup
1162 ''')
1163 l = self.db.issue.get('1', 'nosy')
1164 l.sort()
1165 self.assertEqual(l, [self.chef_id, self.richard_id, self.mary_id,
1166 self.john_id])
1168 self.compareMessages(self._get_mail(),
1169 '''FROM: roundup-admin@your.tracker.email.domain.example
1170 TO: chef@bork.bork.bork, john@test.test, mary@test.test
1171 Content-Type: text/plain; charset="utf-8"
1172 Subject: [issue1] new title
1173 To: chef@bork.bork.bork, john@test.test, mary@test.test
1174 From: richard <issue_tracker@your.tracker.email.domain.example>
1175 Reply-To: Roundup issue tracker
1176 <issue_tracker@your.tracker.email.domain.example>
1177 MIME-Version: 1.0
1178 Message-Id: <followup_dummy_id>
1179 In-Reply-To: <dummy_test_message_id>
1180 X-Roundup-Name: Roundup issue tracker
1181 X-Roundup-Loop: hello
1182 X-Roundup-Issue-Status: chatting
1183 Content-Transfer-Encoding: quoted-printable
1186 richard <richard@test.test> added the comment:
1188 This is a followup
1190 ----------
1191 assignedto: -> mary
1192 nosy: +john, mary
1193 status: unread -> chatting
1194 title: Testing... -> new title
1196 _______________________________________________________________________
1197 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1198 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1199 _______________________________________________________________________
1200 ''')
1202 def testNosyGeneration(self):
1203 self.db.issue.create(title='test')
1205 # create a nosy message
1206 msg = self.db.msg.create(content='This is a test',
1207 author=self.richard_id, messageid='<dummy_test_message_id>')
1208 self.db.journaltag = 'richard'
1209 l = self.db.issue.create(title='test', messages=[msg],
1210 nosy=[self.chef_id, self.mary_id, 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: [issue2] test
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: <dummy_test_message_id>
1223 X-Roundup-Name: Roundup issue tracker
1224 X-Roundup-Loop: hello
1225 X-Roundup-Issue-Status: unread
1226 Content-Transfer-Encoding: quoted-printable
1229 New submission from richard <richard@test.test>:
1231 This is a test
1233 ----------
1234 messages: 1
1235 nosy: Chef, john, mary, richard
1236 status: unread
1237 title: test
1239 _______________________________________________________________________
1240 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1241 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue2>
1242 _______________________________________________________________________
1243 ''')
1245 def testPropertyChangeOnly(self):
1246 self.doNewIssue()
1247 oldvalues = self.db.getnode('issue', '1').copy()
1248 oldvalues['assignedto'] = None
1249 # reconstruct old behaviour: This would reuse the
1250 # database-handle from the doNewIssue above which has committed
1251 # as user "Chef". So we close and reopen the db as that user.
1252 #self.db.close() actually don't close 'cos this empties memorydb
1253 self.db = self.instance.open('Chef')
1254 self.db.issue.set('1', assignedto=self.chef_id)
1255 self.db.commit()
1256 self.db.issue.nosymessage('1', None, oldvalues)
1258 new_mail = ""
1259 for line in self._get_mail().split("\n"):
1260 if "Message-Id: " in line:
1261 continue
1262 if "Date: " in line:
1263 continue
1264 new_mail += line+"\n"
1266 self.compareMessages(new_mail, """
1267 FROM: roundup-admin@your.tracker.email.domain.example
1268 TO: chef@bork.bork.bork, richard@test.test
1269 Content-Type: text/plain; charset="utf-8"
1270 Subject: [issue1] Testing...
1271 To: chef@bork.bork.bork, richard@test.test
1272 From: "Bork, Chef" <issue_tracker@your.tracker.email.domain.example>
1273 X-Roundup-Name: Roundup issue tracker
1274 X-Roundup-Loop: hello
1275 X-Roundup-Issue-Status: unread
1276 X-Roundup-Version: 1.3.3
1277 In-Reply-To: <dummy_test_message_id>
1278 MIME-Version: 1.0
1279 Reply-To: Roundup issue tracker
1280 <issue_tracker@your.tracker.email.domain.example>
1281 Content-Transfer-Encoding: quoted-printable
1284 Change by Bork, Chef <chef@bork.bork.bork>:
1287 ----------
1288 assignedto: -> Chef
1290 _______________________________________________________________________
1291 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1292 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1293 _______________________________________________________________________
1294 """)
1297 #
1298 # FOLLOWUP TITLE MATCH
1299 #
1300 def testFollowupTitleMatch(self):
1301 self.doNewIssue()
1302 self._handle_mail('''Content-Type: text/plain;
1303 charset="iso-8859-1"
1304 From: richard <richard@test.test>
1305 To: issue_tracker@your.tracker.email.domain.example
1306 Message-Id: <followup_dummy_id>
1307 Subject: Re: Testing... [assignedto=mary; nosy=+john]
1309 This is a followup
1310 ''')
1311 self.compareMessages(self._get_mail(),
1312 '''FROM: roundup-admin@your.tracker.email.domain.example
1313 TO: chef@bork.bork.bork, john@test.test, mary@test.test
1314 Content-Type: text/plain; charset="utf-8"
1315 Subject: [issue1] Testing...
1316 To: chef@bork.bork.bork, john@test.test, mary@test.test
1317 From: richard <issue_tracker@your.tracker.email.domain.example>
1318 Reply-To: Roundup issue tracker
1319 <issue_tracker@your.tracker.email.domain.example>
1320 MIME-Version: 1.0
1321 Message-Id: <followup_dummy_id>
1322 In-Reply-To: <dummy_test_message_id>
1323 X-Roundup-Name: Roundup issue tracker
1324 X-Roundup-Loop: hello
1325 X-Roundup-Issue-Status: chatting
1326 Content-Transfer-Encoding: quoted-printable
1329 richard <richard@test.test> added the comment:
1331 This is a followup
1333 ----------
1334 assignedto: -> mary
1335 nosy: +john, mary
1336 status: unread -> chatting
1338 _______________________________________________________________________
1339 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1340 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1341 _______________________________________________________________________
1342 ''')
1344 def testFollowupTitleMatchMultiRe(self):
1345 nodeid1 = self.doNewIssue()
1346 nodeid2 = 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 ''')
1356 nodeid3 = self._handle_mail('''Content-Type: text/plain;
1357 charset="iso-8859-1"
1358 From: richard <richard@test.test>
1359 To: issue_tracker@your.tracker.email.domain.example
1360 Message-Id: <followup2_dummy_id>
1361 Subject: Ang: Re: Testing...
1363 This is a followup
1364 ''')
1365 self.assertEqual(nodeid1, nodeid2)
1366 self.assertEqual(nodeid1, nodeid3)
1368 def testFollowupTitleMatchNever(self):
1369 nodeid = self.doNewIssue()
1370 self.db.config.MAILGW_SUBJECT_CONTENT_MATCH = 'never'
1371 self.assertNotEqual(self._handle_mail('''Content-Type: text/plain;
1372 charset="iso-8859-1"
1373 From: richard <richard@test.test>
1374 To: issue_tracker@your.tracker.email.domain.example
1375 Message-Id: <followup_dummy_id>
1376 Subject: Re: Testing...
1378 This is a followup
1379 '''), nodeid)
1381 def testFollowupTitleMatchNeverInterval(self):
1382 nodeid = self.doNewIssue()
1383 # force failure of the interval
1384 time.sleep(2)
1385 self.db.config.MAILGW_SUBJECT_CONTENT_MATCH = 'creation 00:00:01'
1386 self.assertNotEqual(self._handle_mail('''Content-Type: text/plain;
1387 charset="iso-8859-1"
1388 From: richard <richard@test.test>
1389 To: issue_tracker@your.tracker.email.domain.example
1390 Message-Id: <followup_dummy_id>
1391 Subject: Re: Testing...
1393 This is a followup
1394 '''), nodeid)
1397 def testFollowupTitleMatchInterval(self):
1398 nodeid = self.doNewIssue()
1399 self.db.config.MAILGW_SUBJECT_CONTENT_MATCH = 'creation +1d'
1400 self.assertEqual(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: <followup_dummy_id>
1405 Subject: Re: Testing...
1407 This is a followup
1408 '''), nodeid)
1411 def testFollowupNosyAuthor(self):
1412 self.doNewIssue()
1413 self.db.config.ADD_AUTHOR_TO_NOSY = 'yes'
1414 self._handle_mail('''Content-Type: text/plain;
1415 charset="iso-8859-1"
1416 From: john@test.test
1417 To: issue_tracker@your.tracker.email.domain.example
1418 Message-Id: <followup_dummy_id>
1419 In-Reply-To: <dummy_test_message_id>
1420 Subject: [issue1] Testing...
1422 This is a followup
1423 ''')
1425 self.compareMessages(self._get_mail(),
1426 '''FROM: roundup-admin@your.tracker.email.domain.example
1427 TO: chef@bork.bork.bork, richard@test.test
1428 Content-Type: text/plain; charset="utf-8"
1429 Subject: [issue1] Testing...
1430 To: chef@bork.bork.bork, richard@test.test
1431 From: John Doe <issue_tracker@your.tracker.email.domain.example>
1432 Reply-To: Roundup issue tracker
1433 <issue_tracker@your.tracker.email.domain.example>
1434 MIME-Version: 1.0
1435 Message-Id: <followup_dummy_id>
1436 In-Reply-To: <dummy_test_message_id>
1437 X-Roundup-Name: Roundup issue tracker
1438 X-Roundup-Loop: hello
1439 X-Roundup-Issue-Status: chatting
1440 Content-Transfer-Encoding: quoted-printable
1443 John Doe <john@test.test> added the comment:
1445 This is a followup
1447 ----------
1448 nosy: +john
1449 status: unread -> chatting
1451 _______________________________________________________________________
1452 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1453 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1454 _______________________________________________________________________
1456 ''')
1458 def testFollowupNosyRecipients(self):
1459 self.doNewIssue()
1460 self.db.config.ADD_RECIPIENTS_TO_NOSY = 'yes'
1461 self._handle_mail('''Content-Type: text/plain;
1462 charset="iso-8859-1"
1463 From: richard@test.test
1464 To: issue_tracker@your.tracker.email.domain.example
1465 Cc: john@test.test
1466 Message-Id: <followup_dummy_id>
1467 In-Reply-To: <dummy_test_message_id>
1468 Subject: [issue1] Testing...
1470 This is a followup
1471 ''')
1472 self.compareMessages(self._get_mail(),
1473 '''FROM: roundup-admin@your.tracker.email.domain.example
1474 TO: chef@bork.bork.bork
1475 Content-Type: text/plain; charset="utf-8"
1476 Subject: [issue1] Testing...
1477 To: chef@bork.bork.bork
1478 From: richard <issue_tracker@your.tracker.email.domain.example>
1479 Reply-To: Roundup issue tracker
1480 <issue_tracker@your.tracker.email.domain.example>
1481 MIME-Version: 1.0
1482 Message-Id: <followup_dummy_id>
1483 In-Reply-To: <dummy_test_message_id>
1484 X-Roundup-Name: Roundup issue tracker
1485 X-Roundup-Loop: hello
1486 X-Roundup-Issue-Status: chatting
1487 Content-Transfer-Encoding: quoted-printable
1490 richard <richard@test.test> added the comment:
1492 This is a followup
1494 ----------
1495 nosy: +john
1496 status: unread -> chatting
1498 _______________________________________________________________________
1499 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1500 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1501 _______________________________________________________________________
1503 ''')
1505 def testFollowupNosyAuthorAndCopy(self):
1506 self.doNewIssue()
1507 self.db.config.ADD_AUTHOR_TO_NOSY = 'yes'
1508 self.db.config.MESSAGES_TO_AUTHOR = 'yes'
1509 self._handle_mail('''Content-Type: text/plain;
1510 charset="iso-8859-1"
1511 From: john@test.test
1512 To: issue_tracker@your.tracker.email.domain.example
1513 Message-Id: <followup_dummy_id>
1514 In-Reply-To: <dummy_test_message_id>
1515 Subject: [issue1] Testing...
1517 This is a followup
1518 ''')
1519 self.compareMessages(self._get_mail(),
1520 '''FROM: roundup-admin@your.tracker.email.domain.example
1521 TO: chef@bork.bork.bork, john@test.test, richard@test.test
1522 Content-Type: text/plain; charset="utf-8"
1523 Subject: [issue1] Testing...
1524 To: chef@bork.bork.bork, john@test.test, richard@test.test
1525 From: John Doe <issue_tracker@your.tracker.email.domain.example>
1526 Reply-To: Roundup issue tracker
1527 <issue_tracker@your.tracker.email.domain.example>
1528 MIME-Version: 1.0
1529 Message-Id: <followup_dummy_id>
1530 In-Reply-To: <dummy_test_message_id>
1531 X-Roundup-Name: Roundup issue tracker
1532 X-Roundup-Loop: hello
1533 X-Roundup-Issue-Status: chatting
1534 Content-Transfer-Encoding: quoted-printable
1537 John Doe <john@test.test> added the comment:
1539 This is a followup
1541 ----------
1542 nosy: +john
1543 status: unread -> chatting
1545 _______________________________________________________________________
1546 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1547 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1548 _______________________________________________________________________
1550 ''')
1552 def testFollowupNoNosyAuthor(self):
1553 self.doNewIssue()
1554 self.instance.config.ADD_AUTHOR_TO_NOSY = 'no'
1555 self._handle_mail('''Content-Type: text/plain;
1556 charset="iso-8859-1"
1557 From: john@test.test
1558 To: issue_tracker@your.tracker.email.domain.example
1559 Message-Id: <followup_dummy_id>
1560 In-Reply-To: <dummy_test_message_id>
1561 Subject: [issue1] Testing...
1563 This is a followup
1564 ''')
1565 self.compareMessages(self._get_mail(),
1566 '''FROM: roundup-admin@your.tracker.email.domain.example
1567 TO: chef@bork.bork.bork, richard@test.test
1568 Content-Type: text/plain; charset="utf-8"
1569 Subject: [issue1] Testing...
1570 To: chef@bork.bork.bork, richard@test.test
1571 From: John Doe <issue_tracker@your.tracker.email.domain.example>
1572 Reply-To: Roundup issue tracker
1573 <issue_tracker@your.tracker.email.domain.example>
1574 MIME-Version: 1.0
1575 Message-Id: <followup_dummy_id>
1576 In-Reply-To: <dummy_test_message_id>
1577 X-Roundup-Name: Roundup issue tracker
1578 X-Roundup-Loop: hello
1579 X-Roundup-Issue-Status: chatting
1580 Content-Transfer-Encoding: quoted-printable
1583 John Doe <john@test.test> added the comment:
1585 This is a followup
1587 ----------
1588 status: unread -> chatting
1590 _______________________________________________________________________
1591 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1592 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1593 _______________________________________________________________________
1595 ''')
1597 def testFollowupNoNosyRecipients(self):
1598 self.doNewIssue()
1599 self.instance.config.ADD_RECIPIENTS_TO_NOSY = 'no'
1600 self._handle_mail('''Content-Type: text/plain;
1601 charset="iso-8859-1"
1602 From: richard@test.test
1603 To: issue_tracker@your.tracker.email.domain.example
1604 Cc: john@test.test
1605 Message-Id: <followup_dummy_id>
1606 In-Reply-To: <dummy_test_message_id>
1607 Subject: [issue1] Testing...
1609 This is a followup
1610 ''')
1611 self.compareMessages(self._get_mail(),
1612 '''FROM: roundup-admin@your.tracker.email.domain.example
1613 TO: chef@bork.bork.bork
1614 Content-Type: text/plain; charset="utf-8"
1615 Subject: [issue1] Testing...
1616 To: chef@bork.bork.bork
1617 From: richard <issue_tracker@your.tracker.email.domain.example>
1618 Reply-To: Roundup issue tracker
1619 <issue_tracker@your.tracker.email.domain.example>
1620 MIME-Version: 1.0
1621 Message-Id: <followup_dummy_id>
1622 In-Reply-To: <dummy_test_message_id>
1623 X-Roundup-Name: Roundup issue tracker
1624 X-Roundup-Loop: hello
1625 X-Roundup-Issue-Status: chatting
1626 Content-Transfer-Encoding: quoted-printable
1629 richard <richard@test.test> added the comment:
1631 This is a followup
1633 ----------
1634 status: unread -> chatting
1636 _______________________________________________________________________
1637 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1638 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1639 _______________________________________________________________________
1641 ''')
1643 def testFollowupEmptyMessage(self):
1644 self.doNewIssue()
1646 self._handle_mail('''Content-Type: text/plain;
1647 charset="iso-8859-1"
1648 From: richard <richard@test.test>
1649 To: issue_tracker@your.tracker.email.domain.example
1650 Message-Id: <followup_dummy_id>
1651 In-Reply-To: <dummy_test_message_id>
1652 Subject: [issue1] Testing... [assignedto=mary; nosy=+john]
1654 ''')
1655 l = self.db.issue.get('1', 'nosy')
1656 l.sort()
1657 self.assertEqual(l, [self.chef_id, self.richard_id, self.mary_id,
1658 self.john_id])
1660 # should be no file created (ie. no message)
1661 assert not os.path.exists(SENDMAILDEBUG)
1663 def testFollowupEmptyMessageNoSubject(self):
1664 self.doNewIssue()
1666 self._handle_mail('''Content-Type: text/plain;
1667 charset="iso-8859-1"
1668 From: richard <richard@test.test>
1669 To: issue_tracker@your.tracker.email.domain.example
1670 Message-Id: <followup_dummy_id>
1671 In-Reply-To: <dummy_test_message_id>
1672 Subject: [issue1] [assignedto=mary; nosy=+john]
1674 ''')
1675 l = self.db.issue.get('1', 'nosy')
1676 l.sort()
1677 self.assertEqual(l, [self.chef_id, self.richard_id, self.mary_id,
1678 self.john_id])
1680 # should be no file created (ie. no message)
1681 assert not os.path.exists(SENDMAILDEBUG)
1683 def testNosyRemove(self):
1684 self.doNewIssue()
1686 self._handle_mail('''Content-Type: text/plain;
1687 charset="iso-8859-1"
1688 From: richard <richard@test.test>
1689 To: issue_tracker@your.tracker.email.domain.example
1690 Message-Id: <followup_dummy_id>
1691 In-Reply-To: <dummy_test_message_id>
1692 Subject: [issue1] Testing... [nosy=-richard]
1694 ''')
1695 l = self.db.issue.get('1', 'nosy')
1696 l.sort()
1697 self.assertEqual(l, [self.chef_id])
1699 # NO NOSY MESSAGE SHOULD BE SENT!
1700 assert not os.path.exists(SENDMAILDEBUG)
1702 def testNewUserAuthor(self):
1703 self.db.commit()
1704 l = self.db.user.list()
1705 l.sort()
1706 message = '''Content-Type: text/plain;
1707 charset="iso-8859-1"
1708 From: fubar <fubar@bork.bork.bork>
1709 To: issue_tracker@your.tracker.email.domain.example
1710 Message-Id: <dummy_test_message_id>
1711 Subject: [issue] Testing...
1713 This is a test submission of a new issue.
1714 '''
1715 self.db.security.role['anonymous'].permissions=[]
1716 anonid = self.db.user.lookup('anonymous')
1717 self.db.user.set(anonid, roles='Anonymous')
1718 try:
1719 self._handle_mail(message)
1720 except Unauthorized, value:
1721 body_diff = self.compareMessages(str(value), """
1722 You are not a registered user.
1724 Unknown address: fubar@bork.bork.bork
1725 """)
1726 assert not body_diff, body_diff
1727 else:
1728 raise AssertionError, "Unathorized not raised when handling mail"
1730 # Add Web Access role to anonymous, and try again to make sure
1731 # we get a "please register at:" message this time.
1732 p = [
1733 self.db.security.getPermission('Register', 'user'),
1734 self.db.security.getPermission('Web Access', None),
1735 ]
1736 self.db.security.role['anonymous'].permissions=p
1737 try:
1738 self._handle_mail(message)
1739 except Unauthorized, value:
1740 body_diff = self.compareMessages(str(value), """
1741 You are not a registered user. Please register at:
1743 http://tracker.example/cgi-bin/roundup.cgi/bugs/user?template=register
1745 ...before sending mail to the tracker.
1747 Unknown address: fubar@bork.bork.bork
1748 """)
1749 assert not body_diff, body_diff
1750 else:
1751 raise AssertionError, "Unathorized not raised when handling mail"
1753 # Make sure list of users is the same as before.
1754 m = self.db.user.list()
1755 m.sort()
1756 self.assertEqual(l, m)
1758 # now with the permission
1759 p = [
1760 self.db.security.getPermission('Register', 'user'),
1761 self.db.security.getPermission('Email Access', None),
1762 ]
1763 self.db.security.role['anonymous'].permissions=p
1764 self._handle_mail(message)
1765 m = self.db.user.list()
1766 m.sort()
1767 self.assertNotEqual(l, m)
1769 def testNewUserAuthorEncodedName(self):
1770 l = set(self.db.user.list())
1771 # From: name has Euro symbol in it
1772 message = '''Content-Type: text/plain;
1773 charset="iso-8859-1"
1774 From: =?utf8?b?SOKCrGxsbw==?= <fubar@bork.bork.bork>
1775 To: issue_tracker@your.tracker.email.domain.example
1776 Message-Id: <dummy_test_message_id>
1777 Subject: [issue] Testing...
1779 This is a test submission of a new issue.
1780 '''
1781 p = [
1782 self.db.security.getPermission('Register', 'user'),
1783 self.db.security.getPermission('Email Access', None),
1784 self.db.security.getPermission('Create', 'issue'),
1785 self.db.security.getPermission('Create', 'msg'),
1786 ]
1787 self.db.security.role['anonymous'].permissions = p
1788 self._handle_mail(message)
1789 m = set(self.db.user.list())
1790 new = list(m - l)[0]
1791 name = self.db.user.get(new, 'realname')
1792 self.assertEquals(name, 'H€llo')
1794 def testUnknownUser(self):
1795 l = set(self.db.user.list())
1796 message = '''Content-Type: text/plain;
1797 charset="iso-8859-1"
1798 From: Nonexisting User <nonexisting@bork.bork.bork>
1799 To: issue_tracker@your.tracker.email.domain.example
1800 Message-Id: <dummy_test_message_id>
1801 Subject: [issue] Testing nonexisting user...
1803 This is a test submission of a new issue.
1804 '''
1805 handler = self._create_mailgw(message)
1806 # we want a bounce message:
1807 handler.trapExceptions = 1
1808 ret = handler.main(StringIO(message))
1809 self.compareMessages(self._get_mail(),
1810 '''FROM: Roundup issue tracker <roundup-admin@your.tracker.email.domain.example>
1811 TO: nonexisting@bork.bork.bork
1812 From nobody Tue Jul 14 12:04:11 2009
1813 Content-Type: multipart/mixed; boundary="===============0639262320=="
1814 MIME-Version: 1.0
1815 Subject: Failed issue tracker submission
1816 To: nonexisting@bork.bork.bork
1817 From: Roundup issue tracker <roundup-admin@your.tracker.email.domain.example>
1818 Date: Tue, 14 Jul 2009 12:04:11 +0000
1819 Precedence: bulk
1820 X-Roundup-Name: Roundup issue tracker
1821 X-Roundup-Loop: hello
1822 X-Roundup-Version: 1.4.8
1823 MIME-Version: 1.0
1825 --===============0639262320==
1826 Content-Type: text/plain; charset="us-ascii"
1827 MIME-Version: 1.0
1828 Content-Transfer-Encoding: 7bit
1832 You are not a registered user. Please register at:
1834 http://tracker.example/cgi-bin/roundup.cgi/bugs/user?template=register
1836 ...before sending mail to the tracker.
1838 Unknown address: nonexisting@bork.bork.bork
1840 --===============0639262320==
1841 Content-Type: text/plain; charset="us-ascii"
1842 MIME-Version: 1.0
1843 Content-Transfer-Encoding: 7bit
1845 Content-Type: text/plain;
1846 charset="iso-8859-1"
1847 From: Nonexisting User <nonexisting@bork.bork.bork>
1848 To: issue_tracker@your.tracker.email.domain.example
1849 Message-Id: <dummy_test_message_id>
1850 Subject: [issue] Testing nonexisting user...
1852 This is a test submission of a new issue.
1854 --===============0639262320==--
1855 ''')
1857 def testEnc01(self):
1858 self.db.user.set(self.mary_id,
1859 realname='\xe4\xf6\xfc\xc4\xd6\xdc\xdf, Mary'.decode
1860 ('latin-1').encode('utf-8'))
1861 self.doNewIssue()
1862 self._handle_mail('''Content-Type: text/plain;
1863 charset="iso-8859-1"
1864 From: mary <mary@test.test>
1865 To: issue_tracker@your.tracker.email.domain.example
1866 Message-Id: <followup_dummy_id>
1867 In-Reply-To: <dummy_test_message_id>
1868 Subject: [issue1] Testing...
1869 Content-Type: text/plain;
1870 charset="iso-8859-1"
1871 Content-Transfer-Encoding: quoted-printable
1873 A message with encoding (encoded oe =F6)
1875 ''')
1876 self.compareMessages(self._get_mail(),
1877 '''FROM: roundup-admin@your.tracker.email.domain.example
1878 TO: chef@bork.bork.bork, richard@test.test
1879 Content-Type: text/plain; charset="utf-8"
1880 Subject: [issue1] Testing...
1881 To: chef@bork.bork.bork, richard@test.test
1882 From: =?utf-8?b?w6TDtsO8w4TDlsOcw58sIE1hcnk=?=
1883 <issue_tracker@your.tracker.email.domain.example>
1884 Reply-To: Roundup issue tracker
1885 <issue_tracker@your.tracker.email.domain.example>
1886 MIME-Version: 1.0
1887 Message-Id: <followup_dummy_id>
1888 In-Reply-To: <dummy_test_message_id>
1889 X-Roundup-Name: Roundup issue tracker
1890 X-Roundup-Loop: hello
1891 X-Roundup-Issue-Status: chatting
1892 Content-Transfer-Encoding: quoted-printable
1895 =C3=A4=C3=B6=C3=BC=C3=84=C3=96=C3=9C=C3=9F, Mary <mary@test.test> added the=
1896 comment:
1898 A message with encoding (encoded oe =C3=B6)
1900 ----------
1901 status: unread -> chatting
1903 _______________________________________________________________________
1904 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1905 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1906 _______________________________________________________________________
1907 ''')
1909 def testEncNonUTF8(self):
1910 self.doNewIssue()
1911 self.instance.config.EMAIL_CHARSET = 'iso-8859-1'
1912 self._handle_mail('''Content-Type: text/plain;
1913 charset="iso-8859-1"
1914 From: mary <mary@test.test>
1915 To: issue_tracker@your.tracker.email.domain.example
1916 Message-Id: <followup_dummy_id>
1917 In-Reply-To: <dummy_test_message_id>
1918 Subject: [issue1] Testing...
1919 Content-Type: text/plain;
1920 charset="iso-8859-1"
1921 Content-Transfer-Encoding: quoted-printable
1923 A message with encoding (encoded oe =F6)
1925 ''')
1926 self.compareMessages(self._get_mail(),
1927 '''FROM: roundup-admin@your.tracker.email.domain.example
1928 TO: chef@bork.bork.bork, richard@test.test
1929 Content-Type: text/plain; charset="iso-8859-1"
1930 Subject: [issue1] Testing...
1931 To: chef@bork.bork.bork, richard@test.test
1932 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
1933 Reply-To: Roundup issue tracker
1934 <issue_tracker@your.tracker.email.domain.example>
1935 MIME-Version: 1.0
1936 Message-Id: <followup_dummy_id>
1937 In-Reply-To: <dummy_test_message_id>
1938 X-Roundup-Name: Roundup issue tracker
1939 X-Roundup-Loop: hello
1940 X-Roundup-Issue-Status: chatting
1941 Content-Transfer-Encoding: quoted-printable
1944 Contrary, Mary <mary@test.test> added the comment:
1946 A message with encoding (encoded oe =F6)
1948 ----------
1949 status: unread -> chatting
1951 _______________________________________________________________________
1952 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1953 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1954 _______________________________________________________________________
1955 ''')
1958 def testMultipartEnc01(self):
1959 self.doNewIssue()
1960 self._handle_mail('''Content-Type: text/plain;
1961 charset="iso-8859-1"
1962 From: mary <mary@test.test>
1963 To: issue_tracker@your.tracker.email.domain.example
1964 Message-Id: <followup_dummy_id>
1965 In-Reply-To: <dummy_test_message_id>
1966 Subject: [issue1] Testing...
1967 Content-Type: multipart/mixed;
1968 boundary="----_=_NextPart_000_01"
1970 This message is in MIME format. Since your mail reader does not understand
1971 this format, some or all of this message may not be legible.
1973 ------_=_NextPart_000_01
1974 Content-Type: text/plain;
1975 charset="iso-8859-1"
1976 Content-Transfer-Encoding: quoted-printable
1978 A message with first part encoded (encoded oe =F6)
1980 ''')
1981 self.compareMessages(self._get_mail(),
1982 '''FROM: roundup-admin@your.tracker.email.domain.example
1983 TO: chef@bork.bork.bork, richard@test.test
1984 Content-Type: text/plain; charset="utf-8"
1985 Subject: [issue1] Testing...
1986 To: chef@bork.bork.bork, richard@test.test
1987 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
1988 Reply-To: Roundup issue tracker
1989 <issue_tracker@your.tracker.email.domain.example>
1990 MIME-Version: 1.0
1991 Message-Id: <followup_dummy_id>
1992 In-Reply-To: <dummy_test_message_id>
1993 X-Roundup-Name: Roundup issue tracker
1994 X-Roundup-Loop: hello
1995 X-Roundup-Issue-Status: chatting
1996 Content-Transfer-Encoding: quoted-printable
1999 Contrary, Mary <mary@test.test> added the comment:
2001 A message with first part encoded (encoded oe =C3=B6)
2003 ----------
2004 status: unread -> chatting
2006 _______________________________________________________________________
2007 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
2008 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
2009 _______________________________________________________________________
2010 ''')
2012 def testContentDisposition(self):
2013 self.doNewIssue()
2014 self._handle_mail('''Content-Type: text/plain;
2015 charset="iso-8859-1"
2016 From: mary <mary@test.test>
2017 To: issue_tracker@your.tracker.email.domain.example
2018 Message-Id: <followup_dummy_id>
2019 In-Reply-To: <dummy_test_message_id>
2020 Subject: [issue1] Testing...
2021 Content-Type: multipart/mixed; boundary="bCsyhTFzCvuiizWE"
2022 Content-Disposition: inline
2025 --bCsyhTFzCvuiizWE
2026 Content-Type: text/plain; charset=us-ascii
2027 Content-Disposition: inline
2029 test attachment binary
2031 --bCsyhTFzCvuiizWE
2032 Content-Type: application/octet-stream
2033 Content-Disposition: attachment; filename="main.dvi"
2034 Content-Transfer-Encoding: base64
2036 SnVzdCBhIHRlc3QgAQo=
2038 --bCsyhTFzCvuiizWE--
2039 ''')
2040 messages = self.db.issue.get('1', 'messages')
2041 messages.sort()
2042 file = self.db.file.getnode (self.db.msg.get(messages[-1], 'files')[0])
2043 self.assertEqual(file.name, 'main.dvi')
2044 self.assertEqual(file.content, 'Just a test \001\n')
2046 def testFollowupStupidQuoting(self):
2047 self.doNewIssue()
2049 self._handle_mail('''Content-Type: text/plain;
2050 charset="iso-8859-1"
2051 From: richard <richard@test.test>
2052 To: issue_tracker@your.tracker.email.domain.example
2053 Message-Id: <followup_dummy_id>
2054 In-Reply-To: <dummy_test_message_id>
2055 Subject: Re: "[issue1] Testing... "
2057 This is a followup
2058 ''')
2059 self.compareMessages(self._get_mail(),
2060 '''FROM: roundup-admin@your.tracker.email.domain.example
2061 TO: chef@bork.bork.bork
2062 Content-Type: text/plain; charset="utf-8"
2063 Subject: [issue1] Testing...
2064 To: chef@bork.bork.bork
2065 From: richard <issue_tracker@your.tracker.email.domain.example>
2066 Reply-To: Roundup issue tracker
2067 <issue_tracker@your.tracker.email.domain.example>
2068 MIME-Version: 1.0
2069 Message-Id: <followup_dummy_id>
2070 In-Reply-To: <dummy_test_message_id>
2071 X-Roundup-Name: Roundup issue tracker
2072 X-Roundup-Loop: hello
2073 X-Roundup-Issue-Status: chatting
2074 Content-Transfer-Encoding: quoted-printable
2077 richard <richard@test.test> added the comment:
2079 This is a followup
2081 ----------
2082 status: unread -> chatting
2084 _______________________________________________________________________
2085 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
2086 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
2087 _______________________________________________________________________
2088 ''')
2090 def testEmailQuoting(self):
2091 self.instance.config.EMAIL_KEEP_QUOTED_TEXT = 'no'
2092 self.innerTestQuoting('''This is a followup
2093 ''')
2095 def testEmailQuotingRemove(self):
2096 self.instance.config.EMAIL_KEEP_QUOTED_TEXT = 'yes'
2097 self.innerTestQuoting('''Blah blah wrote:
2098 > Blah bklaskdfj sdf asdf jlaskdf skj sdkfjl asdf
2099 > skdjlkjsdfalsdkfjasdlfkj dlfksdfalksd fj
2100 >
2102 This is a followup
2103 ''')
2105 def innerTestQuoting(self, expect):
2106 nodeid = self.doNewIssue()
2108 messages = self.db.issue.get(nodeid, 'messages')
2110 self._handle_mail('''Content-Type: text/plain;
2111 charset="iso-8859-1"
2112 From: richard <richard@test.test>
2113 To: issue_tracker@your.tracker.email.domain.example
2114 Message-Id: <followup_dummy_id>
2115 In-Reply-To: <dummy_test_message_id>
2116 Subject: Re: [issue1] Testing...
2118 Blah blah wrote:
2119 > Blah bklaskdfj sdf asdf jlaskdf skj sdkfjl asdf
2120 > skdjlkjsdfalsdkfjasdlfkj dlfksdfalksd fj
2121 >
2123 This is a followup
2124 ''')
2125 # figure the new message id
2126 newmessages = self.db.issue.get(nodeid, 'messages')
2127 for msg in messages:
2128 newmessages.remove(msg)
2129 messageid = newmessages[0]
2131 self.compareMessages(self.db.msg.get(messageid, 'content'), expect)
2133 def testUserLookup(self):
2134 i = self.db.user.create(username='user1', address='user1@foo.com')
2135 self.assertEqual(uidFromAddress(self.db, ('', 'user1@foo.com'), 0), i)
2136 self.assertEqual(uidFromAddress(self.db, ('', 'USER1@foo.com'), 0), i)
2137 i = self.db.user.create(username='user2', address='USER2@foo.com')
2138 self.assertEqual(uidFromAddress(self.db, ('', 'USER2@foo.com'), 0), i)
2139 self.assertEqual(uidFromAddress(self.db, ('', 'user2@foo.com'), 0), i)
2141 def testUserAlternateLookup(self):
2142 i = self.db.user.create(username='user1', address='user1@foo.com',
2143 alternate_addresses='user1@bar.com')
2144 self.assertEqual(uidFromAddress(self.db, ('', 'user1@bar.com'), 0), i)
2145 self.assertEqual(uidFromAddress(self.db, ('', 'USER1@bar.com'), 0), i)
2147 def testUserCreate(self):
2148 i = uidFromAddress(self.db, ('', 'user@foo.com'), 1)
2149 self.assertNotEqual(uidFromAddress(self.db, ('', 'user@bar.com'), 1), i)
2151 def testRFC2822(self):
2152 ascii_header = "[issue243] This is a \"test\" - with 'quotation' marks"
2153 unicode_header = '[issue244] \xd0\xb0\xd0\xbd\xd0\xb4\xd1\x80\xd0\xb5\xd0\xb9'
2154 unicode_encoded = '=?utf-8?q?[issue244]_=D0=B0=D0=BD=D0=B4=D1=80=D0=B5=D0=B9?='
2155 self.assertEqual(rfc2822.encode_header(ascii_header), ascii_header)
2156 self.assertEqual(rfc2822.encode_header(unicode_header), unicode_encoded)
2158 def testRegistrationConfirmation(self):
2159 otk = "Aj4euk4LZSAdwePohj90SME5SpopLETL"
2160 self.db.getOTKManager().set(otk, username='johannes')
2161 self._handle_mail('''Content-Type: text/plain;
2162 charset="iso-8859-1"
2163 From: Chef <chef@bork.bork.bork>
2164 To: issue_tracker@your.tracker.email.domain.example
2165 Cc: richard@test.test
2166 Message-Id: <dummy_test_message_id>
2167 Subject: Re: Complete your registration to Roundup issue tracker
2168 -- key %s
2170 This is a test confirmation of registration.
2171 ''' % otk)
2172 self.db.user.lookup('johannes')
2174 def testFollowupOnNonIssue(self):
2175 self.db.keyword.create(name='Foo')
2176 self._handle_mail('''Content-Type: text/plain;
2177 charset="iso-8859-1"
2178 From: richard <richard@test.test>
2179 To: issue_tracker@your.tracker.email.domain.example
2180 Message-Id: <followup_dummy_id>
2181 In-Reply-To: <dummy_test_message_id>
2182 Subject: [keyword1] Testing... [name=Bar]
2184 ''')
2185 self.assertEqual(self.db.keyword.get('1', 'name'), 'Bar')
2187 def testResentFrom(self):
2188 nodeid = self._handle_mail('''Content-Type: text/plain;
2189 charset="iso-8859-1"
2190 From: Chef <chef@bork.bork.bork>
2191 Resent-From: mary <mary@test.test>
2192 To: issue_tracker@your.tracker.email.domain.example
2193 Cc: richard@test.test
2194 Message-Id: <dummy_test_message_id>
2195 Subject: [issue] Testing...
2197 This is a test submission of a new issue.
2198 ''')
2199 assert not os.path.exists(SENDMAILDEBUG)
2200 l = self.db.issue.get(nodeid, 'nosy')
2201 l.sort()
2202 self.assertEqual(l, [self.richard_id, self.mary_id])
2203 return nodeid
2205 def testDejaVu(self):
2206 self.assertRaises(IgnoreLoop, self._handle_mail,
2207 '''Content-Type: text/plain;
2208 charset="iso-8859-1"
2209 From: Chef <chef@bork.bork.bork>
2210 X-Roundup-Loop: hello
2211 To: issue_tracker@your.tracker.email.domain.example
2212 Cc: richard@test.test
2213 Message-Id: <dummy_test_message_id>
2214 Subject: Re: [issue] Testing...
2216 Hi, I've been mis-configured to loop messages back to myself.
2217 ''')
2219 def testItsBulkStupid(self):
2220 self.assertRaises(IgnoreBulk, self._handle_mail,
2221 '''Content-Type: text/plain;
2222 charset="iso-8859-1"
2223 From: Chef <chef@bork.bork.bork>
2224 Precedence: bulk
2225 To: issue_tracker@your.tracker.email.domain.example
2226 Cc: richard@test.test
2227 Message-Id: <dummy_test_message_id>
2228 Subject: Re: [issue] Testing...
2230 Hi, I'm on holidays, and this is a dumb auto-responder.
2231 ''')
2233 def testAutoReplyEmailsAreIgnored(self):
2234 self.assertRaises(IgnoreBulk, self._handle_mail,
2235 '''Content-Type: text/plain;
2236 charset="iso-8859-1"
2237 From: Chef <chef@bork.bork.bork>
2238 To: issue_tracker@your.tracker.email.domain.example
2239 Cc: richard@test.test
2240 Message-Id: <dummy_test_message_id>
2241 Subject: Re: [issue] Out of office AutoReply: Back next week
2243 Hi, I am back in the office next week
2244 ''')
2246 def testNoSubject(self):
2247 self.assertRaises(MailUsageError, self._handle_mail,
2248 '''Content-Type: text/plain;
2249 charset="iso-8859-1"
2250 From: Chef <chef@bork.bork.bork>
2251 To: issue_tracker@your.tracker.email.domain.example
2252 Cc: richard@test.test
2253 Reply-To: chef@bork.bork.bork
2254 Message-Id: <dummy_test_message_id>
2256 ''')
2258 #
2259 # TEST FOR INVALID DESIGNATOR HANDLING
2260 #
2261 def testInvalidDesignator(self):
2262 self.assertRaises(MailUsageError, self._handle_mail,
2263 '''Content-Type: text/plain;
2264 charset="iso-8859-1"
2265 From: Chef <chef@bork.bork.bork>
2266 To: issue_tracker@your.tracker.email.domain.example
2267 Subject: [frobulated] testing
2268 Cc: richard@test.test
2269 Reply-To: chef@bork.bork.bork
2270 Message-Id: <dummy_test_message_id>
2272 ''')
2273 self.assertRaises(MailUsageError, self._handle_mail,
2274 '''Content-Type: text/plain;
2275 charset="iso-8859-1"
2276 From: Chef <chef@bork.bork.bork>
2277 To: issue_tracker@your.tracker.email.domain.example
2278 Subject: [issue12345] testing
2279 Cc: richard@test.test
2280 Reply-To: chef@bork.bork.bork
2281 Message-Id: <dummy_test_message_id>
2283 ''')
2285 def testInvalidClassLoose(self):
2286 self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'loose'
2287 nodeid = self._handle_mail('''Content-Type: text/plain;
2288 charset="iso-8859-1"
2289 From: Chef <chef@bork.bork.bork>
2290 To: issue_tracker@your.tracker.email.domain.example
2291 Subject: [frobulated] testing
2292 Cc: richard@test.test
2293 Reply-To: chef@bork.bork.bork
2294 Message-Id: <dummy_test_message_id>
2296 ''')
2297 assert not os.path.exists(SENDMAILDEBUG)
2298 self.assertEqual(self.db.issue.get(nodeid, 'title'),
2299 '[frobulated] testing')
2301 def testInvalidClassLooseReply(self):
2302 self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'loose'
2303 nodeid = self._handle_mail('''Content-Type: text/plain;
2304 charset="iso-8859-1"
2305 From: Chef <chef@bork.bork.bork>
2306 To: issue_tracker@your.tracker.email.domain.example
2307 Subject: Re: [frobulated] testing
2308 Cc: richard@test.test
2309 Reply-To: chef@bork.bork.bork
2310 Message-Id: <dummy_test_message_id>
2312 ''')
2313 assert not os.path.exists(SENDMAILDEBUG)
2314 self.assertEqual(self.db.issue.get(nodeid, 'title'),
2315 '[frobulated] testing')
2317 def testInvalidClassLoose(self):
2318 self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'loose'
2319 nodeid = self._handle_mail('''Content-Type: text/plain;
2320 charset="iso-8859-1"
2321 From: Chef <chef@bork.bork.bork>
2322 To: issue_tracker@your.tracker.email.domain.example
2323 Subject: [issue1234] testing
2324 Cc: richard@test.test
2325 Reply-To: chef@bork.bork.bork
2326 Message-Id: <dummy_test_message_id>
2328 ''')
2329 assert not os.path.exists(SENDMAILDEBUG)
2330 self.assertEqual(self.db.issue.get(nodeid, 'title'),
2331 '[issue1234] testing')
2333 def testClassLooseOK(self):
2334 self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'loose'
2335 self.db.keyword.create(name='Foo')
2336 nodeid = self._handle_mail('''Content-Type: text/plain;
2337 charset="iso-8859-1"
2338 From: Chef <chef@bork.bork.bork>
2339 To: issue_tracker@your.tracker.email.domain.example
2340 Subject: [keyword1] Testing... [name=Bar]
2341 Cc: richard@test.test
2342 Reply-To: chef@bork.bork.bork
2343 Message-Id: <dummy_test_message_id>
2345 ''')
2346 assert not os.path.exists(SENDMAILDEBUG)
2347 self.assertEqual(self.db.keyword.get('1', 'name'), 'Bar')
2349 def testClassStrictInvalid(self):
2350 self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'strict'
2351 self.instance.config.MAILGW_DEFAULT_CLASS = ''
2353 message = '''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: Testing...
2358 Cc: richard@test.test
2359 Reply-To: chef@bork.bork.bork
2360 Message-Id: <dummy_test_message_id>
2362 '''
2363 self.assertRaises(MailUsageError, self._handle_mail, message)
2365 def testClassStrictValid(self):
2366 self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'strict'
2367 self.instance.config.MAILGW_DEFAULT_CLASS = ''
2369 nodeid = self._handle_mail('''Content-Type: text/plain;
2370 charset="iso-8859-1"
2371 From: Chef <chef@bork.bork.bork>
2372 To: issue_tracker@your.tracker.email.domain.example
2373 Subject: [issue] Testing...
2374 Cc: richard@test.test
2375 Reply-To: chef@bork.bork.bork
2376 Message-Id: <dummy_test_message_id>
2378 ''')
2380 assert not os.path.exists(SENDMAILDEBUG)
2381 self.assertEqual(self.db.issue.get(nodeid, 'title'), 'Testing...')
2383 #
2384 # TEST FOR INVALID COMMANDS HANDLING
2385 #
2386 def testInvalidCommands(self):
2387 self.assertRaises(MailUsageError, self._handle_mail,
2388 '''Content-Type: text/plain;
2389 charset="iso-8859-1"
2390 From: Chef <chef@bork.bork.bork>
2391 To: issue_tracker@your.tracker.email.domain.example
2392 Subject: testing [frobulated]
2393 Cc: richard@test.test
2394 Reply-To: chef@bork.bork.bork
2395 Message-Id: <dummy_test_message_id>
2397 ''')
2399 def testInvalidCommandPassthrough(self):
2400 self.instance.config.MAILGW_SUBJECT_SUFFIX_PARSING = 'none'
2401 nodeid = self._handle_mail('''Content-Type: text/plain;
2402 charset="iso-8859-1"
2403 From: Chef <chef@bork.bork.bork>
2404 To: issue_tracker@your.tracker.email.domain.example
2405 Subject: testing [frobulated]
2406 Cc: richard@test.test
2407 Reply-To: chef@bork.bork.bork
2408 Message-Id: <dummy_test_message_id>
2410 ''')
2411 assert not os.path.exists(SENDMAILDEBUG)
2412 self.assertEqual(self.db.issue.get(nodeid, 'title'),
2413 'testing [frobulated]')
2415 def testInvalidCommandPassthroughLoose(self):
2416 self.instance.config.MAILGW_SUBJECT_SUFFIX_PARSING = 'loose'
2417 nodeid = self._handle_mail('''Content-Type: text/plain;
2418 charset="iso-8859-1"
2419 From: Chef <chef@bork.bork.bork>
2420 To: issue_tracker@your.tracker.email.domain.example
2421 Subject: testing [frobulated]
2422 Cc: richard@test.test
2423 Reply-To: chef@bork.bork.bork
2424 Message-Id: <dummy_test_message_id>
2426 ''')
2427 assert not os.path.exists(SENDMAILDEBUG)
2428 self.assertEqual(self.db.issue.get(nodeid, 'title'),
2429 'testing [frobulated]')
2431 def testInvalidCommandPassthroughLooseOK(self):
2432 self.instance.config.MAILGW_SUBJECT_SUFFIX_PARSING = 'loose'
2433 nodeid = self._handle_mail('''Content-Type: text/plain;
2434 charset="iso-8859-1"
2435 From: Chef <chef@bork.bork.bork>
2436 To: issue_tracker@your.tracker.email.domain.example
2437 Subject: testing [assignedto=mary]
2438 Cc: richard@test.test
2439 Reply-To: chef@bork.bork.bork
2440 Message-Id: <dummy_test_message_id>
2442 ''')
2443 assert not os.path.exists(SENDMAILDEBUG)
2444 self.assertEqual(self.db.issue.get(nodeid, 'title'), 'testing')
2445 self.assertEqual(self.db.issue.get(nodeid, 'assignedto'), self.mary_id)
2447 def testCommandDelimiters(self):
2448 self.instance.config.MAILGW_SUBJECT_SUFFIX_DELIMITERS = '{}'
2449 nodeid = self._handle_mail('''Content-Type: text/plain;
2450 charset="iso-8859-1"
2451 From: Chef <chef@bork.bork.bork>
2452 To: issue_tracker@your.tracker.email.domain.example
2453 Subject: testing {assignedto=mary}
2454 Cc: richard@test.test
2455 Reply-To: chef@bork.bork.bork
2456 Message-Id: <dummy_test_message_id>
2458 ''')
2459 assert not os.path.exists(SENDMAILDEBUG)
2460 self.assertEqual(self.db.issue.get(nodeid, 'title'), 'testing')
2461 self.assertEqual(self.db.issue.get(nodeid, 'assignedto'), self.mary_id)
2463 def testPrefixDelimiters(self):
2464 self.instance.config.MAILGW_SUBJECT_SUFFIX_DELIMITERS = '{}'
2465 self.db.keyword.create(name='Foo')
2466 self._handle_mail('''Content-Type: text/plain;
2467 charset="iso-8859-1"
2468 From: richard <richard@test.test>
2469 To: issue_tracker@your.tracker.email.domain.example
2470 Message-Id: <followup_dummy_id>
2471 In-Reply-To: <dummy_test_message_id>
2472 Subject: {keyword1} Testing... {name=Bar}
2474 ''')
2475 assert not os.path.exists(SENDMAILDEBUG)
2476 self.assertEqual(self.db.keyword.get('1', 'name'), 'Bar')
2478 def testCommandDelimitersIgnore(self):
2479 self.instance.config.MAILGW_SUBJECT_SUFFIX_DELIMITERS = '{}'
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 [assignedto=mary]
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 [assignedto=mary]')
2493 self.assertEqual(self.db.issue.get(nodeid, 'assignedto'), None)
2495 def testReplytoMatch(self):
2496 self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'loose'
2497 nodeid = self.doNewIssue()
2498 nodeid2 = self._handle_mail('''Content-Type: text/plain;
2499 charset="iso-8859-1"
2500 From: Chef <chef@bork.bork.bork>
2501 To: issue_tracker@your.tracker.email.domain.example
2502 Message-Id: <dummy_test_message_id2>
2503 In-Reply-To: <dummy_test_message_id>
2504 Subject: Testing...
2506 Followup message.
2507 ''')
2509 nodeid3 = self._handle_mail('''Content-Type: text/plain;
2510 charset="iso-8859-1"
2511 From: Chef <chef@bork.bork.bork>
2512 To: issue_tracker@your.tracker.email.domain.example
2513 Message-Id: <dummy_test_message_id3>
2514 In-Reply-To: <dummy_test_message_id2>
2515 Subject: Testing...
2517 Yet another message in the same thread/issue.
2518 ''')
2520 self.assertEqual(nodeid, nodeid2)
2521 self.assertEqual(nodeid, nodeid3)
2523 def testHelpSubject(self):
2524 message = '''Content-Type: text/plain;
2525 charset="iso-8859-1"
2526 From: Chef <chef@bork.bork.bork>
2527 To: issue_tracker@your.tracker.email.domain.example
2528 Message-Id: <dummy_test_message_id2>
2529 In-Reply-To: <dummy_test_message_id>
2530 Subject: hElp
2533 '''
2534 self.assertRaises(MailUsageHelp, self._handle_mail, message)
2536 def testMaillistSubject(self):
2537 self.instance.config.MAILGW_SUBJECT_SUFFIX_DELIMITERS = '[]'
2538 self.db.keyword.create(name='Foo')
2539 self._handle_mail('''Content-Type: text/plain;
2540 charset="iso-8859-1"
2541 From: Chef <chef@bork.bork.bork>
2542 To: issue_tracker@your.tracker.email.domain.example
2543 Subject: [mailinglist-name] [keyword1] Testing.. [name=Bar]
2544 Cc: richard@test.test
2545 Reply-To: chef@bork.bork.bork
2546 Message-Id: <dummy_test_message_id>
2548 ''')
2550 assert not os.path.exists(SENDMAILDEBUG)
2551 self.assertEqual(self.db.keyword.get('1', 'name'), 'Bar')
2553 def testUnknownPrefixSubject(self):
2554 self.db.keyword.create(name='Foo')
2555 self._handle_mail('''Content-Type: text/plain;
2556 charset="iso-8859-1"
2557 From: Chef <chef@bork.bork.bork>
2558 To: issue_tracker@your.tracker.email.domain.example
2559 Subject: VeryStrangeRe: [keyword1] Testing.. [name=Bar]
2560 Cc: richard@test.test
2561 Reply-To: chef@bork.bork.bork
2562 Message-Id: <dummy_test_message_id>
2564 ''')
2566 assert not os.path.exists(SENDMAILDEBUG)
2567 self.assertEqual(self.db.keyword.get('1', 'name'), 'Bar')
2569 def testOneCharSubject(self):
2570 message = '''Content-Type: text/plain;
2571 charset="iso-8859-1"
2572 From: Chef <chef@bork.bork.bork>
2573 To: issue_tracker@your.tracker.email.domain.example
2574 Subject: b
2575 Cc: richard@test.test
2576 Reply-To: chef@bork.bork.bork
2577 Message-Id: <dummy_test_message_id>
2579 '''
2580 try:
2581 self._handle_mail(message)
2582 except MailUsageError:
2583 self.fail('MailUsageError raised')
2585 def testIssueidLast(self):
2586 nodeid1 = self.doNewIssue()
2587 nodeid2 = self._handle_mail('''Content-Type: text/plain;
2588 charset="iso-8859-1"
2589 From: mary <mary@test.test>
2590 To: issue_tracker@your.tracker.email.domain.example
2591 Message-Id: <followup_dummy_id>
2592 In-Reply-To: <dummy_test_message_id>
2593 Subject: New title [issue1]
2595 This is a second followup
2596 ''')
2598 assert nodeid1 == nodeid2
2599 self.assertEqual(self.db.issue.get(nodeid2, 'title'), "Testing...")
2601 def testSecurityMessagePermissionContent(self):
2602 id = self.doNewIssue()
2603 issue = self.db.issue.getnode (id)
2604 self.db.security.addRole(name='Nomsg')
2605 self.db.security.addPermissionToRole('Nomsg', 'Email Access')
2606 for cl in 'issue', 'file', 'keyword':
2607 for p in 'View', 'Edit', 'Create':
2608 self.db.security.addPermissionToRole('Nomsg', p, cl)
2609 self.db.user.set(self.mary_id, roles='Nomsg')
2610 nodeid = self._handle_mail('''Content-Type: text/plain;
2611 charset="iso-8859-1"
2612 From: Chef <chef@bork.bork.bork>
2613 To: issue_tracker@your.tracker.email.domain.example
2614 Message-Id: <dummy_test_message_id_2>
2615 Subject: [issue%(id)s] Testing... [nosy=+mary]
2617 Just a test reply
2618 '''%locals())
2619 assert os.path.exists(SENDMAILDEBUG)
2620 self.compareMessages(self._get_mail(),
2621 '''FROM: roundup-admin@your.tracker.email.domain.example
2622 TO: chef@bork.bork.bork, richard@test.test
2623 Content-Type: text/plain; charset="utf-8"
2624 Subject: [issue1] Testing...
2625 To: richard@test.test
2626 From: "Bork, Chef" <issue_tracker@your.tracker.email.domain.example>
2627 Reply-To: Roundup issue tracker
2628 <issue_tracker@your.tracker.email.domain.example>
2629 MIME-Version: 1.0
2630 Message-Id: <dummy_test_message_id_2>
2631 In-Reply-To: <dummy_test_message_id>
2632 X-Roundup-Name: Roundup issue tracker
2633 X-Roundup-Loop: hello
2634 X-Roundup-Issue-Status: chatting
2635 Content-Transfer-Encoding: quoted-printable
2638 Bork, Chef <chef@bork.bork.bork> added the comment:
2640 Just a test reply
2642 ----------
2643 nosy: +mary
2644 status: unread -> chatting
2646 _______________________________________________________________________
2647 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
2648 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
2649 _______________________________________________________________________
2650 ''')
2652 def testOutlookAttachment(self):
2653 message = '''X-MimeOLE: Produced By Microsoft Exchange V6.5
2654 Content-class: urn:content-classes:message
2655 MIME-Version: 1.0
2656 Content-Type: multipart/mixed;
2657 boundary="----_=_NextPart_001_01CACA65.40A51CBC"
2658 Subject: Example of a failed outlook attachment e-mail
2659 Date: Tue, 23 Mar 2010 01:43:44 -0700
2660 Message-ID: <CA37F17219784343816CA6613D2E339205E7D0F9@nrcwstexb1.nrc.ca>
2661 X-MS-Has-Attach: yes
2662 X-MS-TNEF-Correlator:
2663 Thread-Topic: Example of a failed outlook attachment e-mail
2664 Thread-Index: AcrKJo/t3pUBBwTpSwWNE3LE67UBDQ==
2665 From: "Hugh" <richard@test.test>
2666 To: <richard@test.test>
2667 X-OriginalArrivalTime: 23 Mar 2010 08:45:57.0350 (UTC) FILETIME=[41893860:01CACA65]
2669 This is a multi-part message in MIME format.
2671 ------_=_NextPart_001_01CACA65.40A51CBC
2672 Content-Type: multipart/alternative;
2673 boundary="----_=_NextPart_002_01CACA65.40A51CBC"
2676 ------_=_NextPart_002_01CACA65.40A51CBC
2677 Content-Type: text/plain;
2678 charset="us-ascii"
2679 Content-Transfer-Encoding: quoted-printable
2682 Hi Richard,
2684 I suppose this isn't the exact message that was sent but is a resend of
2685 one of my trial messages that failed. For your benefit I changed the
2686 subject line and am adding these words to the message body. Should
2687 still be as problematic, but if you like I can resend an exact copy of a
2688 failed message changing nothing except putting your address instead of
2689 our tracker.
2691 Thanks very much for taking time to look into this. Much appreciated.
2693 <<battery backup>>=20
2695 ------_=_NextPart_002_01CACA65.40A51CBC
2696 Content-Type: text/html;
2697 charset="us-ascii"
2698 Content-Transfer-Encoding: quoted-printable
2700 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
2701 <HTML>
2702 <HEAD>
2703 <META HTTP-EQUIV=3D"Content-Type" CONTENT=3D"text/html; =
2704 charset=3Dus-ascii">
2705 <META NAME=3D"Generator" CONTENT=3D"MS Exchange Server version =
2706 6.5.7654.12">
2707 <TITLE>Example of a failed outlook attachment e-mail</TITLE>
2708 </HEAD>
2709 <BODY>
2710 <!-- Converted from text/rtf format -->
2711 <BR>
2713 <P><FONT SIZE=3D2 FACE=3D"Arial">Hi Richard,</FONT>
2714 </P>
2716 <P><FONT SIZE=3D2 FACE=3D"Arial">I suppose this isn't the exact message =
2717 that was sent but is a resend of one of my trial messages that =
2718 failed. For your benefit I changed the subject line and am adding =
2719 these words to the message body. Should still be as problematic, =
2720 but if you like I can resend an exact copy of a failed message changing =
2721 nothing except putting your address instead of our tracker.</FONT></P>
2723 <P><FONT SIZE=3D2 FACE=3D"Arial">Thanks very much for taking time to =
2724 look into this. Much appreciated.</FONT>
2725 </P>
2726 <BR>
2728 <P><FONT FACE=3D"Arial" SIZE=3D2 COLOR=3D"#000000"> <<battery =
2729 backup>> </FONT>
2730 </P>
2732 </BODY>
2733 </HTML>
2734 ------_=_NextPart_002_01CACA65.40A51CBC--
2736 ------_=_NextPart_001_01CACA65.40A51CBC
2737 Content-Type: message/rfc822
2738 Content-Transfer-Encoding: 7bit
2740 X-MimeOLE: Produced By Microsoft Exchange V6.5
2741 MIME-Version: 1.0
2742 Content-Type: multipart/alternative;
2743 boundary="----_=_NextPart_003_01CAC15A.29717800"
2744 X-OriginalArrivalTime: 11 Mar 2010 20:33:51.0249 (UTC) FILETIME=[28FEE010:01CAC15A]
2745 Content-class: urn:content-classes:message
2746 Subject: battery backup
2747 Date: Thu, 11 Mar 2010 13:33:43 -0700
2748 Message-ID: <p06240809c7bf02f9624c@[128.114.22.203]>
2749 X-MS-Has-Attach:
2750 X-MS-TNEF-Correlator:
2751 Thread-Topic: battery backup
2752 Thread-Index: AcrBWimtulTrSvBdQ2CcfZ8lyQdxmQ==
2753 From: "Jerry" <jerry@test.test>
2754 To: "Hugh" <hugh@test.test>
2756 This is a multi-part message in MIME format.
2758 ------_=_NextPart_003_01CAC15A.29717800
2759 Content-Type: text/plain;
2760 charset="iso-8859-1"
2761 Content-Transfer-Encoding: quoted-printable
2763 Dear Hugh,
2764 A car batter has an energy capacity of ~ 500Wh. A UPS=20
2765 battery is worse than this.
2767 if we need to provied 100kW for 30 minutes that will take 100 car=20
2768 batteries. This seems like an awful lot of batteries.
2770 Of course I like your idea of making the time 1 minute, so we get to=20
2771 a more modest number of batteries
2773 Jerry
2776 ------_=_NextPart_003_01CAC15A.29717800
2777 Content-Type: text/html;
2778 charset="iso-8859-1"
2779 Content-Transfer-Encoding: quoted-printable
2781 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
2782 <HTML>
2783 <HEAD>
2784 <META HTTP-EQUIV=3D"Content-Type" CONTENT=3D"text/html; =
2785 charset=3Diso-8859-1">
2786 <META NAME=3D"Generator" CONTENT=3D"MS Exchange Server version =
2787 6.5.7654.12">
2788 <TITLE>battery backup</TITLE>
2789 </HEAD>
2790 <BODY>
2791 <!-- Converted from text/plain format -->
2793 <P><FONT SIZE=3D2>Dear Hugh,</FONT>
2795 <BR> <FONT SIZE=3D2>A car =
2796 batter has an energy capacity of ~ 500Wh. A UPS </FONT>
2798 <BR><FONT SIZE=3D2>battery is worse than this.</FONT>
2799 </P>
2801 <P><FONT SIZE=3D2>if we need to provied 100kW for 30 minutes that will =
2802 take 100 car </FONT>
2804 <BR><FONT SIZE=3D2>batteries. This seems like an awful lot of =
2805 batteries.</FONT>
2806 </P>
2808 <P><FONT SIZE=3D2>Of course I like your idea of making the time 1 =
2809 minute, so we get to </FONT>
2811 <BR><FONT SIZE=3D2>a more modest number of batteries</FONT>
2812 </P>
2814 <P><FONT SIZE=3D2>Jerry</FONT>
2815 </P>
2817 </BODY>
2818 </HTML>
2819 ------_=_NextPart_003_01CAC15A.29717800--
2821 ------_=_NextPart_001_01CACA65.40A51CBC--
2822 '''
2823 nodeid = self._handle_mail(message)
2824 assert not os.path.exists(SENDMAILDEBUG)
2825 msgid = self.db.issue.get(nodeid, 'messages')[0]
2826 self.assert_(self.db.msg.get(msgid, 'content').startswith('Hi Richard'))
2827 self.assertEqual(self.db.msg.get(msgid, 'files'), ['1', '2'])
2828 fileid = self.db.msg.get(msgid, 'files')[0]
2829 self.assertEqual(self.db.file.get(fileid, 'type'), 'text/html')
2830 fileid = self.db.msg.get(msgid, 'files')[1]
2831 self.assertEqual(self.db.file.get(fileid, 'type'), 'message/rfc822')
2833 def testForwardedMessageAttachment(self):
2834 message = '''Return-Path: <rgg@test.test>
2835 Received: from localhost(127.0.0.1), claiming to be "[115.130.26.69]"
2836 via SMTP by localhost, id smtpdAAApLaWrq; Tue Apr 13 23:10:05 2010
2837 Message-ID: <4BC4F9C7.50409@test.test>
2838 Date: Wed, 14 Apr 2010 09:09:59 +1000
2839 From: Rupert Goldie <rgg@test.test>
2840 User-Agent: Thunderbird 2.0.0.24 (Windows/20100228)
2841 MIME-Version: 1.0
2842 To: ekit issues <issues@test.test>
2843 Subject: [Fwd: PHP ERROR (fb)] post limit reached
2844 Content-Type: multipart/mixed; boundary="------------000807090608060304010403"
2846 This is a multi-part message in MIME format.
2847 --------------000807090608060304010403
2848 Content-Type: text/plain; charset=ISO-8859-1; format=flowed
2849 Content-Transfer-Encoding: 7bit
2851 Catch this exception and log it without emailing.
2853 --------------000807090608060304010403
2854 Content-Type: message/rfc822; name="PHP ERROR (fb).eml"
2855 Content-Transfer-Encoding: 7bit
2856 Content-Disposition: inline; filename="PHP ERROR (fb).eml"
2858 Return-Path: <ektravj@test.test>
2859 X-Sieve: CMU Sieve 2.2
2860 via SMTP by crown.off.ekorp.com, id smtpdAAA1JaW1o; Tue Apr 13 23:01:04 2010
2861 X-Virus-Scanned: by amavisd-new at ekit.com
2862 To: facebook-errors@test.test
2863 From: ektravj@test.test
2864 Subject: PHP ERROR (fb)
2865 Message-Id: <20100413230100.D601D27E84@mail2.elax3.ekorp.com>
2866 Date: Tue, 13 Apr 2010 23:01:00 +0000 (UTC)
2868 [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
2869 Stack trace:
2870 #0 /app/01/www/virtual/fb.ekit.com/htdocs/gateway/ekit/feed/index.php(178): fb_exceptions(Object(FacebookRestClientException))
2871 #1 {main}
2872 thrown in /app/01/www/virtual/fb.ekit.com/htdocs/includes/functions.php on line 280
2875 --------------000807090608060304010403--
2876 '''
2877 nodeid = self._handle_mail(message)
2878 assert not os.path.exists(SENDMAILDEBUG)
2879 msgid = self.db.issue.get(nodeid, 'messages')[0]
2880 self.assertEqual(self.db.msg.get(msgid, 'content'),
2881 'Catch this exception and log it without emailing.')
2882 self.assertEqual(self.db.msg.get(msgid, 'files'), ['1'])
2883 fileid = self.db.msg.get(msgid, 'files')[0]
2884 self.assertEqual(self.db.file.get(fileid, 'type'), 'message/rfc822')
2886 def test_suite():
2887 suite = unittest.TestSuite()
2888 suite.addTest(unittest.makeSuite(MailgwTestCase))
2889 return suite
2891 if __name__ == '__main__':
2892 runner = unittest.TextTestRunner()
2893 unittest.main(testRunner=runner)
2895 # vim: set filetype=python sts=4 sw=4 et si :