0d698b6f6221d08ad00716d08ed1be658a5e702c
1 # -*- encoding: utf-8 -*-
2 #
3 # Copyright (c) 2001 Richard Jones, richard@bofh.asn.au.
4 # This module is free software, and you may redistribute it and/or modify
5 # under the same terms as Python, so long as this copyright message and
6 # disclaimer are retained in their original form.
7 #
8 # This module is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11 #
12 # $Id: test_mailgw.py,v 1.96 2008-08-19 01:40:59 richard Exp $
14 # TODO: test bcc
16 import unittest, tempfile, os, shutil, errno, imp, sys, difflib, rfc822, time
18 from cStringIO import StringIO
20 if not os.environ.has_key('SENDMAILDEBUG'):
21 os.environ['SENDMAILDEBUG'] = 'mail-test.log'
22 SENDMAILDEBUG = os.environ['SENDMAILDEBUG']
24 from roundup import mailgw, i18n, roundupdb
25 from roundup.mailgw import MailGW, Unauthorized, uidFromAddress, \
26 parseContent, IgnoreLoop, IgnoreBulk, MailUsageError, MailUsageHelp
27 from roundup import init, instance, password, rfc2822, __version__
28 from roundup.anypy.sets_ import set
30 #import db_test_base
31 import memorydb
33 class Message(rfc822.Message):
34 """String-based Message class with equivalence test."""
35 def __init__(self, s):
36 rfc822.Message.__init__(self, StringIO(s.strip()))
38 def __eq__(self, other):
39 return (self.dict == other.dict and
40 self.fp.read() == other.fp.read())
42 class Tracker(object):
43 def open(self, journaltag):
44 return self.db
46 class DiffHelper:
47 def compareMessages(self, new, old):
48 """Compare messages for semantic equivalence."""
49 new, old = Message(new), Message(old)
51 # all Roundup-generated messages have "Precedence: bulk"
52 old['Precedence'] = 'bulk'
54 # don't try to compare the date
55 del new['date'], old['date']
57 if not new == old:
58 res = []
60 replace = {}
61 for key in new.keys():
62 if key.startswith('from '):
63 # skip the unix from line
64 continue
65 if key.lower() == 'x-roundup-version':
66 # version changes constantly, so handle it specially
67 if new[key] != __version__:
68 res.append(' %s: %r != %r' % (key, __version__,
69 new[key]))
70 elif key.lower() == 'content-type' and 'boundary=' in new[key]:
71 # handle mime messages
72 newmime = new[key].split('=',1)[-1].strip('"')
73 oldmime = old.get(key, '').split('=',1)[-1].strip('"')
74 replace ['--' + newmime] = '--' + oldmime
75 replace ['--' + newmime + '--'] = '--' + oldmime + '--'
76 elif new.get(key, '') != old.get(key, ''):
77 res.append(' %s: %r != %r' % (key, old.get(key, ''),
78 new.get(key, '')))
80 body_diff = self.compareStrings(new.fp.read(), old.fp.read(),
81 replace=replace)
82 if body_diff:
83 res.append('')
84 res.extend(body_diff)
86 if res:
87 res.insert(0, 'Generated message not correct (diff follows, expected vs. actual):')
88 raise AssertionError, '\n'.join(res)
90 def compareStrings(self, s2, s1, replace={}):
91 '''Note the reversal of s2 and s1 - difflib.SequenceMatcher wants
92 the first to be the "original" but in the calls in this file,
93 the second arg is the original. Ho hum.
94 Do replacements over the replace dict -- used for mime boundary
95 '''
96 l1 = s1.strip().split('\n')
97 l2 = [replace.get(i,i) for i in s2.strip().split('\n')]
98 if l1 == l2:
99 return
100 s = difflib.SequenceMatcher(None, l1, l2)
101 res = []
102 for value, s1s, s1e, s2s, s2e in s.get_opcodes():
103 if value == 'equal':
104 for i in range(s1s, s1e):
105 res.append(' %s'%l1[i])
106 elif value == 'delete':
107 for i in range(s1s, s1e):
108 res.append('- %s'%l1[i])
109 elif value == 'insert':
110 for i in range(s2s, s2e):
111 res.append('+ %s'%l2[i])
112 elif value == 'replace':
113 for i, j in zip(range(s1s, s1e), range(s2s, s2e)):
114 res.append('- %s'%l1[i])
115 res.append('+ %s'%l2[j])
117 return res
119 class MailgwTestCase(unittest.TestCase, DiffHelper):
120 count = 0
121 schema = 'classic'
122 def setUp(self):
123 self.old_translate_ = mailgw._
124 roundupdb._ = mailgw._ = i18n.get_translation(language='C').gettext
125 MailgwTestCase.count = MailgwTestCase.count + 1
127 # and open the database / "instance"
128 self.db = memorydb.create('admin')
129 self.instance = Tracker()
130 self.instance.db = self.db
131 self.instance.config = self.db.config
132 self.instance.MailGW = MailGW
134 self.chef_id = self.db.user.create(username='Chef',
135 address='chef@bork.bork.bork', realname='Bork, Chef', roles='User')
136 self.richard_id = self.db.user.create(username='richard',
137 address='richard@test.test', roles='User')
138 self.mary_id = self.db.user.create(username='mary',
139 address='mary@test.test', roles='User', realname='Contrary, Mary')
140 self.john_id = self.db.user.create(username='john',
141 address='john@test.test', roles='User', realname='John Doe',
142 alternate_addresses='jondoe@test.test\njohn.doe@test.test')
143 self.rgg_id = self.db.user.create(username='rgg',
144 address='rgg@test.test', roles='User')
146 def tearDown(self):
147 roundupdb._ = mailgw._ = self.old_translate_
148 if os.path.exists(SENDMAILDEBUG):
149 os.remove(SENDMAILDEBUG)
150 self.db.close()
152 def _create_mailgw(self, message, args=()):
153 class MailGW(self.instance.MailGW):
154 def handle_message(self, message):
155 return self._handle_message(message)
156 handler = MailGW(self.instance, args)
157 handler.db = self.db
158 return handler
160 def _handle_mail(self, message, args=()):
161 handler = self._create_mailgw(message, args)
162 handler.trapExceptions = 0
163 return handler.main(StringIO(message))
165 def _get_mail(self):
166 f = open(SENDMAILDEBUG)
167 try:
168 return f.read()
169 finally:
170 f.close()
172 def testEmptyMessage(self):
173 nodeid = self._handle_mail('''Content-Type: text/plain;
174 charset="iso-8859-1"
175 From: Chef <chef@bork.bork.bork>
176 To: issue_tracker@your.tracker.email.domain.example
177 Cc: richard@test.test
178 Reply-To: chef@bork.bork.bork
179 Message-Id: <dummy_test_message_id>
180 Subject: [issue] Testing...
182 ''')
183 assert not os.path.exists(SENDMAILDEBUG)
184 self.assertEqual(self.db.issue.get(nodeid, 'title'), 'Testing...')
186 def testMessageWithFromInIt(self):
187 nodeid = self._handle_mail('''Content-Type: text/plain;
188 charset="iso-8859-1"
189 From: Chef <chef@bork.bork.bork>
190 To: issue_tracker@your.tracker.email.domain.example
191 Cc: richard@test.test
192 Reply-To: chef@bork.bork.bork
193 Message-Id: <dummy_test_message_id>
194 Subject: [issue] Testing...
196 From here to there!
197 ''')
198 assert not os.path.exists(SENDMAILDEBUG)
199 msgid = self.db.issue.get(nodeid, 'messages')[0]
200 self.assertEqual(self.db.msg.get(msgid, 'content'), 'From here to there!')
202 def testNoMessageId(self):
203 self.instance.config['MAIL_DOMAIN'] = 'example.com'
204 nodeid = self._handle_mail('''Content-Type: text/plain;
205 charset="iso-8859-1"
206 From: Chef <chef@bork.bork.bork>
207 To: issue_tracker@your.tracker.email.domain.example
208 Cc: richard@test.test
209 Reply-To: chef@bork.bork.bork
210 Subject: [issue] Testing...
212 Hi there!
213 ''')
214 assert not os.path.exists(SENDMAILDEBUG)
215 msgid = self.db.issue.get(nodeid, 'messages')[0]
216 messageid = self.db.msg.get(msgid, 'messageid')
217 x1, x2 = messageid.split('@')
218 self.assertEqual(x2, 'example.com>')
219 x = x1.split('.')[-1]
220 self.assertEqual(x, 'issueNone')
221 nodeid = self._handle_mail('''Content-Type: text/plain;
222 charset="iso-8859-1"
223 From: Chef <chef@bork.bork.bork>
224 To: issue_tracker@your.tracker.email.domain.example
225 Subject: [issue%(nodeid)s] Testing...
227 Just a test reply
228 '''%locals())
229 msgid = self.db.issue.get(nodeid, 'messages')[-1]
230 messageid = self.db.msg.get(msgid, 'messageid')
231 x1, x2 = messageid.split('@')
232 self.assertEqual(x2, 'example.com>')
233 x = x1.split('.')[-1]
234 self.assertEqual(x, "issue%s"%nodeid)
236 def testOptions(self):
237 nodeid = self._handle_mail('''Content-Type: text/plain;
238 charset="iso-8859-1"
239 From: Chef <chef@bork.bork.bork>
240 To: issue_tracker@your.tracker.email.domain.example
241 Message-Id: <dummy_test_message_id>
242 Reply-To: chef@bork.bork.bork
243 Subject: [issue] Testing...
245 Hi there!
246 ''', (('-C', 'issue'), ('-S', 'status=chatting;priority=critical')))
247 self.assertEqual(self.db.issue.get(nodeid, 'status'), '3')
248 self.assertEqual(self.db.issue.get(nodeid, 'priority'), '1')
250 def testOptionsMulti(self):
251 nodeid = self._handle_mail('''Content-Type: text/plain;
252 charset="iso-8859-1"
253 From: Chef <chef@bork.bork.bork>
254 To: issue_tracker@your.tracker.email.domain.example
255 Message-Id: <dummy_test_message_id>
256 Reply-To: chef@bork.bork.bork
257 Subject: [issue] Testing...
259 Hi there!
260 ''', (('-C', 'issue'), ('-S', 'status=chatting'), ('-S', 'priority=critical')))
261 self.assertEqual(self.db.issue.get(nodeid, 'status'), '3')
262 self.assertEqual(self.db.issue.get(nodeid, 'priority'), '1')
264 def testOptionClass(self):
265 nodeid = self._handle_mail('''Content-Type: text/plain;
266 charset="iso-8859-1"
267 From: Chef <chef@bork.bork.bork>
268 To: issue_tracker@your.tracker.email.domain.example
269 Message-Id: <dummy_test_message_id>
270 Reply-To: chef@bork.bork.bork
271 Subject: [issue] Testing...
273 Hi there!
274 ''', (('-c', 'issue'),))
275 self.assertEqual(self.db.issue.get(nodeid, 'status'), '3')
276 self.assertEqual(self.db.issue.get(nodeid, 'priority'), '1')
278 def doNewIssue(self):
279 nodeid = self._handle_mail('''Content-Type: text/plain;
280 charset="iso-8859-1"
281 From: Chef <chef@bork.bork.bork>
282 To: issue_tracker@your.tracker.email.domain.example
283 Cc: richard@test.test
284 Message-Id: <dummy_test_message_id>
285 Subject: [issue] Testing...
287 This is a test submission of a new issue.
288 ''')
289 assert not os.path.exists(SENDMAILDEBUG)
290 l = self.db.issue.get(nodeid, 'nosy')
291 l.sort()
292 self.assertEqual(l, [self.chef_id, self.richard_id])
293 return nodeid
295 def testNewIssue(self):
296 self.doNewIssue()
298 def testNewIssueNosy(self):
299 self.instance.config.ADD_AUTHOR_TO_NOSY = 'yes'
300 nodeid = self._handle_mail('''Content-Type: text/plain;
301 charset="iso-8859-1"
302 From: Chef <chef@bork.bork.bork>
303 To: issue_tracker@your.tracker.email.domain.example
304 Cc: richard@test.test
305 Message-Id: <dummy_test_message_id>
306 Subject: [issue] Testing...
308 This is a test submission of a new issue.
309 ''')
310 assert not os.path.exists(SENDMAILDEBUG)
311 l = self.db.issue.get(nodeid, 'nosy')
312 l.sort()
313 self.assertEqual(l, [self.chef_id, self.richard_id])
315 def testAlternateAddress(self):
316 self._handle_mail('''Content-Type: text/plain;
317 charset="iso-8859-1"
318 From: John Doe <john.doe@test.test>
319 To: issue_tracker@your.tracker.email.domain.example
320 Message-Id: <dummy_test_message_id>
321 Subject: [issue] Testing...
323 This is a test submission of a new issue.
324 ''')
325 userlist = self.db.user.list()
326 assert not os.path.exists(SENDMAILDEBUG)
327 self.assertEqual(userlist, self.db.user.list(),
328 "user created when it shouldn't have been")
330 def testNewIssueNoClass(self):
331 self._handle_mail('''Content-Type: text/plain;
332 charset="iso-8859-1"
333 From: Chef <chef@bork.bork.bork>
334 To: issue_tracker@your.tracker.email.domain.example
335 Cc: richard@test.test
336 Message-Id: <dummy_test_message_id>
337 Subject: Testing...
339 This is a test submission of a new issue.
340 ''')
341 assert not os.path.exists(SENDMAILDEBUG)
343 def testNewIssueAuthMsg(self):
344 # TODO: fix the damn config - this is apalling
345 self.db.config.MESSAGES_TO_AUTHOR = 'yes'
346 self._handle_mail('''Content-Type: text/plain;
347 charset="iso-8859-1"
348 From: Chef <chef@bork.bork.bork>
349 To: issue_tracker@your.tracker.email.domain.example
350 Message-Id: <dummy_test_message_id>
351 Subject: [issue] Testing... [nosy=mary; assignedto=richard]
353 This is a test submission of a new issue.
354 ''')
355 self.compareMessages(self._get_mail(),
356 '''FROM: roundup-admin@your.tracker.email.domain.example
357 TO: chef@bork.bork.bork, mary@test.test, richard@test.test
358 Content-Type: text/plain; charset="utf-8"
359 Subject: [issue1] Testing...
360 To: chef@bork.bork.bork, mary@test.test, richard@test.test
361 From: "Bork, Chef" <issue_tracker@your.tracker.email.domain.example>
362 Reply-To: Roundup issue tracker
363 <issue_tracker@your.tracker.email.domain.example>
364 MIME-Version: 1.0
365 Message-Id: <dummy_test_message_id>
366 X-Roundup-Name: Roundup issue tracker
367 X-Roundup-Loop: hello
368 X-Roundup-Issue-Status: unread
369 Content-Transfer-Encoding: quoted-printable
372 New submission from Bork, Chef <chef@bork.bork.bork>:
374 This is a test submission of a new issue.
376 ----------
377 assignedto: richard
378 messages: 1
379 nosy: Chef, mary, richard
380 status: unread
381 title: Testing...
383 _______________________________________________________________________
384 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
385 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
386 _______________________________________________________________________
387 ''')
389 def testNewIssueNoAuthorInfo(self):
390 self.db.config.MAIL_ADD_AUTHORINFO = 'no'
391 self._handle_mail('''Content-Type: text/plain;
392 charset="iso-8859-1"
393 From: Chef <chef@bork.bork.bork>
394 To: issue_tracker@your.tracker.email.domain.example
395 Message-Id: <dummy_test_message_id>
396 Subject: [issue] Testing... [nosy=mary; assignedto=richard]
398 This is a test submission of a new issue.
399 ''')
400 self.compareMessages(self._get_mail(),
401 '''FROM: roundup-admin@your.tracker.email.domain.example
402 TO: chef@bork.bork.bork, mary@test.test, richard@test.test
403 Content-Type: text/plain; charset="utf-8"
404 Subject: [issue1] Testing...
405 To: mary@test.test, richard@test.test
406 From: "Bork, Chef" <issue_tracker@your.tracker.email.domain.example>
407 Reply-To: Roundup issue tracker
408 <issue_tracker@your.tracker.email.domain.example>
409 MIME-Version: 1.0
410 Message-Id: <dummy_test_message_id>
411 X-Roundup-Name: Roundup issue tracker
412 X-Roundup-Loop: hello
413 X-Roundup-Issue-Status: unread
414 Content-Transfer-Encoding: quoted-printable
416 This is a test submission of a new issue.
418 ----------
419 assignedto: richard
420 messages: 1
421 nosy: Chef, mary, richard
422 status: unread
423 title: Testing...
425 _______________________________________________________________________
426 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
427 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
428 _______________________________________________________________________
429 ''')
431 def testNewIssueNoAuthorEmail(self):
432 self.db.config.MAIL_ADD_AUTHOREMAIL = 'no'
433 self._handle_mail('''Content-Type: text/plain;
434 charset="iso-8859-1"
435 From: Chef <chef@bork.bork.bork>
436 To: issue_tracker@your.tracker.email.domain.example
437 Message-Id: <dummy_test_message_id>
438 Subject: [issue] Testing... [nosy=mary; assignedto=richard]
440 This is a test submission of a new issue.
441 ''')
442 self.compareMessages(self._get_mail(),
443 '''FROM: roundup-admin@your.tracker.email.domain.example
444 TO: chef@bork.bork.bork, mary@test.test, richard@test.test
445 Content-Type: text/plain; charset="utf-8"
446 Subject: [issue1] Testing...
447 To: mary@test.test, richard@test.test
448 From: "Bork, Chef" <issue_tracker@your.tracker.email.domain.example>
449 Reply-To: Roundup issue tracker
450 <issue_tracker@your.tracker.email.domain.example>
451 MIME-Version: 1.0
452 Message-Id: <dummy_test_message_id>
453 X-Roundup-Name: Roundup issue tracker
454 X-Roundup-Loop: hello
455 X-Roundup-Issue-Status: unread
456 Content-Transfer-Encoding: quoted-printable
458 New submission from Bork, Chef:
460 This is a test submission of a new issue.
462 ----------
463 assignedto: richard
464 messages: 1
465 nosy: Chef, mary, richard
466 status: unread
467 title: Testing...
469 _______________________________________________________________________
470 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
471 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
472 _______________________________________________________________________
473 ''')
475 multipart_msg = '''From: mary <mary@test.test>
476 To: issue_tracker@your.tracker.email.domain.example
477 Message-Id: <followup_dummy_id>
478 In-Reply-To: <dummy_test_message_id>
479 Subject: [issue1] Testing...
480 Content-Type: multipart/mixed; boundary="bxyzzy"
481 Content-Disposition: inline
484 --bxyzzy
485 Content-Type: multipart/alternative; boundary="bCsyhTFzCvuiizWE"
486 Content-Disposition: inline
488 --bCsyhTFzCvuiizWE
489 Content-Type: text/plain; charset=us-ascii
490 Content-Disposition: inline
492 test attachment first text/plain
494 --bCsyhTFzCvuiizWE
495 Content-Type: application/octet-stream
496 Content-Disposition: attachment; filename="first.dvi"
497 Content-Transfer-Encoding: base64
499 SnVzdCBhIHRlc3QgAQo=
501 --bCsyhTFzCvuiizWE
502 Content-Type: text/plain; charset=us-ascii
503 Content-Disposition: inline
505 test attachment second text/plain
507 --bCsyhTFzCvuiizWE
508 Content-Type: text/html
509 Content-Disposition: inline
511 <html>
512 to be ignored.
513 </html>
515 --bCsyhTFzCvuiizWE--
517 --bxyzzy
518 Content-Type: multipart/alternative; boundary="bCsyhTFzCvuiizWF"
519 Content-Disposition: inline
521 --bCsyhTFzCvuiizWF
522 Content-Type: text/plain; charset=us-ascii
523 Content-Disposition: inline
525 test attachment third text/plain
527 --bCsyhTFzCvuiizWF
528 Content-Type: application/octet-stream
529 Content-Disposition: attachment; filename="second.dvi"
530 Content-Transfer-Encoding: base64
532 SnVzdCBhIHRlc3QK
534 --bCsyhTFzCvuiizWF--
536 --bxyzzy--
537 '''
539 multipart_msg_latin1 = '''From: mary <mary@test.test>
540 To: issue_tracker@your.tracker.email.domain.example
541 Message-Id: <followup_dummy_id>
542 In-Reply-To: <dummy_test_message_id>
543 Subject: [issue1] Testing...
544 Content-Type: multipart/alternative; boundary=001485f339f8f361fb049188dbba
547 --001485f339f8f361fb049188dbba
548 Content-Type: text/plain; charset=ISO-8859-1
549 Content-Transfer-Encoding: quoted-printable
551 umlaut =E4=F6=FC=C4=D6=DC=DF
553 --001485f339f8f361fb049188dbba
554 Content-Type: text/html; charset=ISO-8859-1
555 Content-Transfer-Encoding: quoted-printable
557 <html>umlaut =E4=F6=FC=C4=D6=DC=DF</html>
559 --001485f339f8f361fb049188dbba--
560 '''
562 multipart_msg_rfc822 = '''From: mary <mary@test.test>
563 To: issue_tracker@your.tracker.email.domain.example
564 Message-Id: <followup_dummy_id>
565 In-Reply-To: <dummy_test_message_id>
566 Subject: [issue1] Testing...
567 Content-Type: multipart/mixed; boundary=001485f339f8f361fb049188dbba
569 This is a multi-part message in MIME format.
570 --001485f339f8f361fb049188dbba
571 Content-Type: text/plain; charset=ISO-8859-15
572 Content-Transfer-Encoding: 7bit
574 First part: Text
576 --001485f339f8f361fb049188dbba
577 Content-Type: message/rfc822; name="Fwd: Original email subject.eml"
578 Content-Transfer-Encoding: 7bit
579 Content-Disposition: attachment; filename="Fwd: Original email subject.eml"
581 Message-Id: <followup_dummy_id_2>
582 In-Reply-To: <dummy_test_message_id_2>
583 MIME-Version: 1.0
584 Subject: Fwd: Original email subject
585 Date: Mon, 23 Aug 2010 08:23:33 +0200
586 Content-Type: multipart/alternative; boundary="090500050101020406060002"
588 This is a multi-part message in MIME format.
589 --090500050101020406060002
590 Content-Type: text/plain; charset=ISO-8859-15; format=flowed
591 Content-Transfer-Encoding: 7bit
593 some text in inner email
594 ========================
596 --090500050101020406060002
597 Content-Type: text/html; charset=ISO-8859-15
598 Content-Transfer-Encoding: 7bit
600 <html>
601 some text in inner email
602 ========================
603 </html>
605 --090500050101020406060002--
607 --001485f339f8f361fb049188dbba--
608 '''
610 def testMultipartKeepAlternatives(self):
611 self.doNewIssue()
612 self._handle_mail(self.multipart_msg)
613 messages = self.db.issue.get('1', 'messages')
614 messages.sort()
615 msg = self.db.msg.getnode (messages[-1])
616 assert(len(msg.files) == 5)
617 names = {0 : 'first.dvi', 4 : 'second.dvi'}
618 content = {3 : 'test attachment third text/plain\n',
619 4 : 'Just a test\n'}
620 for n, id in enumerate (msg.files):
621 f = self.db.file.getnode (id)
622 self.assertEqual(f.name, names.get (n, 'unnamed'))
623 if n in content :
624 self.assertEqual(f.content, content [n])
625 self.assertEqual(msg.content, 'test attachment second text/plain')
627 def testMultipartDropAlternatives(self):
628 self.doNewIssue()
629 self.db.config.MAILGW_IGNORE_ALTERNATIVES = True
630 self._handle_mail(self.multipart_msg)
631 messages = self.db.issue.get('1', 'messages')
632 messages.sort()
633 msg = self.db.msg.getnode (messages[-1])
634 assert(len(msg.files) == 2)
635 names = {1 : 'second.dvi'}
636 content = {0 : 'test attachment third text/plain\n',
637 1 : 'Just a test\n'}
638 for n, id in enumerate (msg.files):
639 f = self.db.file.getnode (id)
640 self.assertEqual(f.name, names.get (n, 'unnamed'))
641 if n in content :
642 self.assertEqual(f.content, content [n])
643 self.assertEqual(msg.content, 'test attachment second text/plain')
645 def testMultipartCharsetUTF8NoAttach(self):
646 c = 'umlaut \xc3\xa4\xc3\xb6\xc3\xbc\xc3\x84\xc3\x96\xc3\x9c\xc3\x9f'
647 self.doNewIssue()
648 self.db.config.NOSY_MAX_ATTACHMENT_SIZE = 0
649 self._handle_mail(self.multipart_msg_latin1)
650 messages = self.db.issue.get('1', 'messages')
651 messages.sort()
652 msg = self.db.msg.getnode (messages[-1])
653 assert(len(msg.files) == 1)
654 name = 'unnamed'
655 content = '<html>' + c + '</html>\n'
656 for n, id in enumerate (msg.files):
657 f = self.db.file.getnode (id)
658 self.assertEqual(f.name, name)
659 self.assertEqual(f.content, content)
660 self.assertEqual(msg.content, c)
661 self.compareMessages(self._get_mail(),
662 '''FROM: roundup-admin@your.tracker.email.domain.example
663 TO: chef@bork.bork.bork, richard@test.test
664 Content-Type: text/plain; charset="utf-8"
665 Subject: [issue1] Testing...
666 To: chef@bork.bork.bork, richard@test.test
667 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
668 Reply-To: Roundup issue tracker
669 <issue_tracker@your.tracker.email.domain.example>
670 MIME-Version: 1.0
671 Message-Id: <followup_dummy_id>
672 In-Reply-To: <dummy_test_message_id>
673 X-Roundup-Name: Roundup issue tracker
674 X-Roundup-Loop: hello
675 X-Roundup-Issue-Status: chatting
676 X-Roundup-Issue-Files: unnamed
677 Content-Transfer-Encoding: quoted-printable
680 Contrary, Mary <mary@test.test> added the comment:
682 umlaut =C3=A4=C3=B6=C3=BC=C3=84=C3=96=C3=9C=C3=9F
683 File 'unnamed' not attached - you can download it from http://tracker.examp=
684 le/cgi-bin/roundup.cgi/bugs/file1.
686 ----------
687 status: unread -> chatting
689 _______________________________________________________________________
690 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
691 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
692 _______________________________________________________________________
693 ''')
695 def testMultipartCharsetLatin1NoAttach(self):
696 c = 'umlaut \xc3\xa4\xc3\xb6\xc3\xbc\xc3\x84\xc3\x96\xc3\x9c\xc3\x9f'
697 self.doNewIssue()
698 self.db.config.NOSY_MAX_ATTACHMENT_SIZE = 0
699 self.db.config.MAIL_CHARSET = 'iso-8859-1'
700 self._handle_mail(self.multipart_msg_latin1)
701 messages = self.db.issue.get('1', 'messages')
702 messages.sort()
703 msg = self.db.msg.getnode (messages[-1])
704 assert(len(msg.files) == 1)
705 name = 'unnamed'
706 content = '<html>' + c + '</html>\n'
707 for n, id in enumerate (msg.files):
708 f = self.db.file.getnode (id)
709 self.assertEqual(f.name, name)
710 self.assertEqual(f.content, content)
711 self.assertEqual(msg.content, c)
712 self.compareMessages(self._get_mail(),
713 '''FROM: roundup-admin@your.tracker.email.domain.example
714 TO: chef@bork.bork.bork, richard@test.test
715 Content-Type: text/plain; charset="iso-8859-1"
716 Subject: [issue1] Testing...
717 To: chef@bork.bork.bork, richard@test.test
718 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
719 Reply-To: Roundup issue tracker
720 <issue_tracker@your.tracker.email.domain.example>
721 MIME-Version: 1.0
722 Message-Id: <followup_dummy_id>
723 In-Reply-To: <dummy_test_message_id>
724 X-Roundup-Name: Roundup issue tracker
725 X-Roundup-Loop: hello
726 X-Roundup-Issue-Status: chatting
727 X-Roundup-Issue-Files: unnamed
728 Content-Transfer-Encoding: quoted-printable
731 Contrary, Mary <mary@test.test> added the comment:
733 umlaut =E4=F6=FC=C4=D6=DC=DF
734 File 'unnamed' not attached - you can download it from http://tracker.examp=
735 le/cgi-bin/roundup.cgi/bugs/file1.
737 ----------
738 status: unread -> chatting
740 _______________________________________________________________________
741 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
742 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
743 _______________________________________________________________________
744 ''')
746 def testMultipartCharsetUTF8AttachFile(self):
747 c = 'umlaut \xc3\xa4\xc3\xb6\xc3\xbc\xc3\x84\xc3\x96\xc3\x9c\xc3\x9f'
748 self.doNewIssue()
749 self._handle_mail(self.multipart_msg_latin1)
750 messages = self.db.issue.get('1', 'messages')
751 messages.sort()
752 msg = self.db.msg.getnode (messages[-1])
753 assert(len(msg.files) == 1)
754 name = 'unnamed'
755 content = '<html>' + c + '</html>\n'
756 for n, id in enumerate (msg.files):
757 f = self.db.file.getnode (id)
758 self.assertEqual(f.name, name)
759 self.assertEqual(f.content, content)
760 self.assertEqual(msg.content, c)
761 self.compareMessages(self._get_mail(),
762 '''FROM: roundup-admin@your.tracker.email.domain.example
763 TO: chef@bork.bork.bork, richard@test.test
764 Content-Type: multipart/mixed; boundary="utf-8"
765 Subject: [issue1] Testing...
766 To: chef@bork.bork.bork, richard@test.test
767 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
768 Reply-To: Roundup issue tracker
769 <issue_tracker@your.tracker.email.domain.example>
770 MIME-Version: 1.0
771 Message-Id: <followup_dummy_id>
772 In-Reply-To: <dummy_test_message_id>
773 X-Roundup-Name: Roundup issue tracker
774 X-Roundup-Loop: hello
775 X-Roundup-Issue-Status: chatting
776 X-Roundup-Issue-Files: unnamed
777 Content-Transfer-Encoding: quoted-printable
780 --utf-8
781 MIME-Version: 1.0
782 Content-Type: text/plain; charset="utf-8"
783 Content-Transfer-Encoding: quoted-printable
786 Contrary, Mary <mary@test.test> added the comment:
788 umlaut =C3=A4=C3=B6=C3=BC=C3=84=C3=96=C3=9C=C3=9F
790 ----------
791 status: unread -> chatting
793 _______________________________________________________________________
794 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
795 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
796 _______________________________________________________________________
797 --utf-8
798 Content-Type: text/html
799 MIME-Version: 1.0
800 Content-Transfer-Encoding: base64
801 Content-Disposition: attachment;
802 filename="unnamed"
804 PGh0bWw+dW1sYXV0IMOkw7bDvMOEw5bDnMOfPC9odG1sPgo=
806 --utf-8--
807 ''')
809 def testMultipartCharsetLatin1AttachFile(self):
810 c = 'umlaut \xc3\xa4\xc3\xb6\xc3\xbc\xc3\x84\xc3\x96\xc3\x9c\xc3\x9f'
811 self.doNewIssue()
812 self.db.config.MAIL_CHARSET = 'iso-8859-1'
813 self._handle_mail(self.multipart_msg_latin1)
814 messages = self.db.issue.get('1', 'messages')
815 messages.sort()
816 msg = self.db.msg.getnode (messages[-1])
817 assert(len(msg.files) == 1)
818 name = 'unnamed'
819 content = '<html>' + c + '</html>\n'
820 for n, id in enumerate (msg.files):
821 f = self.db.file.getnode (id)
822 self.assertEqual(f.name, name)
823 self.assertEqual(f.content, content)
824 self.assertEqual(msg.content, c)
825 self.compareMessages(self._get_mail(),
826 '''FROM: roundup-admin@your.tracker.email.domain.example
827 TO: chef@bork.bork.bork, richard@test.test
828 Content-Type: multipart/mixed; boundary="utf-8"
829 Subject: [issue1] Testing...
830 To: chef@bork.bork.bork, richard@test.test
831 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
832 Reply-To: Roundup issue tracker
833 <issue_tracker@your.tracker.email.domain.example>
834 MIME-Version: 1.0
835 Message-Id: <followup_dummy_id>
836 In-Reply-To: <dummy_test_message_id>
837 X-Roundup-Name: Roundup issue tracker
838 X-Roundup-Loop: hello
839 X-Roundup-Issue-Status: chatting
840 X-Roundup-Issue-Files: unnamed
841 Content-Transfer-Encoding: quoted-printable
844 --utf-8
845 MIME-Version: 1.0
846 Content-Type: text/plain; charset="iso-8859-1"
847 Content-Transfer-Encoding: quoted-printable
850 Contrary, Mary <mary@test.test> added the comment:
852 umlaut =E4=F6=FC=C4=D6=DC=DF
854 ----------
855 status: unread -> chatting
857 _______________________________________________________________________
858 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
859 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
860 _______________________________________________________________________
861 --utf-8
862 Content-Type: text/html
863 MIME-Version: 1.0
864 Content-Transfer-Encoding: base64
865 Content-Disposition: attachment;
866 filename="unnamed"
868 PGh0bWw+dW1sYXV0IMOkw7bDvMOEw5bDnMOfPC9odG1sPgo=
870 --utf-8--
871 ''')
873 def testMultipartRFC822(self):
874 self.doNewIssue()
875 self._handle_mail(self.multipart_msg_rfc822)
876 messages = self.db.issue.get('1', 'messages')
877 messages.sort()
878 msg = self.db.msg.getnode (messages[-1])
879 assert(len(msg.files) == 1)
880 name = "Fwd: Original email subject.eml"
881 for n, id in enumerate (msg.files):
882 f = self.db.file.getnode (id)
883 self.assertEqual(f.name, name)
884 self.assertEqual(msg.content, 'First part: Text')
885 self.compareMessages(self._get_mail(),
886 '''TO: chef@bork.bork.bork, richard@test.test
887 Content-Type: text/plain; charset="utf-8"
888 Subject: [issue1] Testing...
889 To: chef@bork.bork.bork, richard@test.test
890 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
891 Reply-To: Roundup issue tracker
892 <issue_tracker@your.tracker.email.domain.example>
893 MIME-Version: 1.0
894 Message-Id: <followup_dummy_id>
895 In-Reply-To: <dummy_test_message_id>
896 X-Roundup-Name: Roundup issue tracker
897 X-Roundup-Loop: hello
898 X-Roundup-Issue-Status: chatting
899 X-Roundup-Issue-Files: Fwd: Original email subject.eml
900 Content-Transfer-Encoding: quoted-printable
903 --utf-8
904 MIME-Version: 1.0
905 Content-Type: text/plain; charset="utf-8"
906 Content-Transfer-Encoding: quoted-printable
909 Contrary, Mary <mary@test.test> added the comment:
911 First part: Text
913 ----------
914 status: unread -> chatting
916 _______________________________________________________________________
917 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
918 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
919 _______________________________________________________________________
920 --utf-8
921 Content-Type: message/rfc822
922 MIME-Version: 1.0
923 Content-Disposition: attachment;
924 filename="Fwd: Original email subject.eml"
926 Message-Id: <followup_dummy_id_2>
927 In-Reply-To: <dummy_test_message_id_2>
928 MIME-Version: 1.0
929 Subject: Fwd: Original email subject
930 Date: Mon, 23 Aug 2010 08:23:33 +0200
931 Content-Type: multipart/alternative; boundary="090500050101020406060002"
933 This is a multi-part message in MIME format.
934 --090500050101020406060002
935 Content-Type: text/plain; charset=ISO-8859-15; format=flowed
936 Content-Transfer-Encoding: 7bit
938 some text in inner email
939 ========================
941 --090500050101020406060002
942 Content-Type: text/html; charset=ISO-8859-15
943 Content-Transfer-Encoding: 7bit
945 <html>
946 some text in inner email
947 ========================
948 </html>
950 --090500050101020406060002--
952 --utf-8--
953 ''')
955 def testMultipartRFC822Unpack(self):
956 self.doNewIssue()
957 self.db.config.MAILGW_UNPACK_RFC822 = True
958 self._handle_mail(self.multipart_msg_rfc822)
959 messages = self.db.issue.get('1', 'messages')
960 messages.sort()
961 msg = self.db.msg.getnode (messages[-1])
962 self.assertEqual(len(msg.files), 2)
963 t = 'some text in inner email\n========================\n'
964 content = {0 : t, 1 : '<html>\n' + t + '</html>\n'}
965 for n, id in enumerate (msg.files):
966 f = self.db.file.getnode (id)
967 self.assertEqual(f.name, 'unnamed')
968 if n in content :
969 self.assertEqual(f.content, content [n])
970 self.assertEqual(msg.content, 'First part: Text')
972 def testSimpleFollowup(self):
973 self.doNewIssue()
974 self._handle_mail('''Content-Type: text/plain;
975 charset="iso-8859-1"
976 From: mary <mary@test.test>
977 To: issue_tracker@your.tracker.email.domain.example
978 Message-Id: <followup_dummy_id>
979 In-Reply-To: <dummy_test_message_id>
980 Subject: [issue1] Testing...
982 This is a second followup
983 ''')
984 self.compareMessages(self._get_mail(),
985 '''FROM: roundup-admin@your.tracker.email.domain.example
986 TO: chef@bork.bork.bork, richard@test.test
987 Content-Type: text/plain; charset="utf-8"
988 Subject: [issue1] Testing...
989 To: chef@bork.bork.bork, richard@test.test
990 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
991 Reply-To: Roundup issue tracker
992 <issue_tracker@your.tracker.email.domain.example>
993 MIME-Version: 1.0
994 Message-Id: <followup_dummy_id>
995 In-Reply-To: <dummy_test_message_id>
996 X-Roundup-Name: Roundup issue tracker
997 X-Roundup-Loop: hello
998 X-Roundup-Issue-Status: chatting
999 Content-Transfer-Encoding: quoted-printable
1002 Contrary, Mary <mary@test.test> added the comment:
1004 This is a second followup
1006 ----------
1007 status: unread -> chatting
1009 _______________________________________________________________________
1010 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1011 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1012 _______________________________________________________________________
1013 ''')
1015 def testFollowup(self):
1016 self.doNewIssue()
1018 self._handle_mail('''Content-Type: text/plain;
1019 charset="iso-8859-1"
1020 From: richard <richard@test.test>
1021 To: issue_tracker@your.tracker.email.domain.example
1022 Message-Id: <followup_dummy_id>
1023 In-Reply-To: <dummy_test_message_id>
1024 Subject: [issue1] Testing... [assignedto=mary; nosy=+john]
1026 This is a followup
1027 ''')
1028 l = self.db.issue.get('1', 'nosy')
1029 l.sort()
1030 self.assertEqual(l, [self.chef_id, self.richard_id, self.mary_id,
1031 self.john_id])
1033 self.compareMessages(self._get_mail(),
1034 '''FROM: roundup-admin@your.tracker.email.domain.example
1035 TO: chef@bork.bork.bork, john@test.test, mary@test.test
1036 Content-Type: text/plain; charset="utf-8"
1037 Subject: [issue1] Testing...
1038 To: chef@bork.bork.bork, john@test.test, mary@test.test
1039 From: richard <issue_tracker@your.tracker.email.domain.example>
1040 Reply-To: Roundup issue tracker
1041 <issue_tracker@your.tracker.email.domain.example>
1042 MIME-Version: 1.0
1043 Message-Id: <followup_dummy_id>
1044 In-Reply-To: <dummy_test_message_id>
1045 X-Roundup-Name: Roundup issue tracker
1046 X-Roundup-Loop: hello
1047 X-Roundup-Issue-Status: chatting
1048 Content-Transfer-Encoding: quoted-printable
1051 richard <richard@test.test> added the comment:
1053 This is a followup
1055 ----------
1056 assignedto: -> mary
1057 nosy: +john, mary
1058 status: unread -> chatting
1060 _______________________________________________________________________
1061 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1062 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1063 _______________________________________________________________________
1064 ''')
1066 def testFollowupNoSubjectChange(self):
1067 self.db.config.MAILGW_SUBJECT_UPDATES_TITLE = 'no'
1068 self.doNewIssue()
1070 self._handle_mail('''Content-Type: text/plain;
1071 charset="iso-8859-1"
1072 From: richard <richard@test.test>
1073 To: issue_tracker@your.tracker.email.domain.example
1074 Message-Id: <followup_dummy_id>
1075 In-Reply-To: <dummy_test_message_id>
1076 Subject: [issue1] Wrzlbrmft... [assignedto=mary; nosy=+john]
1078 This is a followup
1079 ''')
1080 l = self.db.issue.get('1', 'nosy')
1081 l.sort()
1082 self.assertEqual(l, [self.chef_id, self.richard_id, self.mary_id,
1083 self.john_id])
1085 self.compareMessages(self._get_mail(),
1086 '''FROM: roundup-admin@your.tracker.email.domain.example
1087 TO: chef@bork.bork.bork, john@test.test, mary@test.test
1088 Content-Type: text/plain; charset="utf-8"
1089 Subject: [issue1] Testing...
1090 To: chef@bork.bork.bork, john@test.test, mary@test.test
1091 From: richard <issue_tracker@your.tracker.email.domain.example>
1092 Reply-To: Roundup issue tracker
1093 <issue_tracker@your.tracker.email.domain.example>
1094 MIME-Version: 1.0
1095 Message-Id: <followup_dummy_id>
1096 In-Reply-To: <dummy_test_message_id>
1097 X-Roundup-Name: Roundup issue tracker
1098 X-Roundup-Loop: hello
1099 X-Roundup-Issue-Status: chatting
1100 Content-Transfer-Encoding: quoted-printable
1103 richard <richard@test.test> added the comment:
1105 This is a followup
1107 ----------
1108 assignedto: -> mary
1109 nosy: +john, mary
1110 status: unread -> chatting
1112 _______________________________________________________________________
1113 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1114 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1115 _______________________________________________________________________
1116 ''')
1117 self.assertEqual(self.db.issue.get('1','title'), 'Testing...')
1119 def testFollowupExplicitSubjectChange(self):
1120 self.doNewIssue()
1122 self._handle_mail('''Content-Type: text/plain;
1123 charset="iso-8859-1"
1124 From: richard <richard@test.test>
1125 To: issue_tracker@your.tracker.email.domain.example
1126 Message-Id: <followup_dummy_id>
1127 In-Reply-To: <dummy_test_message_id>
1128 Subject: [issue1] Wrzlbrmft... [assignedto=mary; nosy=+john; title=new title]
1130 This is a followup
1131 ''')
1132 l = self.db.issue.get('1', 'nosy')
1133 l.sort()
1134 self.assertEqual(l, [self.chef_id, self.richard_id, self.mary_id,
1135 self.john_id])
1137 self.compareMessages(self._get_mail(),
1138 '''FROM: roundup-admin@your.tracker.email.domain.example
1139 TO: chef@bork.bork.bork, john@test.test, mary@test.test
1140 Content-Type: text/plain; charset="utf-8"
1141 Subject: [issue1] new title
1142 To: chef@bork.bork.bork, john@test.test, mary@test.test
1143 From: richard <issue_tracker@your.tracker.email.domain.example>
1144 Reply-To: Roundup issue tracker
1145 <issue_tracker@your.tracker.email.domain.example>
1146 MIME-Version: 1.0
1147 Message-Id: <followup_dummy_id>
1148 In-Reply-To: <dummy_test_message_id>
1149 X-Roundup-Name: Roundup issue tracker
1150 X-Roundup-Loop: hello
1151 X-Roundup-Issue-Status: chatting
1152 Content-Transfer-Encoding: quoted-printable
1155 richard <richard@test.test> added the comment:
1157 This is a followup
1159 ----------
1160 assignedto: -> mary
1161 nosy: +john, mary
1162 status: unread -> chatting
1163 title: Testing... -> new title
1165 _______________________________________________________________________
1166 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1167 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1168 _______________________________________________________________________
1169 ''')
1171 def testNosyGeneration(self):
1172 self.db.issue.create(title='test')
1174 # create a nosy message
1175 msg = self.db.msg.create(content='This is a test',
1176 author=self.richard_id, messageid='<dummy_test_message_id>')
1177 self.db.journaltag = 'richard'
1178 l = self.db.issue.create(title='test', messages=[msg],
1179 nosy=[self.chef_id, self.mary_id, self.john_id])
1181 self.compareMessages(self._get_mail(),
1182 '''FROM: roundup-admin@your.tracker.email.domain.example
1183 TO: chef@bork.bork.bork, john@test.test, mary@test.test
1184 Content-Type: text/plain; charset="utf-8"
1185 Subject: [issue2] test
1186 To: chef@bork.bork.bork, john@test.test, mary@test.test
1187 From: richard <issue_tracker@your.tracker.email.domain.example>
1188 Reply-To: Roundup issue tracker
1189 <issue_tracker@your.tracker.email.domain.example>
1190 MIME-Version: 1.0
1191 Message-Id: <dummy_test_message_id>
1192 X-Roundup-Name: Roundup issue tracker
1193 X-Roundup-Loop: hello
1194 X-Roundup-Issue-Status: unread
1195 Content-Transfer-Encoding: quoted-printable
1198 New submission from richard <richard@test.test>:
1200 This is a test
1202 ----------
1203 messages: 1
1204 nosy: Chef, john, mary, richard
1205 status: unread
1206 title: test
1208 _______________________________________________________________________
1209 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1210 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue2>
1211 _______________________________________________________________________
1212 ''')
1214 def testPropertyChangeOnly(self):
1215 self.doNewIssue()
1216 oldvalues = self.db.getnode('issue', '1').copy()
1217 oldvalues['assignedto'] = None
1218 # reconstruct old behaviour: This would reuse the
1219 # database-handle from the doNewIssue above which has committed
1220 # as user "Chef". So we close and reopen the db as that user.
1221 #self.db.close() actually don't close 'cos this empties memorydb
1222 self.db = self.instance.open('Chef')
1223 self.db.issue.set('1', assignedto=self.chef_id)
1224 self.db.commit()
1225 self.db.issue.nosymessage('1', None, oldvalues)
1227 new_mail = ""
1228 for line in self._get_mail().split("\n"):
1229 if "Message-Id: " in line:
1230 continue
1231 if "Date: " in line:
1232 continue
1233 new_mail += line+"\n"
1235 self.compareMessages(new_mail, """
1236 FROM: roundup-admin@your.tracker.email.domain.example
1237 TO: chef@bork.bork.bork, richard@test.test
1238 Content-Type: text/plain; charset="utf-8"
1239 Subject: [issue1] Testing...
1240 To: chef@bork.bork.bork, richard@test.test
1241 From: "Bork, Chef" <issue_tracker@your.tracker.email.domain.example>
1242 X-Roundup-Name: Roundup issue tracker
1243 X-Roundup-Loop: hello
1244 X-Roundup-Issue-Status: unread
1245 X-Roundup-Version: 1.3.3
1246 In-Reply-To: <dummy_test_message_id>
1247 MIME-Version: 1.0
1248 Reply-To: Roundup issue tracker
1249 <issue_tracker@your.tracker.email.domain.example>
1250 Content-Transfer-Encoding: quoted-printable
1253 Change by Bork, Chef <chef@bork.bork.bork>:
1256 ----------
1257 assignedto: -> Chef
1259 _______________________________________________________________________
1260 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1261 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1262 _______________________________________________________________________
1263 """)
1266 #
1267 # FOLLOWUP TITLE MATCH
1268 #
1269 def testFollowupTitleMatch(self):
1270 self.doNewIssue()
1271 self._handle_mail('''Content-Type: text/plain;
1272 charset="iso-8859-1"
1273 From: richard <richard@test.test>
1274 To: issue_tracker@your.tracker.email.domain.example
1275 Message-Id: <followup_dummy_id>
1276 Subject: Re: Testing... [assignedto=mary; nosy=+john]
1278 This is a followup
1279 ''')
1280 self.compareMessages(self._get_mail(),
1281 '''FROM: roundup-admin@your.tracker.email.domain.example
1282 TO: chef@bork.bork.bork, john@test.test, mary@test.test
1283 Content-Type: text/plain; charset="utf-8"
1284 Subject: [issue1] Testing...
1285 To: chef@bork.bork.bork, john@test.test, mary@test.test
1286 From: richard <issue_tracker@your.tracker.email.domain.example>
1287 Reply-To: Roundup issue tracker
1288 <issue_tracker@your.tracker.email.domain.example>
1289 MIME-Version: 1.0
1290 Message-Id: <followup_dummy_id>
1291 In-Reply-To: <dummy_test_message_id>
1292 X-Roundup-Name: Roundup issue tracker
1293 X-Roundup-Loop: hello
1294 X-Roundup-Issue-Status: chatting
1295 Content-Transfer-Encoding: quoted-printable
1298 richard <richard@test.test> added the comment:
1300 This is a followup
1302 ----------
1303 assignedto: -> mary
1304 nosy: +john, mary
1305 status: unread -> chatting
1307 _______________________________________________________________________
1308 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1309 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1310 _______________________________________________________________________
1311 ''')
1313 def testFollowupTitleMatchMultiRe(self):
1314 nodeid1 = self.doNewIssue()
1315 nodeid2 = self._handle_mail('''Content-Type: text/plain;
1316 charset="iso-8859-1"
1317 From: richard <richard@test.test>
1318 To: issue_tracker@your.tracker.email.domain.example
1319 Message-Id: <followup_dummy_id>
1320 Subject: Re: Testing... [assignedto=mary; nosy=+john]
1322 This is a followup
1323 ''')
1325 nodeid3 = self._handle_mail('''Content-Type: text/plain;
1326 charset="iso-8859-1"
1327 From: richard <richard@test.test>
1328 To: issue_tracker@your.tracker.email.domain.example
1329 Message-Id: <followup2_dummy_id>
1330 Subject: Ang: Re: Testing...
1332 This is a followup
1333 ''')
1334 self.assertEqual(nodeid1, nodeid2)
1335 self.assertEqual(nodeid1, nodeid3)
1337 def testFollowupTitleMatchNever(self):
1338 nodeid = self.doNewIssue()
1339 self.db.config.MAILGW_SUBJECT_CONTENT_MATCH = 'never'
1340 self.assertNotEqual(self._handle_mail('''Content-Type: text/plain;
1341 charset="iso-8859-1"
1342 From: richard <richard@test.test>
1343 To: issue_tracker@your.tracker.email.domain.example
1344 Message-Id: <followup_dummy_id>
1345 Subject: Re: Testing...
1347 This is a followup
1348 '''), nodeid)
1350 def testFollowupTitleMatchNeverInterval(self):
1351 nodeid = self.doNewIssue()
1352 # force failure of the interval
1353 time.sleep(2)
1354 self.db.config.MAILGW_SUBJECT_CONTENT_MATCH = 'creation 00:00:01'
1355 self.assertNotEqual(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 testFollowupTitleMatchInterval(self):
1367 nodeid = self.doNewIssue()
1368 self.db.config.MAILGW_SUBJECT_CONTENT_MATCH = 'creation +1d'
1369 self.assertEqual(self._handle_mail('''Content-Type: text/plain;
1370 charset="iso-8859-1"
1371 From: richard <richard@test.test>
1372 To: issue_tracker@your.tracker.email.domain.example
1373 Message-Id: <followup_dummy_id>
1374 Subject: Re: Testing...
1376 This is a followup
1377 '''), nodeid)
1380 def testFollowupNosyAuthor(self):
1381 self.doNewIssue()
1382 self.db.config.ADD_AUTHOR_TO_NOSY = 'yes'
1383 self._handle_mail('''Content-Type: text/plain;
1384 charset="iso-8859-1"
1385 From: john@test.test
1386 To: issue_tracker@your.tracker.email.domain.example
1387 Message-Id: <followup_dummy_id>
1388 In-Reply-To: <dummy_test_message_id>
1389 Subject: [issue1] Testing...
1391 This is a followup
1392 ''')
1394 self.compareMessages(self._get_mail(),
1395 '''FROM: roundup-admin@your.tracker.email.domain.example
1396 TO: chef@bork.bork.bork, richard@test.test
1397 Content-Type: text/plain; charset="utf-8"
1398 Subject: [issue1] Testing...
1399 To: chef@bork.bork.bork, richard@test.test
1400 From: John Doe <issue_tracker@your.tracker.email.domain.example>
1401 Reply-To: Roundup issue tracker
1402 <issue_tracker@your.tracker.email.domain.example>
1403 MIME-Version: 1.0
1404 Message-Id: <followup_dummy_id>
1405 In-Reply-To: <dummy_test_message_id>
1406 X-Roundup-Name: Roundup issue tracker
1407 X-Roundup-Loop: hello
1408 X-Roundup-Issue-Status: chatting
1409 Content-Transfer-Encoding: quoted-printable
1412 John Doe <john@test.test> added the comment:
1414 This is a followup
1416 ----------
1417 nosy: +john
1418 status: unread -> chatting
1420 _______________________________________________________________________
1421 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1422 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1423 _______________________________________________________________________
1425 ''')
1427 def testFollowupNosyRecipients(self):
1428 self.doNewIssue()
1429 self.db.config.ADD_RECIPIENTS_TO_NOSY = 'yes'
1430 self._handle_mail('''Content-Type: text/plain;
1431 charset="iso-8859-1"
1432 From: richard@test.test
1433 To: issue_tracker@your.tracker.email.domain.example
1434 Cc: john@test.test
1435 Message-Id: <followup_dummy_id>
1436 In-Reply-To: <dummy_test_message_id>
1437 Subject: [issue1] Testing...
1439 This is a followup
1440 ''')
1441 self.compareMessages(self._get_mail(),
1442 '''FROM: roundup-admin@your.tracker.email.domain.example
1443 TO: chef@bork.bork.bork
1444 Content-Type: text/plain; charset="utf-8"
1445 Subject: [issue1] Testing...
1446 To: chef@bork.bork.bork
1447 From: richard <issue_tracker@your.tracker.email.domain.example>
1448 Reply-To: Roundup issue tracker
1449 <issue_tracker@your.tracker.email.domain.example>
1450 MIME-Version: 1.0
1451 Message-Id: <followup_dummy_id>
1452 In-Reply-To: <dummy_test_message_id>
1453 X-Roundup-Name: Roundup issue tracker
1454 X-Roundup-Loop: hello
1455 X-Roundup-Issue-Status: chatting
1456 Content-Transfer-Encoding: quoted-printable
1459 richard <richard@test.test> added the comment:
1461 This is a followup
1463 ----------
1464 nosy: +john
1465 status: unread -> chatting
1467 _______________________________________________________________________
1468 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1469 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1470 _______________________________________________________________________
1472 ''')
1474 def testFollowupNosyAuthorAndCopy(self):
1475 self.doNewIssue()
1476 self.db.config.ADD_AUTHOR_TO_NOSY = 'yes'
1477 self.db.config.MESSAGES_TO_AUTHOR = 'yes'
1478 self._handle_mail('''Content-Type: text/plain;
1479 charset="iso-8859-1"
1480 From: john@test.test
1481 To: issue_tracker@your.tracker.email.domain.example
1482 Message-Id: <followup_dummy_id>
1483 In-Reply-To: <dummy_test_message_id>
1484 Subject: [issue1] Testing...
1486 This is a followup
1487 ''')
1488 self.compareMessages(self._get_mail(),
1489 '''FROM: roundup-admin@your.tracker.email.domain.example
1490 TO: chef@bork.bork.bork, john@test.test, richard@test.test
1491 Content-Type: text/plain; charset="utf-8"
1492 Subject: [issue1] Testing...
1493 To: chef@bork.bork.bork, john@test.test, richard@test.test
1494 From: John Doe <issue_tracker@your.tracker.email.domain.example>
1495 Reply-To: Roundup issue tracker
1496 <issue_tracker@your.tracker.email.domain.example>
1497 MIME-Version: 1.0
1498 Message-Id: <followup_dummy_id>
1499 In-Reply-To: <dummy_test_message_id>
1500 X-Roundup-Name: Roundup issue tracker
1501 X-Roundup-Loop: hello
1502 X-Roundup-Issue-Status: chatting
1503 Content-Transfer-Encoding: quoted-printable
1506 John Doe <john@test.test> added the comment:
1508 This is a followup
1510 ----------
1511 nosy: +john
1512 status: unread -> chatting
1514 _______________________________________________________________________
1515 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1516 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1517 _______________________________________________________________________
1519 ''')
1521 def testFollowupNoNosyAuthor(self):
1522 self.doNewIssue()
1523 self.instance.config.ADD_AUTHOR_TO_NOSY = 'no'
1524 self._handle_mail('''Content-Type: text/plain;
1525 charset="iso-8859-1"
1526 From: john@test.test
1527 To: issue_tracker@your.tracker.email.domain.example
1528 Message-Id: <followup_dummy_id>
1529 In-Reply-To: <dummy_test_message_id>
1530 Subject: [issue1] Testing...
1532 This is a followup
1533 ''')
1534 self.compareMessages(self._get_mail(),
1535 '''FROM: roundup-admin@your.tracker.email.domain.example
1536 TO: chef@bork.bork.bork, richard@test.test
1537 Content-Type: text/plain; charset="utf-8"
1538 Subject: [issue1] Testing...
1539 To: chef@bork.bork.bork, richard@test.test
1540 From: John Doe <issue_tracker@your.tracker.email.domain.example>
1541 Reply-To: Roundup issue tracker
1542 <issue_tracker@your.tracker.email.domain.example>
1543 MIME-Version: 1.0
1544 Message-Id: <followup_dummy_id>
1545 In-Reply-To: <dummy_test_message_id>
1546 X-Roundup-Name: Roundup issue tracker
1547 X-Roundup-Loop: hello
1548 X-Roundup-Issue-Status: chatting
1549 Content-Transfer-Encoding: quoted-printable
1552 John Doe <john@test.test> added the comment:
1554 This is a followup
1556 ----------
1557 status: unread -> chatting
1559 _______________________________________________________________________
1560 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1561 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1562 _______________________________________________________________________
1564 ''')
1566 def testFollowupNoNosyRecipients(self):
1567 self.doNewIssue()
1568 self.instance.config.ADD_RECIPIENTS_TO_NOSY = 'no'
1569 self._handle_mail('''Content-Type: text/plain;
1570 charset="iso-8859-1"
1571 From: richard@test.test
1572 To: issue_tracker@your.tracker.email.domain.example
1573 Cc: john@test.test
1574 Message-Id: <followup_dummy_id>
1575 In-Reply-To: <dummy_test_message_id>
1576 Subject: [issue1] Testing...
1578 This is a followup
1579 ''')
1580 self.compareMessages(self._get_mail(),
1581 '''FROM: roundup-admin@your.tracker.email.domain.example
1582 TO: chef@bork.bork.bork
1583 Content-Type: text/plain; charset="utf-8"
1584 Subject: [issue1] Testing...
1585 To: chef@bork.bork.bork
1586 From: richard <issue_tracker@your.tracker.email.domain.example>
1587 Reply-To: Roundup issue tracker
1588 <issue_tracker@your.tracker.email.domain.example>
1589 MIME-Version: 1.0
1590 Message-Id: <followup_dummy_id>
1591 In-Reply-To: <dummy_test_message_id>
1592 X-Roundup-Name: Roundup issue tracker
1593 X-Roundup-Loop: hello
1594 X-Roundup-Issue-Status: chatting
1595 Content-Transfer-Encoding: quoted-printable
1598 richard <richard@test.test> added the comment:
1600 This is a followup
1602 ----------
1603 status: unread -> chatting
1605 _______________________________________________________________________
1606 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1607 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1608 _______________________________________________________________________
1610 ''')
1612 def testFollowupEmptyMessage(self):
1613 self.doNewIssue()
1615 self._handle_mail('''Content-Type: text/plain;
1616 charset="iso-8859-1"
1617 From: richard <richard@test.test>
1618 To: issue_tracker@your.tracker.email.domain.example
1619 Message-Id: <followup_dummy_id>
1620 In-Reply-To: <dummy_test_message_id>
1621 Subject: [issue1] Testing... [assignedto=mary; nosy=+john]
1623 ''')
1624 l = self.db.issue.get('1', 'nosy')
1625 l.sort()
1626 self.assertEqual(l, [self.chef_id, self.richard_id, self.mary_id,
1627 self.john_id])
1629 # should be no file created (ie. no message)
1630 assert not os.path.exists(SENDMAILDEBUG)
1632 def testFollowupEmptyMessageNoSubject(self):
1633 self.doNewIssue()
1635 self._handle_mail('''Content-Type: text/plain;
1636 charset="iso-8859-1"
1637 From: richard <richard@test.test>
1638 To: issue_tracker@your.tracker.email.domain.example
1639 Message-Id: <followup_dummy_id>
1640 In-Reply-To: <dummy_test_message_id>
1641 Subject: [issue1] [assignedto=mary; nosy=+john]
1643 ''')
1644 l = self.db.issue.get('1', 'nosy')
1645 l.sort()
1646 self.assertEqual(l, [self.chef_id, self.richard_id, self.mary_id,
1647 self.john_id])
1649 # should be no file created (ie. no message)
1650 assert not os.path.exists(SENDMAILDEBUG)
1652 def testNosyRemove(self):
1653 self.doNewIssue()
1655 self._handle_mail('''Content-Type: text/plain;
1656 charset="iso-8859-1"
1657 From: richard <richard@test.test>
1658 To: issue_tracker@your.tracker.email.domain.example
1659 Message-Id: <followup_dummy_id>
1660 In-Reply-To: <dummy_test_message_id>
1661 Subject: [issue1] Testing... [nosy=-richard]
1663 ''')
1664 l = self.db.issue.get('1', 'nosy')
1665 l.sort()
1666 self.assertEqual(l, [self.chef_id])
1668 # NO NOSY MESSAGE SHOULD BE SENT!
1669 assert not os.path.exists(SENDMAILDEBUG)
1671 def testNewUserAuthor(self):
1672 self.db.commit()
1673 l = self.db.user.list()
1674 l.sort()
1675 message = '''Content-Type: text/plain;
1676 charset="iso-8859-1"
1677 From: fubar <fubar@bork.bork.bork>
1678 To: issue_tracker@your.tracker.email.domain.example
1679 Message-Id: <dummy_test_message_id>
1680 Subject: [issue] Testing...
1682 This is a test submission of a new issue.
1683 '''
1684 self.db.security.role['anonymous'].permissions=[]
1685 anonid = self.db.user.lookup('anonymous')
1686 self.db.user.set(anonid, roles='Anonymous')
1687 try:
1688 self._handle_mail(message)
1689 except Unauthorized, value:
1690 body_diff = self.compareMessages(str(value), """
1691 You are not a registered user.
1693 Unknown address: fubar@bork.bork.bork
1694 """)
1695 assert not body_diff, body_diff
1696 else:
1697 raise AssertionError, "Unathorized not raised when handling mail"
1699 # Add Web Access role to anonymous, and try again to make sure
1700 # we get a "please register at:" message this time.
1701 p = [
1702 self.db.security.getPermission('Register', 'user'),
1703 self.db.security.getPermission('Web Access', None),
1704 ]
1705 self.db.security.role['anonymous'].permissions=p
1706 try:
1707 self._handle_mail(message)
1708 except Unauthorized, value:
1709 body_diff = self.compareMessages(str(value), """
1710 You are not a registered user. Please register at:
1712 http://tracker.example/cgi-bin/roundup.cgi/bugs/user?template=register
1714 ...before sending mail to the tracker.
1716 Unknown address: fubar@bork.bork.bork
1717 """)
1718 assert not body_diff, body_diff
1719 else:
1720 raise AssertionError, "Unathorized not raised when handling mail"
1722 # Make sure list of users is the same as before.
1723 m = self.db.user.list()
1724 m.sort()
1725 self.assertEqual(l, m)
1727 # now with the permission
1728 p = [
1729 self.db.security.getPermission('Register', 'user'),
1730 self.db.security.getPermission('Email Access', None),
1731 ]
1732 self.db.security.role['anonymous'].permissions=p
1733 self._handle_mail(message)
1734 m = self.db.user.list()
1735 m.sort()
1736 self.assertNotEqual(l, m)
1738 def testNewUserAuthorEncodedName(self):
1739 l = set(self.db.user.list())
1740 # From: name has Euro symbol in it
1741 message = '''Content-Type: text/plain;
1742 charset="iso-8859-1"
1743 From: =?utf8?b?SOKCrGxsbw==?= <fubar@bork.bork.bork>
1744 To: issue_tracker@your.tracker.email.domain.example
1745 Message-Id: <dummy_test_message_id>
1746 Subject: [issue] Testing...
1748 This is a test submission of a new issue.
1749 '''
1750 p = [
1751 self.db.security.getPermission('Register', 'user'),
1752 self.db.security.getPermission('Email Access', None),
1753 self.db.security.getPermission('Create', 'issue'),
1754 self.db.security.getPermission('Create', 'msg'),
1755 ]
1756 self.db.security.role['anonymous'].permissions = p
1757 self._handle_mail(message)
1758 m = set(self.db.user.list())
1759 new = list(m - l)[0]
1760 name = self.db.user.get(new, 'realname')
1761 self.assertEquals(name, 'H€llo')
1763 def testUnknownUser(self):
1764 l = set(self.db.user.list())
1765 message = '''Content-Type: text/plain;
1766 charset="iso-8859-1"
1767 From: Nonexisting User <nonexisting@bork.bork.bork>
1768 To: issue_tracker@your.tracker.email.domain.example
1769 Message-Id: <dummy_test_message_id>
1770 Subject: [issue] Testing nonexisting user...
1772 This is a test submission of a new issue.
1773 '''
1774 handler = self._create_mailgw(message)
1775 # we want a bounce message:
1776 handler.trapExceptions = 1
1777 ret = handler.main(StringIO(message))
1778 self.compareMessages(self._get_mail(),
1779 '''FROM: Roundup issue tracker <roundup-admin@your.tracker.email.domain.example>
1780 TO: nonexisting@bork.bork.bork
1781 From nobody Tue Jul 14 12:04:11 2009
1782 Content-Type: multipart/mixed; boundary="===============0639262320=="
1783 MIME-Version: 1.0
1784 Subject: Failed issue tracker submission
1785 To: nonexisting@bork.bork.bork
1786 From: Roundup issue tracker <roundup-admin@your.tracker.email.domain.example>
1787 Date: Tue, 14 Jul 2009 12:04:11 +0000
1788 Precedence: bulk
1789 X-Roundup-Name: Roundup issue tracker
1790 X-Roundup-Loop: hello
1791 X-Roundup-Version: 1.4.8
1792 MIME-Version: 1.0
1794 --===============0639262320==
1795 Content-Type: text/plain; charset="us-ascii"
1796 MIME-Version: 1.0
1797 Content-Transfer-Encoding: 7bit
1801 You are not a registered user. Please register at:
1803 http://tracker.example/cgi-bin/roundup.cgi/bugs/user?template=register
1805 ...before sending mail to the tracker.
1807 Unknown address: nonexisting@bork.bork.bork
1809 --===============0639262320==
1810 Content-Type: text/plain; charset="us-ascii"
1811 MIME-Version: 1.0
1812 Content-Transfer-Encoding: 7bit
1814 Content-Type: text/plain;
1815 charset="iso-8859-1"
1816 From: Nonexisting User <nonexisting@bork.bork.bork>
1817 To: issue_tracker@your.tracker.email.domain.example
1818 Message-Id: <dummy_test_message_id>
1819 Subject: [issue] Testing nonexisting user...
1821 This is a test submission of a new issue.
1823 --===============0639262320==--
1824 ''')
1826 def testEnc01(self):
1827 self.db.user.set(self.mary_id,
1828 realname='\xe4\xf6\xfc\xc4\xd6\xdc\xdf, Mary'.decode
1829 ('latin-1').encode('utf-8'))
1830 self.doNewIssue()
1831 self._handle_mail('''Content-Type: text/plain;
1832 charset="iso-8859-1"
1833 From: mary <mary@test.test>
1834 To: issue_tracker@your.tracker.email.domain.example
1835 Message-Id: <followup_dummy_id>
1836 In-Reply-To: <dummy_test_message_id>
1837 Subject: [issue1] Testing...
1838 Content-Type: text/plain;
1839 charset="iso-8859-1"
1840 Content-Transfer-Encoding: quoted-printable
1842 A message with encoding (encoded oe =F6)
1844 ''')
1845 self.compareMessages(self._get_mail(),
1846 '''FROM: roundup-admin@your.tracker.email.domain.example
1847 TO: chef@bork.bork.bork, richard@test.test
1848 Content-Type: text/plain; charset="utf-8"
1849 Subject: [issue1] Testing...
1850 To: chef@bork.bork.bork, richard@test.test
1851 From: =?utf-8?b?w6TDtsO8w4TDlsOcw58sIE1hcnk=?=
1852 <issue_tracker@your.tracker.email.domain.example>
1853 Reply-To: Roundup issue tracker
1854 <issue_tracker@your.tracker.email.domain.example>
1855 MIME-Version: 1.0
1856 Message-Id: <followup_dummy_id>
1857 In-Reply-To: <dummy_test_message_id>
1858 X-Roundup-Name: Roundup issue tracker
1859 X-Roundup-Loop: hello
1860 X-Roundup-Issue-Status: chatting
1861 Content-Transfer-Encoding: quoted-printable
1864 =C3=A4=C3=B6=C3=BC=C3=84=C3=96=C3=9C=C3=9F, Mary <mary@test.test> added the=
1865 comment:
1867 A message with encoding (encoded oe =C3=B6)
1869 ----------
1870 status: unread -> chatting
1872 _______________________________________________________________________
1873 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1874 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1875 _______________________________________________________________________
1876 ''')
1878 def testEncNonUTF8(self):
1879 self.doNewIssue()
1880 self.instance.config.EMAIL_CHARSET = 'iso-8859-1'
1881 self._handle_mail('''Content-Type: text/plain;
1882 charset="iso-8859-1"
1883 From: mary <mary@test.test>
1884 To: issue_tracker@your.tracker.email.domain.example
1885 Message-Id: <followup_dummy_id>
1886 In-Reply-To: <dummy_test_message_id>
1887 Subject: [issue1] Testing...
1888 Content-Type: text/plain;
1889 charset="iso-8859-1"
1890 Content-Transfer-Encoding: quoted-printable
1892 A message with encoding (encoded oe =F6)
1894 ''')
1895 self.compareMessages(self._get_mail(),
1896 '''FROM: roundup-admin@your.tracker.email.domain.example
1897 TO: chef@bork.bork.bork, richard@test.test
1898 Content-Type: text/plain; charset="iso-8859-1"
1899 Subject: [issue1] Testing...
1900 To: chef@bork.bork.bork, richard@test.test
1901 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
1902 Reply-To: Roundup issue tracker
1903 <issue_tracker@your.tracker.email.domain.example>
1904 MIME-Version: 1.0
1905 Message-Id: <followup_dummy_id>
1906 In-Reply-To: <dummy_test_message_id>
1907 X-Roundup-Name: Roundup issue tracker
1908 X-Roundup-Loop: hello
1909 X-Roundup-Issue-Status: chatting
1910 Content-Transfer-Encoding: quoted-printable
1913 Contrary, Mary <mary@test.test> added the comment:
1915 A message with encoding (encoded oe =F6)
1917 ----------
1918 status: unread -> chatting
1920 _______________________________________________________________________
1921 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1922 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1923 _______________________________________________________________________
1924 ''')
1927 def testMultipartEnc01(self):
1928 self.doNewIssue()
1929 self._handle_mail('''Content-Type: text/plain;
1930 charset="iso-8859-1"
1931 From: mary <mary@test.test>
1932 To: issue_tracker@your.tracker.email.domain.example
1933 Message-Id: <followup_dummy_id>
1934 In-Reply-To: <dummy_test_message_id>
1935 Subject: [issue1] Testing...
1936 Content-Type: multipart/mixed;
1937 boundary="----_=_NextPart_000_01"
1939 This message is in MIME format. Since your mail reader does not understand
1940 this format, some or all of this message may not be legible.
1942 ------_=_NextPart_000_01
1943 Content-Type: text/plain;
1944 charset="iso-8859-1"
1945 Content-Transfer-Encoding: quoted-printable
1947 A message with first part encoded (encoded oe =F6)
1949 ''')
1950 self.compareMessages(self._get_mail(),
1951 '''FROM: roundup-admin@your.tracker.email.domain.example
1952 TO: chef@bork.bork.bork, richard@test.test
1953 Content-Type: text/plain; charset="utf-8"
1954 Subject: [issue1] Testing...
1955 To: chef@bork.bork.bork, richard@test.test
1956 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
1957 Reply-To: Roundup issue tracker
1958 <issue_tracker@your.tracker.email.domain.example>
1959 MIME-Version: 1.0
1960 Message-Id: <followup_dummy_id>
1961 In-Reply-To: <dummy_test_message_id>
1962 X-Roundup-Name: Roundup issue tracker
1963 X-Roundup-Loop: hello
1964 X-Roundup-Issue-Status: chatting
1965 Content-Transfer-Encoding: quoted-printable
1968 Contrary, Mary <mary@test.test> added the comment:
1970 A message with first part encoded (encoded oe =C3=B6)
1972 ----------
1973 status: unread -> chatting
1975 _______________________________________________________________________
1976 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1977 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1978 _______________________________________________________________________
1979 ''')
1981 def testContentDisposition(self):
1982 self.doNewIssue()
1983 self._handle_mail('''Content-Type: text/plain;
1984 charset="iso-8859-1"
1985 From: mary <mary@test.test>
1986 To: issue_tracker@your.tracker.email.domain.example
1987 Message-Id: <followup_dummy_id>
1988 In-Reply-To: <dummy_test_message_id>
1989 Subject: [issue1] Testing...
1990 Content-Type: multipart/mixed; boundary="bCsyhTFzCvuiizWE"
1991 Content-Disposition: inline
1994 --bCsyhTFzCvuiizWE
1995 Content-Type: text/plain; charset=us-ascii
1996 Content-Disposition: inline
1998 test attachment binary
2000 --bCsyhTFzCvuiizWE
2001 Content-Type: application/octet-stream
2002 Content-Disposition: attachment; filename="main.dvi"
2003 Content-Transfer-Encoding: base64
2005 SnVzdCBhIHRlc3QgAQo=
2007 --bCsyhTFzCvuiizWE--
2008 ''')
2009 messages = self.db.issue.get('1', 'messages')
2010 messages.sort()
2011 file = self.db.file.getnode (self.db.msg.get(messages[-1], 'files')[0])
2012 self.assertEqual(file.name, 'main.dvi')
2013 self.assertEqual(file.content, 'Just a test \001\n')
2015 def testFollowupStupidQuoting(self):
2016 self.doNewIssue()
2018 self._handle_mail('''Content-Type: text/plain;
2019 charset="iso-8859-1"
2020 From: richard <richard@test.test>
2021 To: issue_tracker@your.tracker.email.domain.example
2022 Message-Id: <followup_dummy_id>
2023 In-Reply-To: <dummy_test_message_id>
2024 Subject: Re: "[issue1] Testing... "
2026 This is a followup
2027 ''')
2028 self.compareMessages(self._get_mail(),
2029 '''FROM: roundup-admin@your.tracker.email.domain.example
2030 TO: chef@bork.bork.bork
2031 Content-Type: text/plain; charset="utf-8"
2032 Subject: [issue1] Testing...
2033 To: chef@bork.bork.bork
2034 From: richard <issue_tracker@your.tracker.email.domain.example>
2035 Reply-To: Roundup issue tracker
2036 <issue_tracker@your.tracker.email.domain.example>
2037 MIME-Version: 1.0
2038 Message-Id: <followup_dummy_id>
2039 In-Reply-To: <dummy_test_message_id>
2040 X-Roundup-Name: Roundup issue tracker
2041 X-Roundup-Loop: hello
2042 X-Roundup-Issue-Status: chatting
2043 Content-Transfer-Encoding: quoted-printable
2046 richard <richard@test.test> added the comment:
2048 This is a followup
2050 ----------
2051 status: unread -> chatting
2053 _______________________________________________________________________
2054 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
2055 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
2056 _______________________________________________________________________
2057 ''')
2059 def testEmailQuoting(self):
2060 self.instance.config.EMAIL_KEEP_QUOTED_TEXT = 'no'
2061 self.innerTestQuoting('''This is a followup
2062 ''')
2064 def testEmailQuotingRemove(self):
2065 self.instance.config.EMAIL_KEEP_QUOTED_TEXT = 'yes'
2066 self.innerTestQuoting('''Blah blah wrote:
2067 > Blah bklaskdfj sdf asdf jlaskdf skj sdkfjl asdf
2068 > skdjlkjsdfalsdkfjasdlfkj dlfksdfalksd fj
2069 >
2071 This is a followup
2072 ''')
2074 def innerTestQuoting(self, expect):
2075 nodeid = self.doNewIssue()
2077 messages = self.db.issue.get(nodeid, 'messages')
2079 self._handle_mail('''Content-Type: text/plain;
2080 charset="iso-8859-1"
2081 From: richard <richard@test.test>
2082 To: issue_tracker@your.tracker.email.domain.example
2083 Message-Id: <followup_dummy_id>
2084 In-Reply-To: <dummy_test_message_id>
2085 Subject: Re: [issue1] Testing...
2087 Blah blah wrote:
2088 > Blah bklaskdfj sdf asdf jlaskdf skj sdkfjl asdf
2089 > skdjlkjsdfalsdkfjasdlfkj dlfksdfalksd fj
2090 >
2092 This is a followup
2093 ''')
2094 # figure the new message id
2095 newmessages = self.db.issue.get(nodeid, 'messages')
2096 for msg in messages:
2097 newmessages.remove(msg)
2098 messageid = newmessages[0]
2100 self.compareMessages(self.db.msg.get(messageid, 'content'), expect)
2102 def testUserLookup(self):
2103 i = self.db.user.create(username='user1', address='user1@foo.com')
2104 self.assertEqual(uidFromAddress(self.db, ('', 'user1@foo.com'), 0), i)
2105 self.assertEqual(uidFromAddress(self.db, ('', 'USER1@foo.com'), 0), i)
2106 i = self.db.user.create(username='user2', address='USER2@foo.com')
2107 self.assertEqual(uidFromAddress(self.db, ('', 'USER2@foo.com'), 0), i)
2108 self.assertEqual(uidFromAddress(self.db, ('', 'user2@foo.com'), 0), i)
2110 def testUserAlternateLookup(self):
2111 i = self.db.user.create(username='user1', address='user1@foo.com',
2112 alternate_addresses='user1@bar.com')
2113 self.assertEqual(uidFromAddress(self.db, ('', 'user1@bar.com'), 0), i)
2114 self.assertEqual(uidFromAddress(self.db, ('', 'USER1@bar.com'), 0), i)
2116 def testUserCreate(self):
2117 i = uidFromAddress(self.db, ('', 'user@foo.com'), 1)
2118 self.assertNotEqual(uidFromAddress(self.db, ('', 'user@bar.com'), 1), i)
2120 def testRFC2822(self):
2121 ascii_header = "[issue243] This is a \"test\" - with 'quotation' marks"
2122 unicode_header = '[issue244] \xd0\xb0\xd0\xbd\xd0\xb4\xd1\x80\xd0\xb5\xd0\xb9'
2123 unicode_encoded = '=?utf-8?q?[issue244]_=D0=B0=D0=BD=D0=B4=D1=80=D0=B5=D0=B9?='
2124 self.assertEqual(rfc2822.encode_header(ascii_header), ascii_header)
2125 self.assertEqual(rfc2822.encode_header(unicode_header), unicode_encoded)
2127 def testRegistrationConfirmation(self):
2128 otk = "Aj4euk4LZSAdwePohj90SME5SpopLETL"
2129 self.db.getOTKManager().set(otk, username='johannes')
2130 self._handle_mail('''Content-Type: text/plain;
2131 charset="iso-8859-1"
2132 From: Chef <chef@bork.bork.bork>
2133 To: issue_tracker@your.tracker.email.domain.example
2134 Cc: richard@test.test
2135 Message-Id: <dummy_test_message_id>
2136 Subject: Re: Complete your registration to Roundup issue tracker
2137 -- key %s
2139 This is a test confirmation of registration.
2140 ''' % otk)
2141 self.db.user.lookup('johannes')
2143 def testFollowupOnNonIssue(self):
2144 self.db.keyword.create(name='Foo')
2145 self._handle_mail('''Content-Type: text/plain;
2146 charset="iso-8859-1"
2147 From: richard <richard@test.test>
2148 To: issue_tracker@your.tracker.email.domain.example
2149 Message-Id: <followup_dummy_id>
2150 In-Reply-To: <dummy_test_message_id>
2151 Subject: [keyword1] Testing... [name=Bar]
2153 ''')
2154 self.assertEqual(self.db.keyword.get('1', 'name'), 'Bar')
2156 def testResentFrom(self):
2157 nodeid = self._handle_mail('''Content-Type: text/plain;
2158 charset="iso-8859-1"
2159 From: Chef <chef@bork.bork.bork>
2160 Resent-From: mary <mary@test.test>
2161 To: issue_tracker@your.tracker.email.domain.example
2162 Cc: richard@test.test
2163 Message-Id: <dummy_test_message_id>
2164 Subject: [issue] Testing...
2166 This is a test submission of a new issue.
2167 ''')
2168 assert not os.path.exists(SENDMAILDEBUG)
2169 l = self.db.issue.get(nodeid, 'nosy')
2170 l.sort()
2171 self.assertEqual(l, [self.richard_id, self.mary_id])
2172 return nodeid
2174 def testDejaVu(self):
2175 self.assertRaises(IgnoreLoop, self._handle_mail,
2176 '''Content-Type: text/plain;
2177 charset="iso-8859-1"
2178 From: Chef <chef@bork.bork.bork>
2179 X-Roundup-Loop: hello
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've been mis-configured to loop messages back to myself.
2186 ''')
2188 def testItsBulkStupid(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 Precedence: bulk
2194 To: issue_tracker@your.tracker.email.domain.example
2195 Cc: richard@test.test
2196 Message-Id: <dummy_test_message_id>
2197 Subject: Re: [issue] Testing...
2199 Hi, I'm on holidays, and this is a dumb auto-responder.
2200 ''')
2202 def testAutoReplyEmailsAreIgnored(self):
2203 self.assertRaises(IgnoreBulk, self._handle_mail,
2204 '''Content-Type: text/plain;
2205 charset="iso-8859-1"
2206 From: Chef <chef@bork.bork.bork>
2207 To: issue_tracker@your.tracker.email.domain.example
2208 Cc: richard@test.test
2209 Message-Id: <dummy_test_message_id>
2210 Subject: Re: [issue] Out of office AutoReply: Back next week
2212 Hi, I am back in the office next week
2213 ''')
2215 def testNoSubject(self):
2216 self.assertRaises(MailUsageError, self._handle_mail,
2217 '''Content-Type: text/plain;
2218 charset="iso-8859-1"
2219 From: Chef <chef@bork.bork.bork>
2220 To: issue_tracker@your.tracker.email.domain.example
2221 Cc: richard@test.test
2222 Reply-To: chef@bork.bork.bork
2223 Message-Id: <dummy_test_message_id>
2225 ''')
2227 #
2228 # TEST FOR INVALID DESIGNATOR HANDLING
2229 #
2230 def testInvalidDesignator(self):
2231 self.assertRaises(MailUsageError, self._handle_mail,
2232 '''Content-Type: text/plain;
2233 charset="iso-8859-1"
2234 From: Chef <chef@bork.bork.bork>
2235 To: issue_tracker@your.tracker.email.domain.example
2236 Subject: [frobulated] testing
2237 Cc: richard@test.test
2238 Reply-To: chef@bork.bork.bork
2239 Message-Id: <dummy_test_message_id>
2241 ''')
2242 self.assertRaises(MailUsageError, self._handle_mail,
2243 '''Content-Type: text/plain;
2244 charset="iso-8859-1"
2245 From: Chef <chef@bork.bork.bork>
2246 To: issue_tracker@your.tracker.email.domain.example
2247 Subject: [issue12345] testing
2248 Cc: richard@test.test
2249 Reply-To: chef@bork.bork.bork
2250 Message-Id: <dummy_test_message_id>
2252 ''')
2254 def testInvalidClassLoose(self):
2255 self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'loose'
2256 nodeid = self._handle_mail('''Content-Type: text/plain;
2257 charset="iso-8859-1"
2258 From: Chef <chef@bork.bork.bork>
2259 To: issue_tracker@your.tracker.email.domain.example
2260 Subject: [frobulated] testing
2261 Cc: richard@test.test
2262 Reply-To: chef@bork.bork.bork
2263 Message-Id: <dummy_test_message_id>
2265 ''')
2266 assert not os.path.exists(SENDMAILDEBUG)
2267 self.assertEqual(self.db.issue.get(nodeid, 'title'),
2268 '[frobulated] testing')
2270 def testInvalidClassLooseReply(self):
2271 self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'loose'
2272 nodeid = self._handle_mail('''Content-Type: text/plain;
2273 charset="iso-8859-1"
2274 From: Chef <chef@bork.bork.bork>
2275 To: issue_tracker@your.tracker.email.domain.example
2276 Subject: Re: [frobulated] testing
2277 Cc: richard@test.test
2278 Reply-To: chef@bork.bork.bork
2279 Message-Id: <dummy_test_message_id>
2281 ''')
2282 assert not os.path.exists(SENDMAILDEBUG)
2283 self.assertEqual(self.db.issue.get(nodeid, 'title'),
2284 '[frobulated] testing')
2286 def testInvalidClassLoose(self):
2287 self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'loose'
2288 nodeid = self._handle_mail('''Content-Type: text/plain;
2289 charset="iso-8859-1"
2290 From: Chef <chef@bork.bork.bork>
2291 To: issue_tracker@your.tracker.email.domain.example
2292 Subject: [issue1234] testing
2293 Cc: richard@test.test
2294 Reply-To: chef@bork.bork.bork
2295 Message-Id: <dummy_test_message_id>
2297 ''')
2298 assert not os.path.exists(SENDMAILDEBUG)
2299 self.assertEqual(self.db.issue.get(nodeid, 'title'),
2300 '[issue1234] testing')
2302 def testClassLooseOK(self):
2303 self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'loose'
2304 self.db.keyword.create(name='Foo')
2305 nodeid = self._handle_mail('''Content-Type: text/plain;
2306 charset="iso-8859-1"
2307 From: Chef <chef@bork.bork.bork>
2308 To: issue_tracker@your.tracker.email.domain.example
2309 Subject: [keyword1] Testing... [name=Bar]
2310 Cc: richard@test.test
2311 Reply-To: chef@bork.bork.bork
2312 Message-Id: <dummy_test_message_id>
2314 ''')
2315 assert not os.path.exists(SENDMAILDEBUG)
2316 self.assertEqual(self.db.keyword.get('1', 'name'), 'Bar')
2318 def testClassStrictInvalid(self):
2319 self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'strict'
2320 self.instance.config.MAILGW_DEFAULT_CLASS = ''
2322 message = '''Content-Type: text/plain;
2323 charset="iso-8859-1"
2324 From: Chef <chef@bork.bork.bork>
2325 To: issue_tracker@your.tracker.email.domain.example
2326 Subject: Testing...
2327 Cc: richard@test.test
2328 Reply-To: chef@bork.bork.bork
2329 Message-Id: <dummy_test_message_id>
2331 '''
2332 self.assertRaises(MailUsageError, self._handle_mail, message)
2334 def testClassStrictValid(self):
2335 self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'strict'
2336 self.instance.config.MAILGW_DEFAULT_CLASS = ''
2338 nodeid = self._handle_mail('''Content-Type: text/plain;
2339 charset="iso-8859-1"
2340 From: Chef <chef@bork.bork.bork>
2341 To: issue_tracker@your.tracker.email.domain.example
2342 Subject: [issue] Testing...
2343 Cc: richard@test.test
2344 Reply-To: chef@bork.bork.bork
2345 Message-Id: <dummy_test_message_id>
2347 ''')
2349 assert not os.path.exists(SENDMAILDEBUG)
2350 self.assertEqual(self.db.issue.get(nodeid, 'title'), 'Testing...')
2352 #
2353 # TEST FOR INVALID COMMANDS HANDLING
2354 #
2355 def testInvalidCommands(self):
2356 self.assertRaises(MailUsageError, self._handle_mail,
2357 '''Content-Type: text/plain;
2358 charset="iso-8859-1"
2359 From: Chef <chef@bork.bork.bork>
2360 To: issue_tracker@your.tracker.email.domain.example
2361 Subject: testing [frobulated]
2362 Cc: richard@test.test
2363 Reply-To: chef@bork.bork.bork
2364 Message-Id: <dummy_test_message_id>
2366 ''')
2368 def testInvalidCommandPassthrough(self):
2369 self.instance.config.MAILGW_SUBJECT_SUFFIX_PARSING = 'none'
2370 nodeid = self._handle_mail('''Content-Type: text/plain;
2371 charset="iso-8859-1"
2372 From: Chef <chef@bork.bork.bork>
2373 To: issue_tracker@your.tracker.email.domain.example
2374 Subject: testing [frobulated]
2375 Cc: richard@test.test
2376 Reply-To: chef@bork.bork.bork
2377 Message-Id: <dummy_test_message_id>
2379 ''')
2380 assert not os.path.exists(SENDMAILDEBUG)
2381 self.assertEqual(self.db.issue.get(nodeid, 'title'),
2382 'testing [frobulated]')
2384 def testInvalidCommandPassthroughLoose(self):
2385 self.instance.config.MAILGW_SUBJECT_SUFFIX_PARSING = 'loose'
2386 nodeid = self._handle_mail('''Content-Type: text/plain;
2387 charset="iso-8859-1"
2388 From: Chef <chef@bork.bork.bork>
2389 To: issue_tracker@your.tracker.email.domain.example
2390 Subject: testing [frobulated]
2391 Cc: richard@test.test
2392 Reply-To: chef@bork.bork.bork
2393 Message-Id: <dummy_test_message_id>
2395 ''')
2396 assert not os.path.exists(SENDMAILDEBUG)
2397 self.assertEqual(self.db.issue.get(nodeid, 'title'),
2398 'testing [frobulated]')
2400 def testInvalidCommandPassthroughLooseOK(self):
2401 self.instance.config.MAILGW_SUBJECT_SUFFIX_PARSING = 'loose'
2402 nodeid = self._handle_mail('''Content-Type: text/plain;
2403 charset="iso-8859-1"
2404 From: Chef <chef@bork.bork.bork>
2405 To: issue_tracker@your.tracker.email.domain.example
2406 Subject: testing [assignedto=mary]
2407 Cc: richard@test.test
2408 Reply-To: chef@bork.bork.bork
2409 Message-Id: <dummy_test_message_id>
2411 ''')
2412 assert not os.path.exists(SENDMAILDEBUG)
2413 self.assertEqual(self.db.issue.get(nodeid, 'title'), 'testing')
2414 self.assertEqual(self.db.issue.get(nodeid, 'assignedto'), self.mary_id)
2416 def testCommandDelimiters(self):
2417 self.instance.config.MAILGW_SUBJECT_SUFFIX_DELIMITERS = '{}'
2418 nodeid = self._handle_mail('''Content-Type: text/plain;
2419 charset="iso-8859-1"
2420 From: Chef <chef@bork.bork.bork>
2421 To: issue_tracker@your.tracker.email.domain.example
2422 Subject: testing {assignedto=mary}
2423 Cc: richard@test.test
2424 Reply-To: chef@bork.bork.bork
2425 Message-Id: <dummy_test_message_id>
2427 ''')
2428 assert not os.path.exists(SENDMAILDEBUG)
2429 self.assertEqual(self.db.issue.get(nodeid, 'title'), 'testing')
2430 self.assertEqual(self.db.issue.get(nodeid, 'assignedto'), self.mary_id)
2432 def testPrefixDelimiters(self):
2433 self.instance.config.MAILGW_SUBJECT_SUFFIX_DELIMITERS = '{}'
2434 self.db.keyword.create(name='Foo')
2435 self._handle_mail('''Content-Type: text/plain;
2436 charset="iso-8859-1"
2437 From: richard <richard@test.test>
2438 To: issue_tracker@your.tracker.email.domain.example
2439 Message-Id: <followup_dummy_id>
2440 In-Reply-To: <dummy_test_message_id>
2441 Subject: {keyword1} Testing... {name=Bar}
2443 ''')
2444 assert not os.path.exists(SENDMAILDEBUG)
2445 self.assertEqual(self.db.keyword.get('1', 'name'), 'Bar')
2447 def testCommandDelimitersIgnore(self):
2448 self.instance.config.MAILGW_SUBJECT_SUFFIX_DELIMITERS = '{}'
2449 nodeid = self._handle_mail('''Content-Type: text/plain;
2450 charset="iso-8859-1"
2451 From: Chef <chef@bork.bork.bork>
2452 To: issue_tracker@your.tracker.email.domain.example
2453 Subject: testing [assignedto=mary]
2454 Cc: richard@test.test
2455 Reply-To: chef@bork.bork.bork
2456 Message-Id: <dummy_test_message_id>
2458 ''')
2459 assert not os.path.exists(SENDMAILDEBUG)
2460 self.assertEqual(self.db.issue.get(nodeid, 'title'),
2461 'testing [assignedto=mary]')
2462 self.assertEqual(self.db.issue.get(nodeid, 'assignedto'), None)
2464 def testReplytoMatch(self):
2465 self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'loose'
2466 nodeid = self.doNewIssue()
2467 nodeid2 = self._handle_mail('''Content-Type: text/plain;
2468 charset="iso-8859-1"
2469 From: Chef <chef@bork.bork.bork>
2470 To: issue_tracker@your.tracker.email.domain.example
2471 Message-Id: <dummy_test_message_id2>
2472 In-Reply-To: <dummy_test_message_id>
2473 Subject: Testing...
2475 Followup message.
2476 ''')
2478 nodeid3 = self._handle_mail('''Content-Type: text/plain;
2479 charset="iso-8859-1"
2480 From: Chef <chef@bork.bork.bork>
2481 To: issue_tracker@your.tracker.email.domain.example
2482 Message-Id: <dummy_test_message_id3>
2483 In-Reply-To: <dummy_test_message_id2>
2484 Subject: Testing...
2486 Yet another message in the same thread/issue.
2487 ''')
2489 self.assertEqual(nodeid, nodeid2)
2490 self.assertEqual(nodeid, nodeid3)
2492 def testHelpSubject(self):
2493 message = '''Content-Type: text/plain;
2494 charset="iso-8859-1"
2495 From: Chef <chef@bork.bork.bork>
2496 To: issue_tracker@your.tracker.email.domain.example
2497 Message-Id: <dummy_test_message_id2>
2498 In-Reply-To: <dummy_test_message_id>
2499 Subject: hElp
2502 '''
2503 self.assertRaises(MailUsageHelp, self._handle_mail, message)
2505 def testMaillistSubject(self):
2506 self.instance.config.MAILGW_SUBJECT_SUFFIX_DELIMITERS = '[]'
2507 self.db.keyword.create(name='Foo')
2508 self._handle_mail('''Content-Type: text/plain;
2509 charset="iso-8859-1"
2510 From: Chef <chef@bork.bork.bork>
2511 To: issue_tracker@your.tracker.email.domain.example
2512 Subject: [mailinglist-name] [keyword1] Testing.. [name=Bar]
2513 Cc: richard@test.test
2514 Reply-To: chef@bork.bork.bork
2515 Message-Id: <dummy_test_message_id>
2517 ''')
2519 assert not os.path.exists(SENDMAILDEBUG)
2520 self.assertEqual(self.db.keyword.get('1', 'name'), 'Bar')
2522 def testUnknownPrefixSubject(self):
2523 self.db.keyword.create(name='Foo')
2524 self._handle_mail('''Content-Type: text/plain;
2525 charset="iso-8859-1"
2526 From: Chef <chef@bork.bork.bork>
2527 To: issue_tracker@your.tracker.email.domain.example
2528 Subject: VeryStrangeRe: [keyword1] Testing.. [name=Bar]
2529 Cc: richard@test.test
2530 Reply-To: chef@bork.bork.bork
2531 Message-Id: <dummy_test_message_id>
2533 ''')
2535 assert not os.path.exists(SENDMAILDEBUG)
2536 self.assertEqual(self.db.keyword.get('1', 'name'), 'Bar')
2538 def testOneCharSubject(self):
2539 message = '''Content-Type: text/plain;
2540 charset="iso-8859-1"
2541 From: Chef <chef@bork.bork.bork>
2542 To: issue_tracker@your.tracker.email.domain.example
2543 Subject: b
2544 Cc: richard@test.test
2545 Reply-To: chef@bork.bork.bork
2546 Message-Id: <dummy_test_message_id>
2548 '''
2549 try:
2550 self._handle_mail(message)
2551 except MailUsageError:
2552 self.fail('MailUsageError raised')
2554 def testIssueidLast(self):
2555 nodeid1 = self.doNewIssue()
2556 nodeid2 = self._handle_mail('''Content-Type: text/plain;
2557 charset="iso-8859-1"
2558 From: mary <mary@test.test>
2559 To: issue_tracker@your.tracker.email.domain.example
2560 Message-Id: <followup_dummy_id>
2561 In-Reply-To: <dummy_test_message_id>
2562 Subject: New title [issue1]
2564 This is a second followup
2565 ''')
2567 assert nodeid1 == nodeid2
2568 self.assertEqual(self.db.issue.get(nodeid2, 'title'), "Testing...")
2570 def testSecurityMessagePermissionContent(self):
2571 id = self.doNewIssue()
2572 issue = self.db.issue.getnode (id)
2573 self.db.security.addRole(name='Nomsg')
2574 self.db.security.addPermissionToRole('Nomsg', 'Email Access')
2575 for cl in 'issue', 'file', 'keyword':
2576 for p in 'View', 'Edit', 'Create':
2577 self.db.security.addPermissionToRole('Nomsg', p, cl)
2578 self.db.user.set(self.mary_id, roles='Nomsg')
2579 nodeid = self._handle_mail('''Content-Type: text/plain;
2580 charset="iso-8859-1"
2581 From: Chef <chef@bork.bork.bork>
2582 To: issue_tracker@your.tracker.email.domain.example
2583 Message-Id: <dummy_test_message_id_2>
2584 Subject: [issue%(id)s] Testing... [nosy=+mary]
2586 Just a test reply
2587 '''%locals())
2588 assert os.path.exists(SENDMAILDEBUG)
2589 self.compareMessages(self._get_mail(),
2590 '''FROM: roundup-admin@your.tracker.email.domain.example
2591 TO: chef@bork.bork.bork, richard@test.test
2592 Content-Type: text/plain; charset="utf-8"
2593 Subject: [issue1] Testing...
2594 To: richard@test.test
2595 From: "Bork, Chef" <issue_tracker@your.tracker.email.domain.example>
2596 Reply-To: Roundup issue tracker
2597 <issue_tracker@your.tracker.email.domain.example>
2598 MIME-Version: 1.0
2599 Message-Id: <dummy_test_message_id_2>
2600 In-Reply-To: <dummy_test_message_id>
2601 X-Roundup-Name: Roundup issue tracker
2602 X-Roundup-Loop: hello
2603 X-Roundup-Issue-Status: chatting
2604 Content-Transfer-Encoding: quoted-printable
2607 Bork, Chef <chef@bork.bork.bork> added the comment:
2609 Just a test reply
2611 ----------
2612 nosy: +mary
2613 status: unread -> chatting
2615 _______________________________________________________________________
2616 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
2617 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
2618 _______________________________________________________________________
2619 ''')
2621 def testOutlookAttachment(self):
2622 message = '''X-MimeOLE: Produced By Microsoft Exchange V6.5
2623 Content-class: urn:content-classes:message
2624 MIME-Version: 1.0
2625 Content-Type: multipart/mixed;
2626 boundary="----_=_NextPart_001_01CACA65.40A51CBC"
2627 Subject: Example of a failed outlook attachment e-mail
2628 Date: Tue, 23 Mar 2010 01:43:44 -0700
2629 Message-ID: <CA37F17219784343816CA6613D2E339205E7D0F9@nrcwstexb1.nrc.ca>
2630 X-MS-Has-Attach: yes
2631 X-MS-TNEF-Correlator:
2632 Thread-Topic: Example of a failed outlook attachment e-mail
2633 Thread-Index: AcrKJo/t3pUBBwTpSwWNE3LE67UBDQ==
2634 From: "Hugh" <richard@test.test>
2635 To: <richard@test.test>
2636 X-OriginalArrivalTime: 23 Mar 2010 08:45:57.0350 (UTC) FILETIME=[41893860:01CACA65]
2638 This is a multi-part message in MIME format.
2640 ------_=_NextPart_001_01CACA65.40A51CBC
2641 Content-Type: multipart/alternative;
2642 boundary="----_=_NextPart_002_01CACA65.40A51CBC"
2645 ------_=_NextPart_002_01CACA65.40A51CBC
2646 Content-Type: text/plain;
2647 charset="us-ascii"
2648 Content-Transfer-Encoding: quoted-printable
2651 Hi Richard,
2653 I suppose this isn't the exact message that was sent but is a resend of
2654 one of my trial messages that failed. For your benefit I changed the
2655 subject line and am adding these words to the message body. Should
2656 still be as problematic, but if you like I can resend an exact copy of a
2657 failed message changing nothing except putting your address instead of
2658 our tracker.
2660 Thanks very much for taking time to look into this. Much appreciated.
2662 <<battery backup>>=20
2664 ------_=_NextPart_002_01CACA65.40A51CBC
2665 Content-Type: text/html;
2666 charset="us-ascii"
2667 Content-Transfer-Encoding: quoted-printable
2669 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
2670 <HTML>
2671 <HEAD>
2672 <META HTTP-EQUIV=3D"Content-Type" CONTENT=3D"text/html; =
2673 charset=3Dus-ascii">
2674 <META NAME=3D"Generator" CONTENT=3D"MS Exchange Server version =
2675 6.5.7654.12">
2676 <TITLE>Example of a failed outlook attachment e-mail</TITLE>
2677 </HEAD>
2678 <BODY>
2679 <!-- Converted from text/rtf format -->
2680 <BR>
2682 <P><FONT SIZE=3D2 FACE=3D"Arial">Hi Richard,</FONT>
2683 </P>
2685 <P><FONT SIZE=3D2 FACE=3D"Arial">I suppose this isn't the exact message =
2686 that was sent but is a resend of one of my trial messages that =
2687 failed. For your benefit I changed the subject line and am adding =
2688 these words to the message body. Should still be as problematic, =
2689 but if you like I can resend an exact copy of a failed message changing =
2690 nothing except putting your address instead of our tracker.</FONT></P>
2692 <P><FONT SIZE=3D2 FACE=3D"Arial">Thanks very much for taking time to =
2693 look into this. Much appreciated.</FONT>
2694 </P>
2695 <BR>
2697 <P><FONT FACE=3D"Arial" SIZE=3D2 COLOR=3D"#000000"> <<battery =
2698 backup>> </FONT>
2699 </P>
2701 </BODY>
2702 </HTML>
2703 ------_=_NextPart_002_01CACA65.40A51CBC--
2705 ------_=_NextPart_001_01CACA65.40A51CBC
2706 Content-Type: message/rfc822
2707 Content-Transfer-Encoding: 7bit
2709 X-MimeOLE: Produced By Microsoft Exchange V6.5
2710 MIME-Version: 1.0
2711 Content-Type: multipart/alternative;
2712 boundary="----_=_NextPart_003_01CAC15A.29717800"
2713 X-OriginalArrivalTime: 11 Mar 2010 20:33:51.0249 (UTC) FILETIME=[28FEE010:01CAC15A]
2714 Content-class: urn:content-classes:message
2715 Subject: battery backup
2716 Date: Thu, 11 Mar 2010 13:33:43 -0700
2717 Message-ID: <p06240809c7bf02f9624c@[128.114.22.203]>
2718 X-MS-Has-Attach:
2719 X-MS-TNEF-Correlator:
2720 Thread-Topic: battery backup
2721 Thread-Index: AcrBWimtulTrSvBdQ2CcfZ8lyQdxmQ==
2722 From: "Jerry" <jerry@test.test>
2723 To: "Hugh" <hugh@test.test>
2725 This is a multi-part message in MIME format.
2727 ------_=_NextPart_003_01CAC15A.29717800
2728 Content-Type: text/plain;
2729 charset="iso-8859-1"
2730 Content-Transfer-Encoding: quoted-printable
2732 Dear Hugh,
2733 A car batter has an energy capacity of ~ 500Wh. A UPS=20
2734 battery is worse than this.
2736 if we need to provied 100kW for 30 minutes that will take 100 car=20
2737 batteries. This seems like an awful lot of batteries.
2739 Of course I like your idea of making the time 1 minute, so we get to=20
2740 a more modest number of batteries
2742 Jerry
2745 ------_=_NextPart_003_01CAC15A.29717800
2746 Content-Type: text/html;
2747 charset="iso-8859-1"
2748 Content-Transfer-Encoding: quoted-printable
2750 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
2751 <HTML>
2752 <HEAD>
2753 <META HTTP-EQUIV=3D"Content-Type" CONTENT=3D"text/html; =
2754 charset=3Diso-8859-1">
2755 <META NAME=3D"Generator" CONTENT=3D"MS Exchange Server version =
2756 6.5.7654.12">
2757 <TITLE>battery backup</TITLE>
2758 </HEAD>
2759 <BODY>
2760 <!-- Converted from text/plain format -->
2762 <P><FONT SIZE=3D2>Dear Hugh,</FONT>
2764 <BR> <FONT SIZE=3D2>A car =
2765 batter has an energy capacity of ~ 500Wh. A UPS </FONT>
2767 <BR><FONT SIZE=3D2>battery is worse than this.</FONT>
2768 </P>
2770 <P><FONT SIZE=3D2>if we need to provied 100kW for 30 minutes that will =
2771 take 100 car </FONT>
2773 <BR><FONT SIZE=3D2>batteries. This seems like an awful lot of =
2774 batteries.</FONT>
2775 </P>
2777 <P><FONT SIZE=3D2>Of course I like your idea of making the time 1 =
2778 minute, so we get to </FONT>
2780 <BR><FONT SIZE=3D2>a more modest number of batteries</FONT>
2781 </P>
2783 <P><FONT SIZE=3D2>Jerry</FONT>
2784 </P>
2786 </BODY>
2787 </HTML>
2788 ------_=_NextPart_003_01CAC15A.29717800--
2790 ------_=_NextPart_001_01CACA65.40A51CBC--
2791 '''
2792 nodeid = self._handle_mail(message)
2793 assert not os.path.exists(SENDMAILDEBUG)
2794 msgid = self.db.issue.get(nodeid, 'messages')[0]
2795 self.assert_(self.db.msg.get(msgid, 'content').startswith('Hi Richard'))
2796 self.assertEqual(self.db.msg.get(msgid, 'files'), ['1', '2'])
2797 fileid = self.db.msg.get(msgid, 'files')[0]
2798 self.assertEqual(self.db.file.get(fileid, 'type'), 'text/html')
2799 fileid = self.db.msg.get(msgid, 'files')[1]
2800 self.assertEqual(self.db.file.get(fileid, 'type'), 'message/rfc822')
2802 def testForwardedMessageAttachment(self):
2803 message = '''Return-Path: <rgg@test.test>
2804 Received: from localhost(127.0.0.1), claiming to be "[115.130.26.69]"
2805 via SMTP by localhost, id smtpdAAApLaWrq; Tue Apr 13 23:10:05 2010
2806 Message-ID: <4BC4F9C7.50409@test.test>
2807 Date: Wed, 14 Apr 2010 09:09:59 +1000
2808 From: Rupert Goldie <rgg@test.test>
2809 User-Agent: Thunderbird 2.0.0.24 (Windows/20100228)
2810 MIME-Version: 1.0
2811 To: ekit issues <issues@test.test>
2812 Subject: [Fwd: PHP ERROR (fb)] post limit reached
2813 Content-Type: multipart/mixed; boundary="------------000807090608060304010403"
2815 This is a multi-part message in MIME format.
2816 --------------000807090608060304010403
2817 Content-Type: text/plain; charset=ISO-8859-1; format=flowed
2818 Content-Transfer-Encoding: 7bit
2820 Catch this exception and log it without emailing.
2822 --------------000807090608060304010403
2823 Content-Type: message/rfc822; name="PHP ERROR (fb).eml"
2824 Content-Transfer-Encoding: 7bit
2825 Content-Disposition: inline; filename="PHP ERROR (fb).eml"
2827 Return-Path: <ektravj@test.test>
2828 X-Sieve: CMU Sieve 2.2
2829 via SMTP by crown.off.ekorp.com, id smtpdAAA1JaW1o; Tue Apr 13 23:01:04 2010
2830 X-Virus-Scanned: by amavisd-new at ekit.com
2831 To: facebook-errors@test.test
2832 From: ektravj@test.test
2833 Subject: PHP ERROR (fb)
2834 Message-Id: <20100413230100.D601D27E84@mail2.elax3.ekorp.com>
2835 Date: Tue, 13 Apr 2010 23:01:00 +0000 (UTC)
2837 [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
2838 Stack trace:
2839 #0 /app/01/www/virtual/fb.ekit.com/htdocs/gateway/ekit/feed/index.php(178): fb_exceptions(Object(FacebookRestClientException))
2840 #1 {main}
2841 thrown in /app/01/www/virtual/fb.ekit.com/htdocs/includes/functions.php on line 280
2844 --------------000807090608060304010403--
2845 '''
2846 nodeid = self._handle_mail(message)
2847 assert not os.path.exists(SENDMAILDEBUG)
2848 msgid = self.db.issue.get(nodeid, 'messages')[0]
2849 self.assertEqual(self.db.msg.get(msgid, 'content'),
2850 'Catch this exception and log it without emailing.')
2851 self.assertEqual(self.db.msg.get(msgid, 'files'), ['1'])
2852 fileid = self.db.msg.get(msgid, 'files')[0]
2853 self.assertEqual(self.db.file.get(fileid, 'type'), 'message/rfc822')
2855 def test_suite():
2856 suite = unittest.TestSuite()
2857 suite.addTest(unittest.makeSuite(MailgwTestCase))
2858 return suite
2860 if __name__ == '__main__':
2861 runner = unittest.TextTestRunner()
2862 unittest.main(testRunner=runner)
2864 # vim: set filetype=python sts=4 sw=4 et si :