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