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