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 doNewIssue(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 Cc: richard@test.test
270 Message-Id: <dummy_test_message_id>
271 Subject: [issue] Testing...
273 This is a test submission of a new issue.
274 ''')
275 assert not os.path.exists(SENDMAILDEBUG)
276 l = self.db.issue.get(nodeid, 'nosy')
277 l.sort()
278 self.assertEqual(l, [self.chef_id, self.richard_id])
279 return nodeid
281 def testNewIssue(self):
282 self.doNewIssue()
284 def testNewIssueNosy(self):
285 self.instance.config.ADD_AUTHOR_TO_NOSY = 'yes'
286 nodeid = self._handle_mail('''Content-Type: text/plain;
287 charset="iso-8859-1"
288 From: Chef <chef@bork.bork.bork>
289 To: issue_tracker@your.tracker.email.domain.example
290 Cc: richard@test.test
291 Message-Id: <dummy_test_message_id>
292 Subject: [issue] Testing...
294 This is a test submission of a new issue.
295 ''')
296 assert not os.path.exists(SENDMAILDEBUG)
297 l = self.db.issue.get(nodeid, 'nosy')
298 l.sort()
299 self.assertEqual(l, [self.chef_id, self.richard_id])
301 def testAlternateAddress(self):
302 self._handle_mail('''Content-Type: text/plain;
303 charset="iso-8859-1"
304 From: John Doe <john.doe@test.test>
305 To: issue_tracker@your.tracker.email.domain.example
306 Message-Id: <dummy_test_message_id>
307 Subject: [issue] Testing...
309 This is a test submission of a new issue.
310 ''')
311 userlist = self.db.user.list()
312 assert not os.path.exists(SENDMAILDEBUG)
313 self.assertEqual(userlist, self.db.user.list(),
314 "user created when it shouldn't have been")
316 def testNewIssueNoClass(self):
317 self._handle_mail('''Content-Type: text/plain;
318 charset="iso-8859-1"
319 From: Chef <chef@bork.bork.bork>
320 To: issue_tracker@your.tracker.email.domain.example
321 Cc: richard@test.test
322 Message-Id: <dummy_test_message_id>
323 Subject: Testing...
325 This is a test submission of a new issue.
326 ''')
327 assert not os.path.exists(SENDMAILDEBUG)
329 def testNewIssueAuthMsg(self):
330 # TODO: fix the damn config - this is apalling
331 self.db.config.MESSAGES_TO_AUTHOR = 'yes'
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 Message-Id: <dummy_test_message_id>
337 Subject: [issue] Testing... [nosy=mary; assignedto=richard]
339 This is a test submission of a new issue.
340 ''')
341 self.compareMessages(self._get_mail(),
342 '''FROM: roundup-admin@your.tracker.email.domain.example
343 TO: chef@bork.bork.bork, mary@test.test, richard@test.test
344 Content-Type: text/plain; charset="utf-8"
345 Subject: [issue1] Testing...
346 To: chef@bork.bork.bork, mary@test.test, richard@test.test
347 From: "Bork, Chef" <issue_tracker@your.tracker.email.domain.example>
348 Reply-To: Roundup issue tracker
349 <issue_tracker@your.tracker.email.domain.example>
350 MIME-Version: 1.0
351 Message-Id: <dummy_test_message_id>
352 X-Roundup-Name: Roundup issue tracker
353 X-Roundup-Loop: hello
354 X-Roundup-Issue-Status: unread
355 Content-Transfer-Encoding: quoted-printable
358 New submission from Bork, Chef <chef@bork.bork.bork>:
360 This is a test submission of a new issue.
362 ----------
363 assignedto: richard
364 messages: 1
365 nosy: Chef, mary, richard
366 status: unread
367 title: Testing...
369 _______________________________________________________________________
370 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
371 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
372 _______________________________________________________________________
373 ''')
375 def testNewIssueNoAuthorInfo(self):
376 self.db.config.MAIL_ADD_AUTHORINFO = 'no'
377 self._handle_mail('''Content-Type: text/plain;
378 charset="iso-8859-1"
379 From: Chef <chef@bork.bork.bork>
380 To: issue_tracker@your.tracker.email.domain.example
381 Message-Id: <dummy_test_message_id>
382 Subject: [issue] Testing... [nosy=mary; assignedto=richard]
384 This is a test submission of a new issue.
385 ''')
386 self.compareMessages(self._get_mail(),
387 '''FROM: roundup-admin@your.tracker.email.domain.example
388 TO: chef@bork.bork.bork, mary@test.test, richard@test.test
389 Content-Type: text/plain; charset="utf-8"
390 Subject: [issue1] Testing...
391 To: mary@test.test, richard@test.test
392 From: "Bork, Chef" <issue_tracker@your.tracker.email.domain.example>
393 Reply-To: Roundup issue tracker
394 <issue_tracker@your.tracker.email.domain.example>
395 MIME-Version: 1.0
396 Message-Id: <dummy_test_message_id>
397 X-Roundup-Name: Roundup issue tracker
398 X-Roundup-Loop: hello
399 X-Roundup-Issue-Status: unread
400 Content-Transfer-Encoding: quoted-printable
402 This is a test submission of a new issue.
404 ----------
405 assignedto: richard
406 messages: 1
407 nosy: Chef, mary, richard
408 status: unread
409 title: Testing...
411 _______________________________________________________________________
412 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
413 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
414 _______________________________________________________________________
415 ''')
417 def testNewIssueNoAuthorEmail(self):
418 self.db.config.MAIL_ADD_AUTHOREMAIL = 'no'
419 self._handle_mail('''Content-Type: text/plain;
420 charset="iso-8859-1"
421 From: Chef <chef@bork.bork.bork>
422 To: issue_tracker@your.tracker.email.domain.example
423 Message-Id: <dummy_test_message_id>
424 Subject: [issue] Testing... [nosy=mary; assignedto=richard]
426 This is a test submission of a new issue.
427 ''')
428 self.compareMessages(self._get_mail(),
429 '''FROM: roundup-admin@your.tracker.email.domain.example
430 TO: chef@bork.bork.bork, mary@test.test, richard@test.test
431 Content-Type: text/plain; charset="utf-8"
432 Subject: [issue1] Testing...
433 To: mary@test.test, richard@test.test
434 From: "Bork, Chef" <issue_tracker@your.tracker.email.domain.example>
435 Reply-To: Roundup issue tracker
436 <issue_tracker@your.tracker.email.domain.example>
437 MIME-Version: 1.0
438 Message-Id: <dummy_test_message_id>
439 X-Roundup-Name: Roundup issue tracker
440 X-Roundup-Loop: hello
441 X-Roundup-Issue-Status: unread
442 Content-Transfer-Encoding: quoted-printable
444 New submission from Bork, Chef:
446 This is a test submission of a new issue.
448 ----------
449 assignedto: richard
450 messages: 1
451 nosy: Chef, mary, richard
452 status: unread
453 title: Testing...
455 _______________________________________________________________________
456 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
457 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
458 _______________________________________________________________________
459 ''')
461 multipart_msg = '''From: mary <mary@test.test>
462 To: issue_tracker@your.tracker.email.domain.example
463 Message-Id: <followup_dummy_id>
464 In-Reply-To: <dummy_test_message_id>
465 Subject: [issue1] Testing...
466 Content-Type: multipart/mixed; boundary="bxyzzy"
467 Content-Disposition: inline
470 --bxyzzy
471 Content-Type: multipart/alternative; boundary="bCsyhTFzCvuiizWE"
472 Content-Disposition: inline
474 --bCsyhTFzCvuiizWE
475 Content-Type: text/plain; charset=us-ascii
476 Content-Disposition: inline
478 test attachment first text/plain
480 --bCsyhTFzCvuiizWE
481 Content-Type: application/octet-stream
482 Content-Disposition: attachment; filename="first.dvi"
483 Content-Transfer-Encoding: base64
485 SnVzdCBhIHRlc3QgAQo=
487 --bCsyhTFzCvuiizWE
488 Content-Type: text/plain; charset=us-ascii
489 Content-Disposition: inline
491 test attachment second text/plain
493 --bCsyhTFzCvuiizWE
494 Content-Type: text/html
495 Content-Disposition: inline
497 <html>
498 to be ignored.
499 </html>
501 --bCsyhTFzCvuiizWE--
503 --bxyzzy
504 Content-Type: multipart/alternative; boundary="bCsyhTFzCvuiizWF"
505 Content-Disposition: inline
507 --bCsyhTFzCvuiizWF
508 Content-Type: text/plain; charset=us-ascii
509 Content-Disposition: inline
511 test attachment third text/plain
513 --bCsyhTFzCvuiizWF
514 Content-Type: application/octet-stream
515 Content-Disposition: attachment; filename="second.dvi"
516 Content-Transfer-Encoding: base64
518 SnVzdCBhIHRlc3QK
520 --bCsyhTFzCvuiizWF--
522 --bxyzzy--
523 '''
525 multipart_msg_latin1 = '''From: mary <mary@test.test>
526 To: issue_tracker@your.tracker.email.domain.example
527 Message-Id: <followup_dummy_id>
528 In-Reply-To: <dummy_test_message_id>
529 Subject: [issue1] Testing...
530 Content-Type: multipart/alternative; boundary=001485f339f8f361fb049188dbba
533 --001485f339f8f361fb049188dbba
534 Content-Type: text/plain; charset=ISO-8859-1
535 Content-Transfer-Encoding: quoted-printable
537 umlaut =E4=F6=FC=C4=D6=DC=DF
539 --001485f339f8f361fb049188dbba
540 Content-Type: text/html; charset=ISO-8859-1
541 Content-Transfer-Encoding: quoted-printable
543 <html>umlaut =E4=F6=FC=C4=D6=DC=DF</html>
545 --001485f339f8f361fb049188dbba--
546 '''
548 multipart_msg_rfc822 = '''From: mary <mary@test.test>
549 To: issue_tracker@your.tracker.email.domain.example
550 Message-Id: <followup_dummy_id>
551 In-Reply-To: <dummy_test_message_id>
552 Subject: [issue1] Testing...
553 Content-Type: multipart/mixed; boundary=001485f339f8f361fb049188dbba
555 This is a multi-part message in MIME format.
556 --001485f339f8f361fb049188dbba
557 Content-Type: text/plain; charset=ISO-8859-15
558 Content-Transfer-Encoding: 7bit
560 First part: Text
562 --001485f339f8f361fb049188dbba
563 Content-Type: message/rfc822; name="Fwd: Original email subject.eml"
564 Content-Transfer-Encoding: 7bit
565 Content-Disposition: attachment; filename="Fwd: Original email subject.eml"
567 Message-Id: <followup_dummy_id_2>
568 In-Reply-To: <dummy_test_message_id_2>
569 MIME-Version: 1.0
570 Subject: Fwd: Original email subject
571 Date: Mon, 23 Aug 2010 08:23:33 +0200
572 Content-Type: multipart/alternative; boundary="090500050101020406060002"
574 This is a multi-part message in MIME format.
575 --090500050101020406060002
576 Content-Type: text/plain; charset=ISO-8859-15; format=flowed
577 Content-Transfer-Encoding: 7bit
579 some text in inner email
580 ========================
582 --090500050101020406060002
583 Content-Type: text/html; charset=ISO-8859-15
584 Content-Transfer-Encoding: 7bit
586 <html>
587 some text in inner email
588 ========================
589 </html>
591 --090500050101020406060002--
593 --001485f339f8f361fb049188dbba--
594 '''
596 def testMultipartKeepAlternatives(self):
597 self.doNewIssue()
598 self._handle_mail(self.multipart_msg)
599 messages = self.db.issue.get('1', 'messages')
600 messages.sort()
601 msg = self.db.msg.getnode (messages[-1])
602 assert(len(msg.files) == 5)
603 names = {0 : 'first.dvi', 4 : 'second.dvi'}
604 content = {3 : 'test attachment third text/plain\n',
605 4 : 'Just a test\n'}
606 for n, id in enumerate (msg.files):
607 f = self.db.file.getnode (id)
608 self.assertEqual(f.name, names.get (n, 'unnamed'))
609 if n in content :
610 self.assertEqual(f.content, content [n])
611 self.assertEqual(msg.content, 'test attachment second text/plain')
613 def testMultipartDropAlternatives(self):
614 self.doNewIssue()
615 self.db.config.MAILGW_IGNORE_ALTERNATIVES = True
616 self._handle_mail(self.multipart_msg)
617 messages = self.db.issue.get('1', 'messages')
618 messages.sort()
619 msg = self.db.msg.getnode (messages[-1])
620 assert(len(msg.files) == 2)
621 names = {1 : 'second.dvi'}
622 content = {0 : 'test attachment third text/plain\n',
623 1 : 'Just a test\n'}
624 for n, id in enumerate (msg.files):
625 f = self.db.file.getnode (id)
626 self.assertEqual(f.name, names.get (n, 'unnamed'))
627 if n in content :
628 self.assertEqual(f.content, content [n])
629 self.assertEqual(msg.content, 'test attachment second text/plain')
631 def testMultipartCharsetUTF8NoAttach(self):
632 c = 'umlaut \xc3\xa4\xc3\xb6\xc3\xbc\xc3\x84\xc3\x96\xc3\x9c\xc3\x9f'
633 self.doNewIssue()
634 self.db.config.NOSY_MAX_ATTACHMENT_SIZE = 0
635 self._handle_mail(self.multipart_msg_latin1)
636 messages = self.db.issue.get('1', 'messages')
637 messages.sort()
638 msg = self.db.msg.getnode (messages[-1])
639 assert(len(msg.files) == 1)
640 name = 'unnamed'
641 content = '<html>' + c + '</html>\n'
642 for n, id in enumerate (msg.files):
643 f = self.db.file.getnode (id)
644 self.assertEqual(f.name, name)
645 self.assertEqual(f.content, content)
646 self.assertEqual(msg.content, c)
647 self.compareMessages(self._get_mail(),
648 '''FROM: roundup-admin@your.tracker.email.domain.example
649 TO: chef@bork.bork.bork, richard@test.test
650 Content-Type: text/plain; charset="utf-8"
651 Subject: [issue1] Testing...
652 To: chef@bork.bork.bork, richard@test.test
653 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
654 Reply-To: Roundup issue tracker
655 <issue_tracker@your.tracker.email.domain.example>
656 MIME-Version: 1.0
657 Message-Id: <followup_dummy_id>
658 In-Reply-To: <dummy_test_message_id>
659 X-Roundup-Name: Roundup issue tracker
660 X-Roundup-Loop: hello
661 X-Roundup-Issue-Status: chatting
662 X-Roundup-Issue-Files: unnamed
663 Content-Transfer-Encoding: quoted-printable
666 Contrary, Mary <mary@test.test> added the comment:
668 umlaut =C3=A4=C3=B6=C3=BC=C3=84=C3=96=C3=9C=C3=9F
669 File 'unnamed' not attached - you can download it from http://tracker.examp=
670 le/cgi-bin/roundup.cgi/bugs/file1.
672 ----------
673 status: unread -> chatting
675 _______________________________________________________________________
676 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
677 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
678 _______________________________________________________________________
679 ''')
681 def testMultipartCharsetLatin1NoAttach(self):
682 c = 'umlaut \xc3\xa4\xc3\xb6\xc3\xbc\xc3\x84\xc3\x96\xc3\x9c\xc3\x9f'
683 self.doNewIssue()
684 self.db.config.NOSY_MAX_ATTACHMENT_SIZE = 0
685 self.db.config.MAIL_CHARSET = 'iso-8859-1'
686 self._handle_mail(self.multipart_msg_latin1)
687 messages = self.db.issue.get('1', 'messages')
688 messages.sort()
689 msg = self.db.msg.getnode (messages[-1])
690 assert(len(msg.files) == 1)
691 name = 'unnamed'
692 content = '<html>' + c + '</html>\n'
693 for n, id in enumerate (msg.files):
694 f = self.db.file.getnode (id)
695 self.assertEqual(f.name, name)
696 self.assertEqual(f.content, content)
697 self.assertEqual(msg.content, c)
698 self.compareMessages(self._get_mail(),
699 '''FROM: roundup-admin@your.tracker.email.domain.example
700 TO: chef@bork.bork.bork, richard@test.test
701 Content-Type: text/plain; charset="iso-8859-1"
702 Subject: [issue1] Testing...
703 To: chef@bork.bork.bork, richard@test.test
704 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
705 Reply-To: Roundup issue tracker
706 <issue_tracker@your.tracker.email.domain.example>
707 MIME-Version: 1.0
708 Message-Id: <followup_dummy_id>
709 In-Reply-To: <dummy_test_message_id>
710 X-Roundup-Name: Roundup issue tracker
711 X-Roundup-Loop: hello
712 X-Roundup-Issue-Status: chatting
713 X-Roundup-Issue-Files: unnamed
714 Content-Transfer-Encoding: quoted-printable
717 Contrary, Mary <mary@test.test> added the comment:
719 umlaut =E4=F6=FC=C4=D6=DC=DF
720 File 'unnamed' not attached - you can download it from http://tracker.examp=
721 le/cgi-bin/roundup.cgi/bugs/file1.
723 ----------
724 status: unread -> chatting
726 _______________________________________________________________________
727 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
728 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
729 _______________________________________________________________________
730 ''')
732 def testMultipartCharsetUTF8AttachFile(self):
733 c = 'umlaut \xc3\xa4\xc3\xb6\xc3\xbc\xc3\x84\xc3\x96\xc3\x9c\xc3\x9f'
734 self.doNewIssue()
735 self._handle_mail(self.multipart_msg_latin1)
736 messages = self.db.issue.get('1', 'messages')
737 messages.sort()
738 msg = self.db.msg.getnode (messages[-1])
739 assert(len(msg.files) == 1)
740 name = 'unnamed'
741 content = '<html>' + c + '</html>\n'
742 for n, id in enumerate (msg.files):
743 f = self.db.file.getnode (id)
744 self.assertEqual(f.name, name)
745 self.assertEqual(f.content, content)
746 self.assertEqual(msg.content, c)
747 self.compareMessages(self._get_mail(),
748 '''FROM: roundup-admin@your.tracker.email.domain.example
749 TO: chef@bork.bork.bork, richard@test.test
750 Content-Type: multipart/mixed; boundary="utf-8"
751 Subject: [issue1] Testing...
752 To: chef@bork.bork.bork, richard@test.test
753 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
754 Reply-To: Roundup issue tracker
755 <issue_tracker@your.tracker.email.domain.example>
756 MIME-Version: 1.0
757 Message-Id: <followup_dummy_id>
758 In-Reply-To: <dummy_test_message_id>
759 X-Roundup-Name: Roundup issue tracker
760 X-Roundup-Loop: hello
761 X-Roundup-Issue-Status: chatting
762 X-Roundup-Issue-Files: unnamed
763 Content-Transfer-Encoding: quoted-printable
766 --utf-8
767 MIME-Version: 1.0
768 Content-Type: text/plain; charset="utf-8"
769 Content-Transfer-Encoding: quoted-printable
772 Contrary, Mary <mary@test.test> added the comment:
774 umlaut =C3=A4=C3=B6=C3=BC=C3=84=C3=96=C3=9C=C3=9F
776 ----------
777 status: unread -> chatting
779 _______________________________________________________________________
780 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
781 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
782 _______________________________________________________________________
783 --utf-8
784 Content-Type: text/html
785 MIME-Version: 1.0
786 Content-Transfer-Encoding: base64
787 Content-Disposition: attachment;
788 filename="unnamed"
790 PGh0bWw+dW1sYXV0IMOkw7bDvMOEw5bDnMOfPC9odG1sPgo=
792 --utf-8--
793 ''')
795 def testMultipartCharsetLatin1AttachFile(self):
796 c = 'umlaut \xc3\xa4\xc3\xb6\xc3\xbc\xc3\x84\xc3\x96\xc3\x9c\xc3\x9f'
797 self.doNewIssue()
798 self.db.config.MAIL_CHARSET = 'iso-8859-1'
799 self._handle_mail(self.multipart_msg_latin1)
800 messages = self.db.issue.get('1', 'messages')
801 messages.sort()
802 msg = self.db.msg.getnode (messages[-1])
803 assert(len(msg.files) == 1)
804 name = 'unnamed'
805 content = '<html>' + c + '</html>\n'
806 for n, id in enumerate (msg.files):
807 f = self.db.file.getnode (id)
808 self.assertEqual(f.name, name)
809 self.assertEqual(f.content, content)
810 self.assertEqual(msg.content, c)
811 self.compareMessages(self._get_mail(),
812 '''FROM: roundup-admin@your.tracker.email.domain.example
813 TO: chef@bork.bork.bork, richard@test.test
814 Content-Type: multipart/mixed; boundary="utf-8"
815 Subject: [issue1] Testing...
816 To: chef@bork.bork.bork, richard@test.test
817 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
818 Reply-To: Roundup issue tracker
819 <issue_tracker@your.tracker.email.domain.example>
820 MIME-Version: 1.0
821 Message-Id: <followup_dummy_id>
822 In-Reply-To: <dummy_test_message_id>
823 X-Roundup-Name: Roundup issue tracker
824 X-Roundup-Loop: hello
825 X-Roundup-Issue-Status: chatting
826 X-Roundup-Issue-Files: unnamed
827 Content-Transfer-Encoding: quoted-printable
830 --utf-8
831 MIME-Version: 1.0
832 Content-Type: text/plain; charset="iso-8859-1"
833 Content-Transfer-Encoding: quoted-printable
836 Contrary, Mary <mary@test.test> added the comment:
838 umlaut =E4=F6=FC=C4=D6=DC=DF
840 ----------
841 status: unread -> chatting
843 _______________________________________________________________________
844 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
845 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
846 _______________________________________________________________________
847 --utf-8
848 Content-Type: text/html
849 MIME-Version: 1.0
850 Content-Transfer-Encoding: base64
851 Content-Disposition: attachment;
852 filename="unnamed"
854 PGh0bWw+dW1sYXV0IMOkw7bDvMOEw5bDnMOfPC9odG1sPgo=
856 --utf-8--
857 ''')
859 def testMultipartRFC822(self):
860 self.doNewIssue()
861 self._handle_mail(self.multipart_msg_rfc822)
862 messages = self.db.issue.get('1', 'messages')
863 messages.sort()
864 msg = self.db.msg.getnode (messages[-1])
865 assert(len(msg.files) == 1)
866 name = "Fwd: Original email subject.eml"
867 for n, id in enumerate (msg.files):
868 f = self.db.file.getnode (id)
869 self.assertEqual(f.name, name)
870 self.assertEqual(msg.content, 'First part: Text')
871 self.compareMessages(self._get_mail(),
872 '''TO: chef@bork.bork.bork, richard@test.test
873 Content-Type: text/plain; charset="utf-8"
874 Subject: [issue1] Testing...
875 To: chef@bork.bork.bork, richard@test.test
876 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
877 Reply-To: Roundup issue tracker
878 <issue_tracker@your.tracker.email.domain.example>
879 MIME-Version: 1.0
880 Message-Id: <followup_dummy_id>
881 In-Reply-To: <dummy_test_message_id>
882 X-Roundup-Name: Roundup issue tracker
883 X-Roundup-Loop: hello
884 X-Roundup-Issue-Status: chatting
885 X-Roundup-Issue-Files: Fwd: Original email subject.eml
886 Content-Transfer-Encoding: quoted-printable
889 --utf-8
890 MIME-Version: 1.0
891 Content-Type: text/plain; charset="utf-8"
892 Content-Transfer-Encoding: quoted-printable
895 Contrary, Mary <mary@test.test> added the comment:
897 First part: Text
899 ----------
900 status: unread -> chatting
902 _______________________________________________________________________
903 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
904 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
905 _______________________________________________________________________
906 --utf-8
907 Content-Type: message/rfc822
908 MIME-Version: 1.0
909 Content-Disposition: attachment;
910 filename="Fwd: Original email subject.eml"
912 Message-Id: <followup_dummy_id_2>
913 In-Reply-To: <dummy_test_message_id_2>
914 MIME-Version: 1.0
915 Subject: Fwd: Original email subject
916 Date: Mon, 23 Aug 2010 08:23:33 +0200
917 Content-Type: multipart/alternative; boundary="090500050101020406060002"
919 This is a multi-part message in MIME format.
920 --090500050101020406060002
921 Content-Type: text/plain; charset=ISO-8859-15; format=flowed
922 Content-Transfer-Encoding: 7bit
924 some text in inner email
925 ========================
927 --090500050101020406060002
928 Content-Type: text/html; charset=ISO-8859-15
929 Content-Transfer-Encoding: 7bit
931 <html>
932 some text in inner email
933 ========================
934 </html>
936 --090500050101020406060002--
938 --utf-8--
939 ''')
941 def testMultipartRFC822Unpack(self):
942 self.doNewIssue()
943 self.db.config.MAILGW_UNPACK_RFC822 = True
944 self._handle_mail(self.multipart_msg_rfc822)
945 messages = self.db.issue.get('1', 'messages')
946 messages.sort()
947 msg = self.db.msg.getnode (messages[-1])
948 self.assertEqual(len(msg.files), 2)
949 t = 'some text in inner email\n========================\n'
950 content = {0 : t, 1 : '<html>\n' + t + '</html>\n'}
951 for n, id in enumerate (msg.files):
952 f = self.db.file.getnode (id)
953 self.assertEqual(f.name, 'unnamed')
954 if n in content :
955 self.assertEqual(f.content, content [n])
956 self.assertEqual(msg.content, 'First part: Text')
958 def testSimpleFollowup(self):
959 self.doNewIssue()
960 self._handle_mail('''Content-Type: text/plain;
961 charset="iso-8859-1"
962 From: mary <mary@test.test>
963 To: issue_tracker@your.tracker.email.domain.example
964 Message-Id: <followup_dummy_id>
965 In-Reply-To: <dummy_test_message_id>
966 Subject: [issue1] Testing...
968 This is a second followup
969 ''')
970 self.compareMessages(self._get_mail(),
971 '''FROM: roundup-admin@your.tracker.email.domain.example
972 TO: chef@bork.bork.bork, richard@test.test
973 Content-Type: text/plain; charset="utf-8"
974 Subject: [issue1] Testing...
975 To: chef@bork.bork.bork, richard@test.test
976 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
977 Reply-To: Roundup issue tracker
978 <issue_tracker@your.tracker.email.domain.example>
979 MIME-Version: 1.0
980 Message-Id: <followup_dummy_id>
981 In-Reply-To: <dummy_test_message_id>
982 X-Roundup-Name: Roundup issue tracker
983 X-Roundup-Loop: hello
984 X-Roundup-Issue-Status: chatting
985 Content-Transfer-Encoding: quoted-printable
988 Contrary, Mary <mary@test.test> added the comment:
990 This is a second followup
992 ----------
993 status: unread -> chatting
995 _______________________________________________________________________
996 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
997 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
998 _______________________________________________________________________
999 ''')
1001 def testFollowup(self):
1002 self.doNewIssue()
1004 self._handle_mail('''Content-Type: text/plain;
1005 charset="iso-8859-1"
1006 From: richard <richard@test.test>
1007 To: issue_tracker@your.tracker.email.domain.example
1008 Message-Id: <followup_dummy_id>
1009 In-Reply-To: <dummy_test_message_id>
1010 Subject: [issue1] Testing... [assignedto=mary; nosy=+john]
1012 This is a followup
1013 ''')
1014 l = self.db.issue.get('1', 'nosy')
1015 l.sort()
1016 self.assertEqual(l, [self.chef_id, self.richard_id, self.mary_id,
1017 self.john_id])
1019 self.compareMessages(self._get_mail(),
1020 '''FROM: roundup-admin@your.tracker.email.domain.example
1021 TO: chef@bork.bork.bork, john@test.test, mary@test.test
1022 Content-Type: text/plain; charset="utf-8"
1023 Subject: [issue1] Testing...
1024 To: chef@bork.bork.bork, john@test.test, mary@test.test
1025 From: richard <issue_tracker@your.tracker.email.domain.example>
1026 Reply-To: Roundup issue tracker
1027 <issue_tracker@your.tracker.email.domain.example>
1028 MIME-Version: 1.0
1029 Message-Id: <followup_dummy_id>
1030 In-Reply-To: <dummy_test_message_id>
1031 X-Roundup-Name: Roundup issue tracker
1032 X-Roundup-Loop: hello
1033 X-Roundup-Issue-Status: chatting
1034 Content-Transfer-Encoding: quoted-printable
1037 richard <richard@test.test> added the comment:
1039 This is a followup
1041 ----------
1042 assignedto: -> mary
1043 nosy: +john, mary
1044 status: unread -> chatting
1046 _______________________________________________________________________
1047 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1048 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1049 _______________________________________________________________________
1050 ''')
1052 def testFollowupNoSubjectChange(self):
1053 self.db.config.MAILGW_SUBJECT_UPDATES_TITLE = 'no'
1054 self.doNewIssue()
1056 self._handle_mail('''Content-Type: text/plain;
1057 charset="iso-8859-1"
1058 From: richard <richard@test.test>
1059 To: issue_tracker@your.tracker.email.domain.example
1060 Message-Id: <followup_dummy_id>
1061 In-Reply-To: <dummy_test_message_id>
1062 Subject: [issue1] Wrzlbrmft... [assignedto=mary; nosy=+john]
1064 This is a followup
1065 ''')
1066 l = self.db.issue.get('1', 'nosy')
1067 l.sort()
1068 self.assertEqual(l, [self.chef_id, self.richard_id, self.mary_id,
1069 self.john_id])
1071 self.compareMessages(self._get_mail(),
1072 '''FROM: roundup-admin@your.tracker.email.domain.example
1073 TO: chef@bork.bork.bork, john@test.test, mary@test.test
1074 Content-Type: text/plain; charset="utf-8"
1075 Subject: [issue1] Testing...
1076 To: chef@bork.bork.bork, john@test.test, mary@test.test
1077 From: richard <issue_tracker@your.tracker.email.domain.example>
1078 Reply-To: Roundup issue tracker
1079 <issue_tracker@your.tracker.email.domain.example>
1080 MIME-Version: 1.0
1081 Message-Id: <followup_dummy_id>
1082 In-Reply-To: <dummy_test_message_id>
1083 X-Roundup-Name: Roundup issue tracker
1084 X-Roundup-Loop: hello
1085 X-Roundup-Issue-Status: chatting
1086 Content-Transfer-Encoding: quoted-printable
1089 richard <richard@test.test> added the comment:
1091 This is a followup
1093 ----------
1094 assignedto: -> mary
1095 nosy: +john, mary
1096 status: unread -> chatting
1098 _______________________________________________________________________
1099 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1100 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1101 _______________________________________________________________________
1102 ''')
1103 self.assertEqual(self.db.issue.get('1','title'), 'Testing...')
1105 def testFollowupExplicitSubjectChange(self):
1106 self.doNewIssue()
1108 self._handle_mail('''Content-Type: text/plain;
1109 charset="iso-8859-1"
1110 From: richard <richard@test.test>
1111 To: issue_tracker@your.tracker.email.domain.example
1112 Message-Id: <followup_dummy_id>
1113 In-Reply-To: <dummy_test_message_id>
1114 Subject: [issue1] Wrzlbrmft... [assignedto=mary; nosy=+john; title=new title]
1116 This is a followup
1117 ''')
1118 l = self.db.issue.get('1', 'nosy')
1119 l.sort()
1120 self.assertEqual(l, [self.chef_id, self.richard_id, self.mary_id,
1121 self.john_id])
1123 self.compareMessages(self._get_mail(),
1124 '''FROM: roundup-admin@your.tracker.email.domain.example
1125 TO: chef@bork.bork.bork, john@test.test, mary@test.test
1126 Content-Type: text/plain; charset="utf-8"
1127 Subject: [issue1] new title
1128 To: chef@bork.bork.bork, john@test.test, mary@test.test
1129 From: richard <issue_tracker@your.tracker.email.domain.example>
1130 Reply-To: Roundup issue tracker
1131 <issue_tracker@your.tracker.email.domain.example>
1132 MIME-Version: 1.0
1133 Message-Id: <followup_dummy_id>
1134 In-Reply-To: <dummy_test_message_id>
1135 X-Roundup-Name: Roundup issue tracker
1136 X-Roundup-Loop: hello
1137 X-Roundup-Issue-Status: chatting
1138 Content-Transfer-Encoding: quoted-printable
1141 richard <richard@test.test> added the comment:
1143 This is a followup
1145 ----------
1146 assignedto: -> mary
1147 nosy: +john, mary
1148 status: unread -> chatting
1149 title: Testing... -> new title
1151 _______________________________________________________________________
1152 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1153 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1154 _______________________________________________________________________
1155 ''')
1157 def testNosyGeneration(self):
1158 self.db.issue.create(title='test')
1160 # create a nosy message
1161 msg = self.db.msg.create(content='This is a test',
1162 author=self.richard_id, messageid='<dummy_test_message_id>')
1163 self.db.journaltag = 'richard'
1164 l = self.db.issue.create(title='test', messages=[msg],
1165 nosy=[self.chef_id, self.mary_id, self.john_id])
1167 self.compareMessages(self._get_mail(),
1168 '''FROM: roundup-admin@your.tracker.email.domain.example
1169 TO: chef@bork.bork.bork, john@test.test, mary@test.test
1170 Content-Type: text/plain; charset="utf-8"
1171 Subject: [issue2] test
1172 To: chef@bork.bork.bork, john@test.test, mary@test.test
1173 From: richard <issue_tracker@your.tracker.email.domain.example>
1174 Reply-To: Roundup issue tracker
1175 <issue_tracker@your.tracker.email.domain.example>
1176 MIME-Version: 1.0
1177 Message-Id: <dummy_test_message_id>
1178 X-Roundup-Name: Roundup issue tracker
1179 X-Roundup-Loop: hello
1180 X-Roundup-Issue-Status: unread
1181 Content-Transfer-Encoding: quoted-printable
1184 New submission from richard <richard@test.test>:
1186 This is a test
1188 ----------
1189 messages: 1
1190 nosy: Chef, john, mary, richard
1191 status: unread
1192 title: test
1194 _______________________________________________________________________
1195 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1196 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue2>
1197 _______________________________________________________________________
1198 ''')
1200 def testPropertyChangeOnly(self):
1201 self.doNewIssue()
1202 oldvalues = self.db.getnode('issue', '1').copy()
1203 oldvalues['assignedto'] = None
1204 # reconstruct old behaviour: This would reuse the
1205 # database-handle from the doNewIssue above which has committed
1206 # as user "Chef". So we close and reopen the db as that user.
1207 #self.db.close() actually don't close 'cos this empties memorydb
1208 self.db = self.instance.open('Chef')
1209 self.db.issue.set('1', assignedto=self.chef_id)
1210 self.db.commit()
1211 self.db.issue.nosymessage('1', None, oldvalues)
1213 new_mail = ""
1214 for line in self._get_mail().split("\n"):
1215 if "Message-Id: " in line:
1216 continue
1217 if "Date: " in line:
1218 continue
1219 new_mail += line+"\n"
1221 self.compareMessages(new_mail, """
1222 FROM: roundup-admin@your.tracker.email.domain.example
1223 TO: chef@bork.bork.bork, richard@test.test
1224 Content-Type: text/plain; charset="utf-8"
1225 Subject: [issue1] Testing...
1226 To: chef@bork.bork.bork, richard@test.test
1227 From: "Bork, Chef" <issue_tracker@your.tracker.email.domain.example>
1228 X-Roundup-Name: Roundup issue tracker
1229 X-Roundup-Loop: hello
1230 X-Roundup-Issue-Status: unread
1231 X-Roundup-Version: 1.3.3
1232 In-Reply-To: <dummy_test_message_id>
1233 MIME-Version: 1.0
1234 Reply-To: Roundup issue tracker
1235 <issue_tracker@your.tracker.email.domain.example>
1236 Content-Transfer-Encoding: quoted-printable
1239 Change by Bork, Chef <chef@bork.bork.bork>:
1242 ----------
1243 assignedto: -> Chef
1245 _______________________________________________________________________
1246 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1247 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1248 _______________________________________________________________________
1249 """)
1252 #
1253 # FOLLOWUP TITLE MATCH
1254 #
1255 def testFollowupTitleMatch(self):
1256 self.doNewIssue()
1257 self._handle_mail('''Content-Type: text/plain;
1258 charset="iso-8859-1"
1259 From: richard <richard@test.test>
1260 To: issue_tracker@your.tracker.email.domain.example
1261 Message-Id: <followup_dummy_id>
1262 Subject: Re: Testing... [assignedto=mary; nosy=+john]
1264 This is a followup
1265 ''')
1266 self.compareMessages(self._get_mail(),
1267 '''FROM: roundup-admin@your.tracker.email.domain.example
1268 TO: chef@bork.bork.bork, john@test.test, mary@test.test
1269 Content-Type: text/plain; charset="utf-8"
1270 Subject: [issue1] Testing...
1271 To: chef@bork.bork.bork, john@test.test, mary@test.test
1272 From: richard <issue_tracker@your.tracker.email.domain.example>
1273 Reply-To: Roundup issue tracker
1274 <issue_tracker@your.tracker.email.domain.example>
1275 MIME-Version: 1.0
1276 Message-Id: <followup_dummy_id>
1277 In-Reply-To: <dummy_test_message_id>
1278 X-Roundup-Name: Roundup issue tracker
1279 X-Roundup-Loop: hello
1280 X-Roundup-Issue-Status: chatting
1281 Content-Transfer-Encoding: quoted-printable
1284 richard <richard@test.test> added the comment:
1286 This is a followup
1288 ----------
1289 assignedto: -> mary
1290 nosy: +john, mary
1291 status: unread -> chatting
1293 _______________________________________________________________________
1294 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1295 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1296 _______________________________________________________________________
1297 ''')
1299 def testFollowupTitleMatchMultiRe(self):
1300 nodeid1 = self.doNewIssue()
1301 nodeid2 = self._handle_mail('''Content-Type: text/plain;
1302 charset="iso-8859-1"
1303 From: richard <richard@test.test>
1304 To: issue_tracker@your.tracker.email.domain.example
1305 Message-Id: <followup_dummy_id>
1306 Subject: Re: Testing... [assignedto=mary; nosy=+john]
1308 This is a followup
1309 ''')
1311 nodeid3 = self._handle_mail('''Content-Type: text/plain;
1312 charset="iso-8859-1"
1313 From: richard <richard@test.test>
1314 To: issue_tracker@your.tracker.email.domain.example
1315 Message-Id: <followup2_dummy_id>
1316 Subject: Ang: Re: Testing...
1318 This is a followup
1319 ''')
1320 self.assertEqual(nodeid1, nodeid2)
1321 self.assertEqual(nodeid1, nodeid3)
1323 def testFollowupTitleMatchNever(self):
1324 nodeid = self.doNewIssue()
1325 self.db.config.MAILGW_SUBJECT_CONTENT_MATCH = 'never'
1326 self.assertNotEqual(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: <followup_dummy_id>
1331 Subject: Re: Testing...
1333 This is a followup
1334 '''), nodeid)
1336 def testFollowupTitleMatchNeverInterval(self):
1337 nodeid = self.doNewIssue()
1338 # force failure of the interval
1339 time.sleep(2)
1340 self.db.config.MAILGW_SUBJECT_CONTENT_MATCH = 'creation 00:00:01'
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)
1352 def testFollowupTitleMatchInterval(self):
1353 nodeid = self.doNewIssue()
1354 self.db.config.MAILGW_SUBJECT_CONTENT_MATCH = 'creation +1d'
1355 self.assertEqual(self._handle_mail('''Content-Type: text/plain;
1356 charset="iso-8859-1"
1357 From: richard <richard@test.test>
1358 To: issue_tracker@your.tracker.email.domain.example
1359 Message-Id: <followup_dummy_id>
1360 Subject: Re: Testing...
1362 This is a followup
1363 '''), nodeid)
1366 def testFollowupNosyAuthor(self):
1367 self.doNewIssue()
1368 self.db.config.ADD_AUTHOR_TO_NOSY = 'yes'
1369 self._handle_mail('''Content-Type: text/plain;
1370 charset="iso-8859-1"
1371 From: john@test.test
1372 To: issue_tracker@your.tracker.email.domain.example
1373 Message-Id: <followup_dummy_id>
1374 In-Reply-To: <dummy_test_message_id>
1375 Subject: [issue1] Testing...
1377 This is a followup
1378 ''')
1380 self.compareMessages(self._get_mail(),
1381 '''FROM: roundup-admin@your.tracker.email.domain.example
1382 TO: chef@bork.bork.bork, richard@test.test
1383 Content-Type: text/plain; charset="utf-8"
1384 Subject: [issue1] Testing...
1385 To: chef@bork.bork.bork, richard@test.test
1386 From: John Doe <issue_tracker@your.tracker.email.domain.example>
1387 Reply-To: Roundup issue tracker
1388 <issue_tracker@your.tracker.email.domain.example>
1389 MIME-Version: 1.0
1390 Message-Id: <followup_dummy_id>
1391 In-Reply-To: <dummy_test_message_id>
1392 X-Roundup-Name: Roundup issue tracker
1393 X-Roundup-Loop: hello
1394 X-Roundup-Issue-Status: chatting
1395 Content-Transfer-Encoding: quoted-printable
1398 John Doe <john@test.test> added the comment:
1400 This is a followup
1402 ----------
1403 nosy: +john
1404 status: unread -> chatting
1406 _______________________________________________________________________
1407 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1408 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1409 _______________________________________________________________________
1411 ''')
1413 def testFollowupNosyRecipients(self):
1414 self.doNewIssue()
1415 self.db.config.ADD_RECIPIENTS_TO_NOSY = 'yes'
1416 self._handle_mail('''Content-Type: text/plain;
1417 charset="iso-8859-1"
1418 From: richard@test.test
1419 To: issue_tracker@your.tracker.email.domain.example
1420 Cc: john@test.test
1421 Message-Id: <followup_dummy_id>
1422 In-Reply-To: <dummy_test_message_id>
1423 Subject: [issue1] Testing...
1425 This is a followup
1426 ''')
1427 self.compareMessages(self._get_mail(),
1428 '''FROM: roundup-admin@your.tracker.email.domain.example
1429 TO: chef@bork.bork.bork
1430 Content-Type: text/plain; charset="utf-8"
1431 Subject: [issue1] Testing...
1432 To: chef@bork.bork.bork
1433 From: richard <issue_tracker@your.tracker.email.domain.example>
1434 Reply-To: Roundup issue tracker
1435 <issue_tracker@your.tracker.email.domain.example>
1436 MIME-Version: 1.0
1437 Message-Id: <followup_dummy_id>
1438 In-Reply-To: <dummy_test_message_id>
1439 X-Roundup-Name: Roundup issue tracker
1440 X-Roundup-Loop: hello
1441 X-Roundup-Issue-Status: chatting
1442 Content-Transfer-Encoding: quoted-printable
1445 richard <richard@test.test> added the comment:
1447 This is a followup
1449 ----------
1450 nosy: +john
1451 status: unread -> chatting
1453 _______________________________________________________________________
1454 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1455 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1456 _______________________________________________________________________
1458 ''')
1460 def testFollowupNosyAuthorAndCopy(self):
1461 self.doNewIssue()
1462 self.db.config.ADD_AUTHOR_TO_NOSY = 'yes'
1463 self.db.config.MESSAGES_TO_AUTHOR = 'yes'
1464 self._handle_mail('''Content-Type: text/plain;
1465 charset="iso-8859-1"
1466 From: john@test.test
1467 To: issue_tracker@your.tracker.email.domain.example
1468 Message-Id: <followup_dummy_id>
1469 In-Reply-To: <dummy_test_message_id>
1470 Subject: [issue1] Testing...
1472 This is a followup
1473 ''')
1474 self.compareMessages(self._get_mail(),
1475 '''FROM: roundup-admin@your.tracker.email.domain.example
1476 TO: chef@bork.bork.bork, john@test.test, richard@test.test
1477 Content-Type: text/plain; charset="utf-8"
1478 Subject: [issue1] Testing...
1479 To: chef@bork.bork.bork, john@test.test, richard@test.test
1480 From: John Doe <issue_tracker@your.tracker.email.domain.example>
1481 Reply-To: Roundup issue tracker
1482 <issue_tracker@your.tracker.email.domain.example>
1483 MIME-Version: 1.0
1484 Message-Id: <followup_dummy_id>
1485 In-Reply-To: <dummy_test_message_id>
1486 X-Roundup-Name: Roundup issue tracker
1487 X-Roundup-Loop: hello
1488 X-Roundup-Issue-Status: chatting
1489 Content-Transfer-Encoding: quoted-printable
1492 John Doe <john@test.test> added the comment:
1494 This is a followup
1496 ----------
1497 nosy: +john
1498 status: unread -> chatting
1500 _______________________________________________________________________
1501 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1502 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1503 _______________________________________________________________________
1505 ''')
1507 def testFollowupNoNosyAuthor(self):
1508 self.doNewIssue()
1509 self.instance.config.ADD_AUTHOR_TO_NOSY = 'no'
1510 self._handle_mail('''Content-Type: text/plain;
1511 charset="iso-8859-1"
1512 From: john@test.test
1513 To: issue_tracker@your.tracker.email.domain.example
1514 Message-Id: <followup_dummy_id>
1515 In-Reply-To: <dummy_test_message_id>
1516 Subject: [issue1] Testing...
1518 This is a followup
1519 ''')
1520 self.compareMessages(self._get_mail(),
1521 '''FROM: roundup-admin@your.tracker.email.domain.example
1522 TO: chef@bork.bork.bork, richard@test.test
1523 Content-Type: text/plain; charset="utf-8"
1524 Subject: [issue1] Testing...
1525 To: chef@bork.bork.bork, richard@test.test
1526 From: John Doe <issue_tracker@your.tracker.email.domain.example>
1527 Reply-To: Roundup issue tracker
1528 <issue_tracker@your.tracker.email.domain.example>
1529 MIME-Version: 1.0
1530 Message-Id: <followup_dummy_id>
1531 In-Reply-To: <dummy_test_message_id>
1532 X-Roundup-Name: Roundup issue tracker
1533 X-Roundup-Loop: hello
1534 X-Roundup-Issue-Status: chatting
1535 Content-Transfer-Encoding: quoted-printable
1538 John Doe <john@test.test> added the comment:
1540 This is a followup
1542 ----------
1543 status: unread -> chatting
1545 _______________________________________________________________________
1546 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1547 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1548 _______________________________________________________________________
1550 ''')
1552 def testFollowupNoNosyRecipients(self):
1553 self.doNewIssue()
1554 self.instance.config.ADD_RECIPIENTS_TO_NOSY = 'no'
1555 self._handle_mail('''Content-Type: text/plain;
1556 charset="iso-8859-1"
1557 From: richard@test.test
1558 To: issue_tracker@your.tracker.email.domain.example
1559 Cc: john@test.test
1560 Message-Id: <followup_dummy_id>
1561 In-Reply-To: <dummy_test_message_id>
1562 Subject: [issue1] Testing...
1564 This is a followup
1565 ''')
1566 self.compareMessages(self._get_mail(),
1567 '''FROM: roundup-admin@your.tracker.email.domain.example
1568 TO: chef@bork.bork.bork
1569 Content-Type: text/plain; charset="utf-8"
1570 Subject: [issue1] Testing...
1571 To: chef@bork.bork.bork
1572 From: richard <issue_tracker@your.tracker.email.domain.example>
1573 Reply-To: Roundup issue tracker
1574 <issue_tracker@your.tracker.email.domain.example>
1575 MIME-Version: 1.0
1576 Message-Id: <followup_dummy_id>
1577 In-Reply-To: <dummy_test_message_id>
1578 X-Roundup-Name: Roundup issue tracker
1579 X-Roundup-Loop: hello
1580 X-Roundup-Issue-Status: chatting
1581 Content-Transfer-Encoding: quoted-printable
1584 richard <richard@test.test> added the comment:
1586 This is a followup
1588 ----------
1589 status: unread -> chatting
1591 _______________________________________________________________________
1592 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1593 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1594 _______________________________________________________________________
1596 ''')
1598 def testFollowupEmptyMessage(self):
1599 self.doNewIssue()
1601 self._handle_mail('''Content-Type: text/plain;
1602 charset="iso-8859-1"
1603 From: richard <richard@test.test>
1604 To: issue_tracker@your.tracker.email.domain.example
1605 Message-Id: <followup_dummy_id>
1606 In-Reply-To: <dummy_test_message_id>
1607 Subject: [issue1] Testing... [assignedto=mary; nosy=+john]
1609 ''')
1610 l = self.db.issue.get('1', 'nosy')
1611 l.sort()
1612 self.assertEqual(l, [self.chef_id, self.richard_id, self.mary_id,
1613 self.john_id])
1615 # should be no file created (ie. no message)
1616 assert not os.path.exists(SENDMAILDEBUG)
1618 def testFollowupEmptyMessageNoSubject(self):
1619 self.doNewIssue()
1621 self._handle_mail('''Content-Type: text/plain;
1622 charset="iso-8859-1"
1623 From: richard <richard@test.test>
1624 To: issue_tracker@your.tracker.email.domain.example
1625 Message-Id: <followup_dummy_id>
1626 In-Reply-To: <dummy_test_message_id>
1627 Subject: [issue1] [assignedto=mary; nosy=+john]
1629 ''')
1630 l = self.db.issue.get('1', 'nosy')
1631 l.sort()
1632 self.assertEqual(l, [self.chef_id, self.richard_id, self.mary_id,
1633 self.john_id])
1635 # should be no file created (ie. no message)
1636 assert not os.path.exists(SENDMAILDEBUG)
1638 def testNosyRemove(self):
1639 self.doNewIssue()
1641 self._handle_mail('''Content-Type: text/plain;
1642 charset="iso-8859-1"
1643 From: richard <richard@test.test>
1644 To: issue_tracker@your.tracker.email.domain.example
1645 Message-Id: <followup_dummy_id>
1646 In-Reply-To: <dummy_test_message_id>
1647 Subject: [issue1] Testing... [nosy=-richard]
1649 ''')
1650 l = self.db.issue.get('1', 'nosy')
1651 l.sort()
1652 self.assertEqual(l, [self.chef_id])
1654 # NO NOSY MESSAGE SHOULD BE SENT!
1655 assert not os.path.exists(SENDMAILDEBUG)
1657 def testNewUserAuthor(self):
1658 self.db.commit()
1659 l = self.db.user.list()
1660 l.sort()
1661 message = '''Content-Type: text/plain;
1662 charset="iso-8859-1"
1663 From: fubar <fubar@bork.bork.bork>
1664 To: issue_tracker@your.tracker.email.domain.example
1665 Message-Id: <dummy_test_message_id>
1666 Subject: [issue] Testing...
1668 This is a test submission of a new issue.
1669 '''
1670 self.db.security.role['anonymous'].permissions=[]
1671 anonid = self.db.user.lookup('anonymous')
1672 self.db.user.set(anonid, roles='Anonymous')
1673 try:
1674 self._handle_mail(message)
1675 except Unauthorized, value:
1676 body_diff = self.compareMessages(str(value), """
1677 You are not a registered user.
1679 Unknown address: fubar@bork.bork.bork
1680 """)
1681 assert not body_diff, body_diff
1682 else:
1683 raise AssertionError, "Unathorized not raised when handling mail"
1685 # Add Web Access role to anonymous, and try again to make sure
1686 # we get a "please register at:" message this time.
1687 p = [
1688 self.db.security.getPermission('Register', 'user'),
1689 self.db.security.getPermission('Web Access', None),
1690 ]
1691 self.db.security.role['anonymous'].permissions=p
1692 try:
1693 self._handle_mail(message)
1694 except Unauthorized, value:
1695 body_diff = self.compareMessages(str(value), """
1696 You are not a registered user. Please register at:
1698 http://tracker.example/cgi-bin/roundup.cgi/bugs/user?template=register
1700 ...before sending mail to the tracker.
1702 Unknown address: fubar@bork.bork.bork
1703 """)
1704 assert not body_diff, body_diff
1705 else:
1706 raise AssertionError, "Unathorized not raised when handling mail"
1708 # Make sure list of users is the same as before.
1709 m = self.db.user.list()
1710 m.sort()
1711 self.assertEqual(l, m)
1713 # now with the permission
1714 p = [
1715 self.db.security.getPermission('Register', 'user'),
1716 self.db.security.getPermission('Email Access', None),
1717 ]
1718 self.db.security.role['anonymous'].permissions=p
1719 self._handle_mail(message)
1720 m = self.db.user.list()
1721 m.sort()
1722 self.assertNotEqual(l, m)
1724 def testNewUserAuthorEncodedName(self):
1725 l = set(self.db.user.list())
1726 # From: name has Euro symbol in it
1727 message = '''Content-Type: text/plain;
1728 charset="iso-8859-1"
1729 From: =?utf8?b?SOKCrGxsbw==?= <fubar@bork.bork.bork>
1730 To: issue_tracker@your.tracker.email.domain.example
1731 Message-Id: <dummy_test_message_id>
1732 Subject: [issue] Testing...
1734 This is a test submission of a new issue.
1735 '''
1736 p = [
1737 self.db.security.getPermission('Register', 'user'),
1738 self.db.security.getPermission('Email Access', None),
1739 self.db.security.getPermission('Create', 'issue'),
1740 self.db.security.getPermission('Create', 'msg'),
1741 ]
1742 self.db.security.role['anonymous'].permissions = p
1743 self._handle_mail(message)
1744 m = set(self.db.user.list())
1745 new = list(m - l)[0]
1746 name = self.db.user.get(new, 'realname')
1747 self.assertEquals(name, 'H€llo')
1749 def testUnknownUser(self):
1750 l = set(self.db.user.list())
1751 message = '''Content-Type: text/plain;
1752 charset="iso-8859-1"
1753 From: Nonexisting User <nonexisting@bork.bork.bork>
1754 To: issue_tracker@your.tracker.email.domain.example
1755 Message-Id: <dummy_test_message_id>
1756 Subject: [issue] Testing nonexisting user...
1758 This is a test submission of a new issue.
1759 '''
1760 handler = self._create_mailgw(message)
1761 # we want a bounce message:
1762 handler.trapExceptions = 1
1763 ret = handler.main(StringIO(message))
1764 self.compareMessages(self._get_mail(),
1765 '''FROM: Roundup issue tracker <roundup-admin@your.tracker.email.domain.example>
1766 TO: nonexisting@bork.bork.bork
1767 From nobody Tue Jul 14 12:04:11 2009
1768 Content-Type: multipart/mixed; boundary="===============0639262320=="
1769 MIME-Version: 1.0
1770 Subject: Failed issue tracker submission
1771 To: nonexisting@bork.bork.bork
1772 From: Roundup issue tracker <roundup-admin@your.tracker.email.domain.example>
1773 Date: Tue, 14 Jul 2009 12:04:11 +0000
1774 Precedence: bulk
1775 X-Roundup-Name: Roundup issue tracker
1776 X-Roundup-Loop: hello
1777 X-Roundup-Version: 1.4.8
1778 MIME-Version: 1.0
1780 --===============0639262320==
1781 Content-Type: text/plain; charset="us-ascii"
1782 MIME-Version: 1.0
1783 Content-Transfer-Encoding: 7bit
1787 You are not a registered user. Please register at:
1789 http://tracker.example/cgi-bin/roundup.cgi/bugs/user?template=register
1791 ...before sending mail to the tracker.
1793 Unknown address: nonexisting@bork.bork.bork
1795 --===============0639262320==
1796 Content-Type: text/plain; charset="us-ascii"
1797 MIME-Version: 1.0
1798 Content-Transfer-Encoding: 7bit
1800 Content-Type: text/plain;
1801 charset="iso-8859-1"
1802 From: Nonexisting User <nonexisting@bork.bork.bork>
1803 To: issue_tracker@your.tracker.email.domain.example
1804 Message-Id: <dummy_test_message_id>
1805 Subject: [issue] Testing nonexisting user...
1807 This is a test submission of a new issue.
1809 --===============0639262320==--
1810 ''')
1812 def testEnc01(self):
1813 self.db.user.set(self.mary_id,
1814 realname='\xe4\xf6\xfc\xc4\xd6\xdc\xdf, Mary'.decode
1815 ('latin-1').encode('utf-8'))
1816 self.doNewIssue()
1817 self._handle_mail('''Content-Type: text/plain;
1818 charset="iso-8859-1"
1819 From: mary <mary@test.test>
1820 To: issue_tracker@your.tracker.email.domain.example
1821 Message-Id: <followup_dummy_id>
1822 In-Reply-To: <dummy_test_message_id>
1823 Subject: [issue1] Testing...
1824 Content-Type: text/plain;
1825 charset="iso-8859-1"
1826 Content-Transfer-Encoding: quoted-printable
1828 A message with encoding (encoded oe =F6)
1830 ''')
1831 self.compareMessages(self._get_mail(),
1832 '''FROM: roundup-admin@your.tracker.email.domain.example
1833 TO: chef@bork.bork.bork, richard@test.test
1834 Content-Type: text/plain; charset="utf-8"
1835 Subject: [issue1] Testing...
1836 To: chef@bork.bork.bork, richard@test.test
1837 From: =?utf-8?b?w6TDtsO8w4TDlsOcw58sIE1hcnk=?=
1838 <issue_tracker@your.tracker.email.domain.example>
1839 Reply-To: Roundup issue tracker
1840 <issue_tracker@your.tracker.email.domain.example>
1841 MIME-Version: 1.0
1842 Message-Id: <followup_dummy_id>
1843 In-Reply-To: <dummy_test_message_id>
1844 X-Roundup-Name: Roundup issue tracker
1845 X-Roundup-Loop: hello
1846 X-Roundup-Issue-Status: chatting
1847 Content-Transfer-Encoding: quoted-printable
1850 =C3=A4=C3=B6=C3=BC=C3=84=C3=96=C3=9C=C3=9F, Mary <mary@test.test> added the=
1851 comment:
1853 A message with encoding (encoded oe =C3=B6)
1855 ----------
1856 status: unread -> chatting
1858 _______________________________________________________________________
1859 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1860 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1861 _______________________________________________________________________
1862 ''')
1864 def testEncNonUTF8(self):
1865 self.doNewIssue()
1866 self.instance.config.EMAIL_CHARSET = 'iso-8859-1'
1867 self._handle_mail('''Content-Type: text/plain;
1868 charset="iso-8859-1"
1869 From: mary <mary@test.test>
1870 To: issue_tracker@your.tracker.email.domain.example
1871 Message-Id: <followup_dummy_id>
1872 In-Reply-To: <dummy_test_message_id>
1873 Subject: [issue1] Testing...
1874 Content-Type: text/plain;
1875 charset="iso-8859-1"
1876 Content-Transfer-Encoding: quoted-printable
1878 A message with encoding (encoded oe =F6)
1880 ''')
1881 self.compareMessages(self._get_mail(),
1882 '''FROM: roundup-admin@your.tracker.email.domain.example
1883 TO: chef@bork.bork.bork, richard@test.test
1884 Content-Type: text/plain; charset="iso-8859-1"
1885 Subject: [issue1] Testing...
1886 To: chef@bork.bork.bork, richard@test.test
1887 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
1888 Reply-To: Roundup issue tracker
1889 <issue_tracker@your.tracker.email.domain.example>
1890 MIME-Version: 1.0
1891 Message-Id: <followup_dummy_id>
1892 In-Reply-To: <dummy_test_message_id>
1893 X-Roundup-Name: Roundup issue tracker
1894 X-Roundup-Loop: hello
1895 X-Roundup-Issue-Status: chatting
1896 Content-Transfer-Encoding: quoted-printable
1899 Contrary, Mary <mary@test.test> added the comment:
1901 A message with encoding (encoded oe =F6)
1903 ----------
1904 status: unread -> chatting
1906 _______________________________________________________________________
1907 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1908 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1909 _______________________________________________________________________
1910 ''')
1913 def testMultipartEnc01(self):
1914 self.doNewIssue()
1915 self._handle_mail('''Content-Type: text/plain;
1916 charset="iso-8859-1"
1917 From: mary <mary@test.test>
1918 To: issue_tracker@your.tracker.email.domain.example
1919 Message-Id: <followup_dummy_id>
1920 In-Reply-To: <dummy_test_message_id>
1921 Subject: [issue1] Testing...
1922 Content-Type: multipart/mixed;
1923 boundary="----_=_NextPart_000_01"
1925 This message is in MIME format. Since your mail reader does not understand
1926 this format, some or all of this message may not be legible.
1928 ------_=_NextPart_000_01
1929 Content-Type: text/plain;
1930 charset="iso-8859-1"
1931 Content-Transfer-Encoding: quoted-printable
1933 A message with first part encoded (encoded oe =F6)
1935 ''')
1936 self.compareMessages(self._get_mail(),
1937 '''FROM: roundup-admin@your.tracker.email.domain.example
1938 TO: chef@bork.bork.bork, richard@test.test
1939 Content-Type: text/plain; charset="utf-8"
1940 Subject: [issue1] Testing...
1941 To: chef@bork.bork.bork, richard@test.test
1942 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
1943 Reply-To: Roundup issue tracker
1944 <issue_tracker@your.tracker.email.domain.example>
1945 MIME-Version: 1.0
1946 Message-Id: <followup_dummy_id>
1947 In-Reply-To: <dummy_test_message_id>
1948 X-Roundup-Name: Roundup issue tracker
1949 X-Roundup-Loop: hello
1950 X-Roundup-Issue-Status: chatting
1951 Content-Transfer-Encoding: quoted-printable
1954 Contrary, Mary <mary@test.test> added the comment:
1956 A message with first part encoded (encoded oe =C3=B6)
1958 ----------
1959 status: unread -> chatting
1961 _______________________________________________________________________
1962 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1963 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1964 _______________________________________________________________________
1965 ''')
1967 def testContentDisposition(self):
1968 self.doNewIssue()
1969 self._handle_mail('''Content-Type: text/plain;
1970 charset="iso-8859-1"
1971 From: mary <mary@test.test>
1972 To: issue_tracker@your.tracker.email.domain.example
1973 Message-Id: <followup_dummy_id>
1974 In-Reply-To: <dummy_test_message_id>
1975 Subject: [issue1] Testing...
1976 Content-Type: multipart/mixed; boundary="bCsyhTFzCvuiizWE"
1977 Content-Disposition: inline
1980 --bCsyhTFzCvuiizWE
1981 Content-Type: text/plain; charset=us-ascii
1982 Content-Disposition: inline
1984 test attachment binary
1986 --bCsyhTFzCvuiizWE
1987 Content-Type: application/octet-stream
1988 Content-Disposition: attachment; filename="main.dvi"
1989 Content-Transfer-Encoding: base64
1991 SnVzdCBhIHRlc3QgAQo=
1993 --bCsyhTFzCvuiizWE--
1994 ''')
1995 messages = self.db.issue.get('1', 'messages')
1996 messages.sort()
1997 file = self.db.file.getnode (self.db.msg.get(messages[-1], 'files')[0])
1998 self.assertEqual(file.name, 'main.dvi')
1999 self.assertEqual(file.content, 'Just a test \001\n')
2001 def testFollowupStupidQuoting(self):
2002 self.doNewIssue()
2004 self._handle_mail('''Content-Type: text/plain;
2005 charset="iso-8859-1"
2006 From: richard <richard@test.test>
2007 To: issue_tracker@your.tracker.email.domain.example
2008 Message-Id: <followup_dummy_id>
2009 In-Reply-To: <dummy_test_message_id>
2010 Subject: Re: "[issue1] Testing... "
2012 This is a followup
2013 ''')
2014 self.compareMessages(self._get_mail(),
2015 '''FROM: roundup-admin@your.tracker.email.domain.example
2016 TO: chef@bork.bork.bork
2017 Content-Type: text/plain; charset="utf-8"
2018 Subject: [issue1] Testing...
2019 To: chef@bork.bork.bork
2020 From: richard <issue_tracker@your.tracker.email.domain.example>
2021 Reply-To: Roundup issue tracker
2022 <issue_tracker@your.tracker.email.domain.example>
2023 MIME-Version: 1.0
2024 Message-Id: <followup_dummy_id>
2025 In-Reply-To: <dummy_test_message_id>
2026 X-Roundup-Name: Roundup issue tracker
2027 X-Roundup-Loop: hello
2028 X-Roundup-Issue-Status: chatting
2029 Content-Transfer-Encoding: quoted-printable
2032 richard <richard@test.test> added the comment:
2034 This is a followup
2036 ----------
2037 status: unread -> chatting
2039 _______________________________________________________________________
2040 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
2041 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
2042 _______________________________________________________________________
2043 ''')
2045 def testEmailQuoting(self):
2046 self.instance.config.EMAIL_KEEP_QUOTED_TEXT = 'no'
2047 self.innerTestQuoting('''This is a followup
2048 ''')
2050 def testEmailQuotingRemove(self):
2051 self.instance.config.EMAIL_KEEP_QUOTED_TEXT = 'yes'
2052 self.innerTestQuoting('''Blah blah wrote:
2053 > Blah bklaskdfj sdf asdf jlaskdf skj sdkfjl asdf
2054 > skdjlkjsdfalsdkfjasdlfkj dlfksdfalksd fj
2055 >
2057 This is a followup
2058 ''')
2060 def innerTestQuoting(self, expect):
2061 nodeid = self.doNewIssue()
2063 messages = self.db.issue.get(nodeid, 'messages')
2065 self._handle_mail('''Content-Type: text/plain;
2066 charset="iso-8859-1"
2067 From: richard <richard@test.test>
2068 To: issue_tracker@your.tracker.email.domain.example
2069 Message-Id: <followup_dummy_id>
2070 In-Reply-To: <dummy_test_message_id>
2071 Subject: Re: [issue1] Testing...
2073 Blah blah wrote:
2074 > Blah bklaskdfj sdf asdf jlaskdf skj sdkfjl asdf
2075 > skdjlkjsdfalsdkfjasdlfkj dlfksdfalksd fj
2076 >
2078 This is a followup
2079 ''')
2080 # figure the new message id
2081 newmessages = self.db.issue.get(nodeid, 'messages')
2082 for msg in messages:
2083 newmessages.remove(msg)
2084 messageid = newmessages[0]
2086 self.compareMessages(self.db.msg.get(messageid, 'content'), expect)
2088 def testUserLookup(self):
2089 i = self.db.user.create(username='user1', address='user1@foo.com')
2090 self.assertEqual(uidFromAddress(self.db, ('', 'user1@foo.com'), 0), i)
2091 self.assertEqual(uidFromAddress(self.db, ('', 'USER1@foo.com'), 0), i)
2092 i = self.db.user.create(username='user2', address='USER2@foo.com')
2093 self.assertEqual(uidFromAddress(self.db, ('', 'USER2@foo.com'), 0), i)
2094 self.assertEqual(uidFromAddress(self.db, ('', 'user2@foo.com'), 0), i)
2096 def testUserAlternateLookup(self):
2097 i = self.db.user.create(username='user1', address='user1@foo.com',
2098 alternate_addresses='user1@bar.com')
2099 self.assertEqual(uidFromAddress(self.db, ('', 'user1@bar.com'), 0), i)
2100 self.assertEqual(uidFromAddress(self.db, ('', 'USER1@bar.com'), 0), i)
2102 def testUserCreate(self):
2103 i = uidFromAddress(self.db, ('', 'user@foo.com'), 1)
2104 self.assertNotEqual(uidFromAddress(self.db, ('', 'user@bar.com'), 1), i)
2106 def testRFC2822(self):
2107 ascii_header = "[issue243] This is a \"test\" - with 'quotation' marks"
2108 unicode_header = '[issue244] \xd0\xb0\xd0\xbd\xd0\xb4\xd1\x80\xd0\xb5\xd0\xb9'
2109 unicode_encoded = '=?utf-8?q?[issue244]_=D0=B0=D0=BD=D0=B4=D1=80=D0=B5=D0=B9?='
2110 self.assertEqual(rfc2822.encode_header(ascii_header), ascii_header)
2111 self.assertEqual(rfc2822.encode_header(unicode_header), unicode_encoded)
2113 def testRegistrationConfirmation(self):
2114 otk = "Aj4euk4LZSAdwePohj90SME5SpopLETL"
2115 self.db.getOTKManager().set(otk, username='johannes')
2116 self._handle_mail('''Content-Type: text/plain;
2117 charset="iso-8859-1"
2118 From: Chef <chef@bork.bork.bork>
2119 To: issue_tracker@your.tracker.email.domain.example
2120 Cc: richard@test.test
2121 Message-Id: <dummy_test_message_id>
2122 Subject: Re: Complete your registration to Roundup issue tracker
2123 -- key %s
2125 This is a test confirmation of registration.
2126 ''' % otk)
2127 self.db.user.lookup('johannes')
2129 def testFollowupOnNonIssue(self):
2130 self.db.keyword.create(name='Foo')
2131 self._handle_mail('''Content-Type: text/plain;
2132 charset="iso-8859-1"
2133 From: richard <richard@test.test>
2134 To: issue_tracker@your.tracker.email.domain.example
2135 Message-Id: <followup_dummy_id>
2136 In-Reply-To: <dummy_test_message_id>
2137 Subject: [keyword1] Testing... [name=Bar]
2139 ''')
2140 self.assertEqual(self.db.keyword.get('1', 'name'), 'Bar')
2142 def testResentFrom(self):
2143 nodeid = self._handle_mail('''Content-Type: text/plain;
2144 charset="iso-8859-1"
2145 From: Chef <chef@bork.bork.bork>
2146 Resent-From: mary <mary@test.test>
2147 To: issue_tracker@your.tracker.email.domain.example
2148 Cc: richard@test.test
2149 Message-Id: <dummy_test_message_id>
2150 Subject: [issue] Testing...
2152 This is a test submission of a new issue.
2153 ''')
2154 assert not os.path.exists(SENDMAILDEBUG)
2155 l = self.db.issue.get(nodeid, 'nosy')
2156 l.sort()
2157 self.assertEqual(l, [self.richard_id, self.mary_id])
2158 return nodeid
2160 def testDejaVu(self):
2161 self.assertRaises(IgnoreLoop, self._handle_mail,
2162 '''Content-Type: text/plain;
2163 charset="iso-8859-1"
2164 From: Chef <chef@bork.bork.bork>
2165 X-Roundup-Loop: hello
2166 To: issue_tracker@your.tracker.email.domain.example
2167 Cc: richard@test.test
2168 Message-Id: <dummy_test_message_id>
2169 Subject: Re: [issue] Testing...
2171 Hi, I've been mis-configured to loop messages back to myself.
2172 ''')
2174 def testItsBulkStupid(self):
2175 self.assertRaises(IgnoreBulk, self._handle_mail,
2176 '''Content-Type: text/plain;
2177 charset="iso-8859-1"
2178 From: Chef <chef@bork.bork.bork>
2179 Precedence: bulk
2180 To: issue_tracker@your.tracker.email.domain.example
2181 Cc: richard@test.test
2182 Message-Id: <dummy_test_message_id>
2183 Subject: Re: [issue] Testing...
2185 Hi, I'm on holidays, and this is a dumb auto-responder.
2186 ''')
2188 def testAutoReplyEmailsAreIgnored(self):
2189 self.assertRaises(IgnoreBulk, self._handle_mail,
2190 '''Content-Type: text/plain;
2191 charset="iso-8859-1"
2192 From: Chef <chef@bork.bork.bork>
2193 To: issue_tracker@your.tracker.email.domain.example
2194 Cc: richard@test.test
2195 Message-Id: <dummy_test_message_id>
2196 Subject: Re: [issue] Out of office AutoReply: Back next week
2198 Hi, I am back in the office next week
2199 ''')
2201 def testNoSubject(self):
2202 self.assertRaises(MailUsageError, self._handle_mail,
2203 '''Content-Type: text/plain;
2204 charset="iso-8859-1"
2205 From: Chef <chef@bork.bork.bork>
2206 To: issue_tracker@your.tracker.email.domain.example
2207 Cc: richard@test.test
2208 Reply-To: chef@bork.bork.bork
2209 Message-Id: <dummy_test_message_id>
2211 ''')
2213 #
2214 # TEST FOR INVALID DESIGNATOR HANDLING
2215 #
2216 def testInvalidDesignator(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 Subject: [frobulated] testing
2223 Cc: richard@test.test
2224 Reply-To: chef@bork.bork.bork
2225 Message-Id: <dummy_test_message_id>
2227 ''')
2228 self.assertRaises(MailUsageError, self._handle_mail,
2229 '''Content-Type: text/plain;
2230 charset="iso-8859-1"
2231 From: Chef <chef@bork.bork.bork>
2232 To: issue_tracker@your.tracker.email.domain.example
2233 Subject: [issue12345] testing
2234 Cc: richard@test.test
2235 Reply-To: chef@bork.bork.bork
2236 Message-Id: <dummy_test_message_id>
2238 ''')
2240 def testInvalidClassLoose(self):
2241 self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'loose'
2242 nodeid = self._handle_mail('''Content-Type: text/plain;
2243 charset="iso-8859-1"
2244 From: Chef <chef@bork.bork.bork>
2245 To: issue_tracker@your.tracker.email.domain.example
2246 Subject: [frobulated] testing
2247 Cc: richard@test.test
2248 Reply-To: chef@bork.bork.bork
2249 Message-Id: <dummy_test_message_id>
2251 ''')
2252 assert not os.path.exists(SENDMAILDEBUG)
2253 self.assertEqual(self.db.issue.get(nodeid, 'title'),
2254 '[frobulated] testing')
2256 def testInvalidClassLooseReply(self):
2257 self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'loose'
2258 nodeid = self._handle_mail('''Content-Type: text/plain;
2259 charset="iso-8859-1"
2260 From: Chef <chef@bork.bork.bork>
2261 To: issue_tracker@your.tracker.email.domain.example
2262 Subject: Re: [frobulated] testing
2263 Cc: richard@test.test
2264 Reply-To: chef@bork.bork.bork
2265 Message-Id: <dummy_test_message_id>
2267 ''')
2268 assert not os.path.exists(SENDMAILDEBUG)
2269 self.assertEqual(self.db.issue.get(nodeid, 'title'),
2270 '[frobulated] testing')
2272 def testInvalidClassLoose(self):
2273 self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'loose'
2274 nodeid = self._handle_mail('''Content-Type: text/plain;
2275 charset="iso-8859-1"
2276 From: Chef <chef@bork.bork.bork>
2277 To: issue_tracker@your.tracker.email.domain.example
2278 Subject: [issue1234] testing
2279 Cc: richard@test.test
2280 Reply-To: chef@bork.bork.bork
2281 Message-Id: <dummy_test_message_id>
2283 ''')
2284 assert not os.path.exists(SENDMAILDEBUG)
2285 self.assertEqual(self.db.issue.get(nodeid, 'title'),
2286 '[issue1234] testing')
2288 def testClassLooseOK(self):
2289 self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'loose'
2290 self.db.keyword.create(name='Foo')
2291 nodeid = self._handle_mail('''Content-Type: text/plain;
2292 charset="iso-8859-1"
2293 From: Chef <chef@bork.bork.bork>
2294 To: issue_tracker@your.tracker.email.domain.example
2295 Subject: [keyword1] Testing... [name=Bar]
2296 Cc: richard@test.test
2297 Reply-To: chef@bork.bork.bork
2298 Message-Id: <dummy_test_message_id>
2300 ''')
2301 assert not os.path.exists(SENDMAILDEBUG)
2302 self.assertEqual(self.db.keyword.get('1', 'name'), 'Bar')
2304 def testClassStrictInvalid(self):
2305 self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'strict'
2306 self.instance.config.MAILGW_DEFAULT_CLASS = ''
2308 message = '''Content-Type: text/plain;
2309 charset="iso-8859-1"
2310 From: Chef <chef@bork.bork.bork>
2311 To: issue_tracker@your.tracker.email.domain.example
2312 Subject: Testing...
2313 Cc: richard@test.test
2314 Reply-To: chef@bork.bork.bork
2315 Message-Id: <dummy_test_message_id>
2317 '''
2318 self.assertRaises(MailUsageError, self._handle_mail, message)
2320 def testClassStrictValid(self):
2321 self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'strict'
2322 self.instance.config.MAILGW_DEFAULT_CLASS = ''
2324 nodeid = self._handle_mail('''Content-Type: text/plain;
2325 charset="iso-8859-1"
2326 From: Chef <chef@bork.bork.bork>
2327 To: issue_tracker@your.tracker.email.domain.example
2328 Subject: [issue] Testing...
2329 Cc: richard@test.test
2330 Reply-To: chef@bork.bork.bork
2331 Message-Id: <dummy_test_message_id>
2333 ''')
2335 assert not os.path.exists(SENDMAILDEBUG)
2336 self.assertEqual(self.db.issue.get(nodeid, 'title'), 'Testing...')
2338 #
2339 # TEST FOR INVALID COMMANDS HANDLING
2340 #
2341 def testInvalidCommands(self):
2342 self.assertRaises(MailUsageError, self._handle_mail,
2343 '''Content-Type: text/plain;
2344 charset="iso-8859-1"
2345 From: Chef <chef@bork.bork.bork>
2346 To: issue_tracker@your.tracker.email.domain.example
2347 Subject: testing [frobulated]
2348 Cc: richard@test.test
2349 Reply-To: chef@bork.bork.bork
2350 Message-Id: <dummy_test_message_id>
2352 ''')
2354 def testInvalidCommandPassthrough(self):
2355 self.instance.config.MAILGW_SUBJECT_SUFFIX_PARSING = 'none'
2356 nodeid = self._handle_mail('''Content-Type: text/plain;
2357 charset="iso-8859-1"
2358 From: Chef <chef@bork.bork.bork>
2359 To: issue_tracker@your.tracker.email.domain.example
2360 Subject: testing [frobulated]
2361 Cc: richard@test.test
2362 Reply-To: chef@bork.bork.bork
2363 Message-Id: <dummy_test_message_id>
2365 ''')
2366 assert not os.path.exists(SENDMAILDEBUG)
2367 self.assertEqual(self.db.issue.get(nodeid, 'title'),
2368 'testing [frobulated]')
2370 def testInvalidCommandPassthroughLoose(self):
2371 self.instance.config.MAILGW_SUBJECT_SUFFIX_PARSING = 'loose'
2372 nodeid = self._handle_mail('''Content-Type: text/plain;
2373 charset="iso-8859-1"
2374 From: Chef <chef@bork.bork.bork>
2375 To: issue_tracker@your.tracker.email.domain.example
2376 Subject: testing [frobulated]
2377 Cc: richard@test.test
2378 Reply-To: chef@bork.bork.bork
2379 Message-Id: <dummy_test_message_id>
2381 ''')
2382 assert not os.path.exists(SENDMAILDEBUG)
2383 self.assertEqual(self.db.issue.get(nodeid, 'title'),
2384 'testing [frobulated]')
2386 def testInvalidCommandPassthroughLooseOK(self):
2387 self.instance.config.MAILGW_SUBJECT_SUFFIX_PARSING = 'loose'
2388 nodeid = self._handle_mail('''Content-Type: text/plain;
2389 charset="iso-8859-1"
2390 From: Chef <chef@bork.bork.bork>
2391 To: issue_tracker@your.tracker.email.domain.example
2392 Subject: testing [assignedto=mary]
2393 Cc: richard@test.test
2394 Reply-To: chef@bork.bork.bork
2395 Message-Id: <dummy_test_message_id>
2397 ''')
2398 assert not os.path.exists(SENDMAILDEBUG)
2399 self.assertEqual(self.db.issue.get(nodeid, 'title'), 'testing')
2400 self.assertEqual(self.db.issue.get(nodeid, 'assignedto'), self.mary_id)
2402 def testCommandDelimiters(self):
2403 self.instance.config.MAILGW_SUBJECT_SUFFIX_DELIMITERS = '{}'
2404 nodeid = self._handle_mail('''Content-Type: text/plain;
2405 charset="iso-8859-1"
2406 From: Chef <chef@bork.bork.bork>
2407 To: issue_tracker@your.tracker.email.domain.example
2408 Subject: testing {assignedto=mary}
2409 Cc: richard@test.test
2410 Reply-To: chef@bork.bork.bork
2411 Message-Id: <dummy_test_message_id>
2413 ''')
2414 assert not os.path.exists(SENDMAILDEBUG)
2415 self.assertEqual(self.db.issue.get(nodeid, 'title'), 'testing')
2416 self.assertEqual(self.db.issue.get(nodeid, 'assignedto'), self.mary_id)
2418 def testPrefixDelimiters(self):
2419 self.instance.config.MAILGW_SUBJECT_SUFFIX_DELIMITERS = '{}'
2420 self.db.keyword.create(name='Foo')
2421 self._handle_mail('''Content-Type: text/plain;
2422 charset="iso-8859-1"
2423 From: richard <richard@test.test>
2424 To: issue_tracker@your.tracker.email.domain.example
2425 Message-Id: <followup_dummy_id>
2426 In-Reply-To: <dummy_test_message_id>
2427 Subject: {keyword1} Testing... {name=Bar}
2429 ''')
2430 assert not os.path.exists(SENDMAILDEBUG)
2431 self.assertEqual(self.db.keyword.get('1', 'name'), 'Bar')
2433 def testCommandDelimitersIgnore(self):
2434 self.instance.config.MAILGW_SUBJECT_SUFFIX_DELIMITERS = '{}'
2435 nodeid = self._handle_mail('''Content-Type: text/plain;
2436 charset="iso-8859-1"
2437 From: Chef <chef@bork.bork.bork>
2438 To: issue_tracker@your.tracker.email.domain.example
2439 Subject: testing [assignedto=mary]
2440 Cc: richard@test.test
2441 Reply-To: chef@bork.bork.bork
2442 Message-Id: <dummy_test_message_id>
2444 ''')
2445 assert not os.path.exists(SENDMAILDEBUG)
2446 self.assertEqual(self.db.issue.get(nodeid, 'title'),
2447 'testing [assignedto=mary]')
2448 self.assertEqual(self.db.issue.get(nodeid, 'assignedto'), None)
2450 def testReplytoMatch(self):
2451 self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'loose'
2452 nodeid = self.doNewIssue()
2453 nodeid2 = self._handle_mail('''Content-Type: text/plain;
2454 charset="iso-8859-1"
2455 From: Chef <chef@bork.bork.bork>
2456 To: issue_tracker@your.tracker.email.domain.example
2457 Message-Id: <dummy_test_message_id2>
2458 In-Reply-To: <dummy_test_message_id>
2459 Subject: Testing...
2461 Followup message.
2462 ''')
2464 nodeid3 = self._handle_mail('''Content-Type: text/plain;
2465 charset="iso-8859-1"
2466 From: Chef <chef@bork.bork.bork>
2467 To: issue_tracker@your.tracker.email.domain.example
2468 Message-Id: <dummy_test_message_id3>
2469 In-Reply-To: <dummy_test_message_id2>
2470 Subject: Testing...
2472 Yet another message in the same thread/issue.
2473 ''')
2475 self.assertEqual(nodeid, nodeid2)
2476 self.assertEqual(nodeid, nodeid3)
2478 def testHelpSubject(self):
2479 message = '''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_id2>
2484 In-Reply-To: <dummy_test_message_id>
2485 Subject: hElp
2488 '''
2489 self.assertRaises(MailUsageHelp, self._handle_mail, message)
2491 def testMaillistSubject(self):
2492 self.instance.config.MAILGW_SUBJECT_SUFFIX_DELIMITERS = '[]'
2493 self.db.keyword.create(name='Foo')
2494 self._handle_mail('''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 Subject: [mailinglist-name] [keyword1] Testing.. [name=Bar]
2499 Cc: richard@test.test
2500 Reply-To: chef@bork.bork.bork
2501 Message-Id: <dummy_test_message_id>
2503 ''')
2505 assert not os.path.exists(SENDMAILDEBUG)
2506 self.assertEqual(self.db.keyword.get('1', 'name'), 'Bar')
2508 def testUnknownPrefixSubject(self):
2509 self.db.keyword.create(name='Foo')
2510 self._handle_mail('''Content-Type: text/plain;
2511 charset="iso-8859-1"
2512 From: Chef <chef@bork.bork.bork>
2513 To: issue_tracker@your.tracker.email.domain.example
2514 Subject: VeryStrangeRe: [keyword1] Testing.. [name=Bar]
2515 Cc: richard@test.test
2516 Reply-To: chef@bork.bork.bork
2517 Message-Id: <dummy_test_message_id>
2519 ''')
2521 assert not os.path.exists(SENDMAILDEBUG)
2522 self.assertEqual(self.db.keyword.get('1', 'name'), 'Bar')
2524 def testOneCharSubject(self):
2525 message = '''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: b
2530 Cc: richard@test.test
2531 Reply-To: chef@bork.bork.bork
2532 Message-Id: <dummy_test_message_id>
2534 '''
2535 try:
2536 self._handle_mail(message)
2537 except MailUsageError:
2538 self.fail('MailUsageError raised')
2540 def testIssueidLast(self):
2541 nodeid1 = self.doNewIssue()
2542 nodeid2 = self._handle_mail('''Content-Type: text/plain;
2543 charset="iso-8859-1"
2544 From: mary <mary@test.test>
2545 To: issue_tracker@your.tracker.email.domain.example
2546 Message-Id: <followup_dummy_id>
2547 In-Reply-To: <dummy_test_message_id>
2548 Subject: New title [issue1]
2550 This is a second followup
2551 ''')
2553 assert nodeid1 == nodeid2
2554 self.assertEqual(self.db.issue.get(nodeid2, 'title'), "Testing...")
2556 def testSecurityMessagePermissionContent(self):
2557 id = self.doNewIssue()
2558 issue = self.db.issue.getnode (id)
2559 self.db.security.addRole(name='Nomsg')
2560 self.db.security.addPermissionToRole('Nomsg', 'Email Access')
2561 for cl in 'issue', 'file', 'keyword':
2562 for p in 'View', 'Edit', 'Create':
2563 self.db.security.addPermissionToRole('Nomsg', p, cl)
2564 self.db.user.set(self.mary_id, roles='Nomsg')
2565 nodeid = self._handle_mail('''Content-Type: text/plain;
2566 charset="iso-8859-1"
2567 From: Chef <chef@bork.bork.bork>
2568 To: issue_tracker@your.tracker.email.domain.example
2569 Message-Id: <dummy_test_message_id_2>
2570 Subject: [issue%(id)s] Testing... [nosy=+mary]
2572 Just a test reply
2573 '''%locals())
2574 assert os.path.exists(SENDMAILDEBUG)
2575 self.compareMessages(self._get_mail(),
2576 '''FROM: roundup-admin@your.tracker.email.domain.example
2577 TO: chef@bork.bork.bork, richard@test.test
2578 Content-Type: text/plain; charset="utf-8"
2579 Subject: [issue1] Testing...
2580 To: richard@test.test
2581 From: "Bork, Chef" <issue_tracker@your.tracker.email.domain.example>
2582 Reply-To: Roundup issue tracker
2583 <issue_tracker@your.tracker.email.domain.example>
2584 MIME-Version: 1.0
2585 Message-Id: <dummy_test_message_id_2>
2586 In-Reply-To: <dummy_test_message_id>
2587 X-Roundup-Name: Roundup issue tracker
2588 X-Roundup-Loop: hello
2589 X-Roundup-Issue-Status: chatting
2590 Content-Transfer-Encoding: quoted-printable
2593 Bork, Chef <chef@bork.bork.bork> added the comment:
2595 Just a test reply
2597 ----------
2598 nosy: +mary
2599 status: unread -> chatting
2601 _______________________________________________________________________
2602 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
2603 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
2604 _______________________________________________________________________
2605 ''')
2607 def testOutlookAttachment(self):
2608 message = '''X-MimeOLE: Produced By Microsoft Exchange V6.5
2609 Content-class: urn:content-classes:message
2610 MIME-Version: 1.0
2611 Content-Type: multipart/mixed;
2612 boundary="----_=_NextPart_001_01CACA65.40A51CBC"
2613 Subject: Example of a failed outlook attachment e-mail
2614 Date: Tue, 23 Mar 2010 01:43:44 -0700
2615 Message-ID: <CA37F17219784343816CA6613D2E339205E7D0F9@nrcwstexb1.nrc.ca>
2616 X-MS-Has-Attach: yes
2617 X-MS-TNEF-Correlator:
2618 Thread-Topic: Example of a failed outlook attachment e-mail
2619 Thread-Index: AcrKJo/t3pUBBwTpSwWNE3LE67UBDQ==
2620 From: "Hugh" <richard@test.test>
2621 To: <richard@test.test>
2622 X-OriginalArrivalTime: 23 Mar 2010 08:45:57.0350 (UTC) FILETIME=[41893860:01CACA65]
2624 This is a multi-part message in MIME format.
2626 ------_=_NextPart_001_01CACA65.40A51CBC
2627 Content-Type: multipart/alternative;
2628 boundary="----_=_NextPart_002_01CACA65.40A51CBC"
2631 ------_=_NextPart_002_01CACA65.40A51CBC
2632 Content-Type: text/plain;
2633 charset="us-ascii"
2634 Content-Transfer-Encoding: quoted-printable
2637 Hi Richard,
2639 I suppose this isn't the exact message that was sent but is a resend of
2640 one of my trial messages that failed. For your benefit I changed the
2641 subject line and am adding these words to the message body. Should
2642 still be as problematic, but if you like I can resend an exact copy of a
2643 failed message changing nothing except putting your address instead of
2644 our tracker.
2646 Thanks very much for taking time to look into this. Much appreciated.
2648 <<battery backup>>=20
2650 ------_=_NextPart_002_01CACA65.40A51CBC
2651 Content-Type: text/html;
2652 charset="us-ascii"
2653 Content-Transfer-Encoding: quoted-printable
2655 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
2656 <HTML>
2657 <HEAD>
2658 <META HTTP-EQUIV=3D"Content-Type" CONTENT=3D"text/html; =
2659 charset=3Dus-ascii">
2660 <META NAME=3D"Generator" CONTENT=3D"MS Exchange Server version =
2661 6.5.7654.12">
2662 <TITLE>Example of a failed outlook attachment e-mail</TITLE>
2663 </HEAD>
2664 <BODY>
2665 <!-- Converted from text/rtf format -->
2666 <BR>
2668 <P><FONT SIZE=3D2 FACE=3D"Arial">Hi Richard,</FONT>
2669 </P>
2671 <P><FONT SIZE=3D2 FACE=3D"Arial">I suppose this isn't the exact message =
2672 that was sent but is a resend of one of my trial messages that =
2673 failed. For your benefit I changed the subject line and am adding =
2674 these words to the message body. Should still be as problematic, =
2675 but if you like I can resend an exact copy of a failed message changing =
2676 nothing except putting your address instead of our tracker.</FONT></P>
2678 <P><FONT SIZE=3D2 FACE=3D"Arial">Thanks very much for taking time to =
2679 look into this. Much appreciated.</FONT>
2680 </P>
2681 <BR>
2683 <P><FONT FACE=3D"Arial" SIZE=3D2 COLOR=3D"#000000"> <<battery =
2684 backup>> </FONT>
2685 </P>
2687 </BODY>
2688 </HTML>
2689 ------_=_NextPart_002_01CACA65.40A51CBC--
2691 ------_=_NextPart_001_01CACA65.40A51CBC
2692 Content-Type: message/rfc822
2693 Content-Transfer-Encoding: 7bit
2695 X-MimeOLE: Produced By Microsoft Exchange V6.5
2696 MIME-Version: 1.0
2697 Content-Type: multipart/alternative;
2698 boundary="----_=_NextPart_003_01CAC15A.29717800"
2699 X-OriginalArrivalTime: 11 Mar 2010 20:33:51.0249 (UTC) FILETIME=[28FEE010:01CAC15A]
2700 Content-class: urn:content-classes:message
2701 Subject: battery backup
2702 Date: Thu, 11 Mar 2010 13:33:43 -0700
2703 Message-ID: <p06240809c7bf02f9624c@[128.114.22.203]>
2704 X-MS-Has-Attach:
2705 X-MS-TNEF-Correlator:
2706 Thread-Topic: battery backup
2707 Thread-Index: AcrBWimtulTrSvBdQ2CcfZ8lyQdxmQ==
2708 From: "Jerry" <jerry@test.test>
2709 To: "Hugh" <hugh@test.test>
2711 This is a multi-part message in MIME format.
2713 ------_=_NextPart_003_01CAC15A.29717800
2714 Content-Type: text/plain;
2715 charset="iso-8859-1"
2716 Content-Transfer-Encoding: quoted-printable
2718 Dear Hugh,
2719 A car batter has an energy capacity of ~ 500Wh. A UPS=20
2720 battery is worse than this.
2722 if we need to provied 100kW for 30 minutes that will take 100 car=20
2723 batteries. This seems like an awful lot of batteries.
2725 Of course I like your idea of making the time 1 minute, so we get to=20
2726 a more modest number of batteries
2728 Jerry
2731 ------_=_NextPart_003_01CAC15A.29717800
2732 Content-Type: text/html;
2733 charset="iso-8859-1"
2734 Content-Transfer-Encoding: quoted-printable
2736 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
2737 <HTML>
2738 <HEAD>
2739 <META HTTP-EQUIV=3D"Content-Type" CONTENT=3D"text/html; =
2740 charset=3Diso-8859-1">
2741 <META NAME=3D"Generator" CONTENT=3D"MS Exchange Server version =
2742 6.5.7654.12">
2743 <TITLE>battery backup</TITLE>
2744 </HEAD>
2745 <BODY>
2746 <!-- Converted from text/plain format -->
2748 <P><FONT SIZE=3D2>Dear Hugh,</FONT>
2750 <BR> <FONT SIZE=3D2>A car =
2751 batter has an energy capacity of ~ 500Wh. A UPS </FONT>
2753 <BR><FONT SIZE=3D2>battery is worse than this.</FONT>
2754 </P>
2756 <P><FONT SIZE=3D2>if we need to provied 100kW for 30 minutes that will =
2757 take 100 car </FONT>
2759 <BR><FONT SIZE=3D2>batteries. This seems like an awful lot of =
2760 batteries.</FONT>
2761 </P>
2763 <P><FONT SIZE=3D2>Of course I like your idea of making the time 1 =
2764 minute, so we get to </FONT>
2766 <BR><FONT SIZE=3D2>a more modest number of batteries</FONT>
2767 </P>
2769 <P><FONT SIZE=3D2>Jerry</FONT>
2770 </P>
2772 </BODY>
2773 </HTML>
2774 ------_=_NextPart_003_01CAC15A.29717800--
2776 ------_=_NextPart_001_01CACA65.40A51CBC--
2777 '''
2778 nodeid = self._handle_mail(message)
2779 assert not os.path.exists(SENDMAILDEBUG)
2780 msgid = self.db.issue.get(nodeid, 'messages')[0]
2781 self.assert_(self.db.msg.get(msgid, 'content').startswith('Hi Richard'))
2782 self.assertEqual(self.db.msg.get(msgid, 'files'), ['1', '2'])
2783 fileid = self.db.msg.get(msgid, 'files')[0]
2784 self.assertEqual(self.db.file.get(fileid, 'type'), 'text/html')
2785 fileid = self.db.msg.get(msgid, 'files')[1]
2786 self.assertEqual(self.db.file.get(fileid, 'type'), 'message/rfc822')
2788 def testForwardedMessageAttachment(self):
2789 message = '''Return-Path: <rgg@test.test>
2790 Received: from localhost(127.0.0.1), claiming to be "[115.130.26.69]"
2791 via SMTP by localhost, id smtpdAAApLaWrq; Tue Apr 13 23:10:05 2010
2792 Message-ID: <4BC4F9C7.50409@test.test>
2793 Date: Wed, 14 Apr 2010 09:09:59 +1000
2794 From: Rupert Goldie <rgg@test.test>
2795 User-Agent: Thunderbird 2.0.0.24 (Windows/20100228)
2796 MIME-Version: 1.0
2797 To: ekit issues <issues@test.test>
2798 Subject: [Fwd: PHP ERROR (fb)] post limit reached
2799 Content-Type: multipart/mixed; boundary="------------000807090608060304010403"
2801 This is a multi-part message in MIME format.
2802 --------------000807090608060304010403
2803 Content-Type: text/plain; charset=ISO-8859-1; format=flowed
2804 Content-Transfer-Encoding: 7bit
2806 Catch this exception and log it without emailing.
2808 --------------000807090608060304010403
2809 Content-Type: message/rfc822; name="PHP ERROR (fb).eml"
2810 Content-Transfer-Encoding: 7bit
2811 Content-Disposition: inline; filename="PHP ERROR (fb).eml"
2813 Return-Path: <ektravj@test.test>
2814 X-Sieve: CMU Sieve 2.2
2815 via SMTP by crown.off.ekorp.com, id smtpdAAA1JaW1o; Tue Apr 13 23:01:04 2010
2816 X-Virus-Scanned: by amavisd-new at ekit.com
2817 To: facebook-errors@test.test
2818 From: ektravj@test.test
2819 Subject: PHP ERROR (fb)
2820 Message-Id: <20100413230100.D601D27E84@mail2.elax3.ekorp.com>
2821 Date: Tue, 13 Apr 2010 23:01:00 +0000 (UTC)
2823 [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
2824 Stack trace:
2825 #0 /app/01/www/virtual/fb.ekit.com/htdocs/gateway/ekit/feed/index.php(178): fb_exceptions(Object(FacebookRestClientException))
2826 #1 {main}
2827 thrown in /app/01/www/virtual/fb.ekit.com/htdocs/includes/functions.php on line 280
2830 --------------000807090608060304010403--
2831 '''
2832 nodeid = self._handle_mail(message)
2833 assert not os.path.exists(SENDMAILDEBUG)
2834 msgid = self.db.issue.get(nodeid, 'messages')[0]
2835 self.assertEqual(self.db.msg.get(msgid, 'content'),
2836 'Catch this exception and log it without emailing.')
2837 self.assertEqual(self.db.msg.get(msgid, 'files'), ['1'])
2838 fileid = self.db.msg.get(msgid, 'files')[0]
2839 self.assertEqual(self.db.file.get(fileid, 'type'), 'message/rfc822')
2841 def test_suite():
2842 suite = unittest.TestSuite()
2843 suite.addTest(unittest.makeSuite(MailgwTestCase))
2844 return suite
2846 if __name__ == '__main__':
2847 runner = unittest.TextTestRunner()
2848 unittest.main(testRunner=runner)
2850 # vim: set filetype=python sts=4 sw=4 et si :