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):
153 class MailGW(self.instance.MailGW):
154 def handle_message(self, message):
155 return self._handle_message(message)
156 handler = MailGW(self.instance)
157 handler.db = self.db
158 return handler
160 def _handle_mail(self, message):
161 handler = self._create_mailgw(message)
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 doNewIssue(self):
203 nodeid = self._handle_mail('''Content-Type: text/plain;
204 charset="iso-8859-1"
205 From: Chef <chef@bork.bork.bork>
206 To: issue_tracker@your.tracker.email.domain.example
207 Cc: richard@test.test
208 Message-Id: <dummy_test_message_id>
209 Subject: [issue] Testing...
211 This is a test submission of a new issue.
212 ''')
213 assert not os.path.exists(SENDMAILDEBUG)
214 l = self.db.issue.get(nodeid, 'nosy')
215 l.sort()
216 self.assertEqual(l, [self.chef_id, self.richard_id])
217 return nodeid
219 def testNewIssue(self):
220 self.doNewIssue()
222 def testNewIssueNosy(self):
223 self.instance.config.ADD_AUTHOR_TO_NOSY = 'yes'
224 nodeid = self._handle_mail('''Content-Type: text/plain;
225 charset="iso-8859-1"
226 From: Chef <chef@bork.bork.bork>
227 To: issue_tracker@your.tracker.email.domain.example
228 Cc: richard@test.test
229 Message-Id: <dummy_test_message_id>
230 Subject: [issue] Testing...
232 This is a test submission of a new issue.
233 ''')
234 assert not os.path.exists(SENDMAILDEBUG)
235 l = self.db.issue.get(nodeid, 'nosy')
236 l.sort()
237 self.assertEqual(l, [self.chef_id, self.richard_id])
239 def testAlternateAddress(self):
240 self._handle_mail('''Content-Type: text/plain;
241 charset="iso-8859-1"
242 From: John Doe <john.doe@test.test>
243 To: issue_tracker@your.tracker.email.domain.example
244 Message-Id: <dummy_test_message_id>
245 Subject: [issue] Testing...
247 This is a test submission of a new issue.
248 ''')
249 userlist = self.db.user.list()
250 assert not os.path.exists(SENDMAILDEBUG)
251 self.assertEqual(userlist, self.db.user.list(),
252 "user created when it shouldn't have been")
254 def testNewIssueNoClass(self):
255 self._handle_mail('''Content-Type: text/plain;
256 charset="iso-8859-1"
257 From: Chef <chef@bork.bork.bork>
258 To: issue_tracker@your.tracker.email.domain.example
259 Cc: richard@test.test
260 Message-Id: <dummy_test_message_id>
261 Subject: Testing...
263 This is a test submission of a new issue.
264 ''')
265 assert not os.path.exists(SENDMAILDEBUG)
267 def testNewIssueAuthMsg(self):
268 # TODO: fix the damn config - this is apalling
269 self.db.config.MESSAGES_TO_AUTHOR = 'yes'
270 self._handle_mail('''Content-Type: text/plain;
271 charset="iso-8859-1"
272 From: Chef <chef@bork.bork.bork>
273 To: issue_tracker@your.tracker.email.domain.example
274 Message-Id: <dummy_test_message_id>
275 Subject: [issue] Testing... [nosy=mary; assignedto=richard]
277 This is a test submission of a new issue.
278 ''')
279 self.compareMessages(self._get_mail(),
280 '''FROM: roundup-admin@your.tracker.email.domain.example
281 TO: chef@bork.bork.bork, mary@test.test, richard@test.test
282 Content-Type: text/plain; charset="utf-8"
283 Subject: [issue1] Testing...
284 To: chef@bork.bork.bork, mary@test.test, richard@test.test
285 From: "Bork, Chef" <issue_tracker@your.tracker.email.domain.example>
286 Reply-To: Roundup issue tracker
287 <issue_tracker@your.tracker.email.domain.example>
288 MIME-Version: 1.0
289 Message-Id: <dummy_test_message_id>
290 X-Roundup-Name: Roundup issue tracker
291 X-Roundup-Loop: hello
292 X-Roundup-Issue-Status: unread
293 Content-Transfer-Encoding: quoted-printable
296 New submission from Bork, Chef <chef@bork.bork.bork>:
298 This is a test submission of a new issue.
300 ----------
301 assignedto: richard
302 messages: 1
303 nosy: Chef, mary, richard
304 status: unread
305 title: Testing...
307 _______________________________________________________________________
308 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
309 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
310 _______________________________________________________________________
311 ''')
313 def testNewIssueNoAuthorInfo(self):
314 self.db.config.MAIL_ADD_AUTHORINFO = 'no'
315 self._handle_mail('''Content-Type: text/plain;
316 charset="iso-8859-1"
317 From: Chef <chef@bork.bork.bork>
318 To: issue_tracker@your.tracker.email.domain.example
319 Message-Id: <dummy_test_message_id>
320 Subject: [issue] Testing... [nosy=mary; assignedto=richard]
322 This is a test submission of a new issue.
323 ''')
324 self.compareMessages(self._get_mail(),
325 '''FROM: roundup-admin@your.tracker.email.domain.example
326 TO: chef@bork.bork.bork, mary@test.test, richard@test.test
327 Content-Type: text/plain; charset="utf-8"
328 Subject: [issue1] Testing...
329 To: mary@test.test, richard@test.test
330 From: "Bork, Chef" <issue_tracker@your.tracker.email.domain.example>
331 Reply-To: Roundup issue tracker
332 <issue_tracker@your.tracker.email.domain.example>
333 MIME-Version: 1.0
334 Message-Id: <dummy_test_message_id>
335 X-Roundup-Name: Roundup issue tracker
336 X-Roundup-Loop: hello
337 X-Roundup-Issue-Status: unread
338 Content-Transfer-Encoding: quoted-printable
340 This is a test submission of a new issue.
342 ----------
343 assignedto: richard
344 messages: 1
345 nosy: Chef, mary, richard
346 status: unread
347 title: Testing...
349 _______________________________________________________________________
350 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
351 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
352 _______________________________________________________________________
353 ''')
355 def testNewIssueNoAuthorEmail(self):
356 self.db.config.MAIL_ADD_AUTHOREMAIL = 'no'
357 self._handle_mail('''Content-Type: text/plain;
358 charset="iso-8859-1"
359 From: Chef <chef@bork.bork.bork>
360 To: issue_tracker@your.tracker.email.domain.example
361 Message-Id: <dummy_test_message_id>
362 Subject: [issue] Testing... [nosy=mary; assignedto=richard]
364 This is a test submission of a new issue.
365 ''')
366 self.compareMessages(self._get_mail(),
367 '''FROM: roundup-admin@your.tracker.email.domain.example
368 TO: chef@bork.bork.bork, mary@test.test, richard@test.test
369 Content-Type: text/plain; charset="utf-8"
370 Subject: [issue1] Testing...
371 To: mary@test.test, richard@test.test
372 From: "Bork, Chef" <issue_tracker@your.tracker.email.domain.example>
373 Reply-To: Roundup issue tracker
374 <issue_tracker@your.tracker.email.domain.example>
375 MIME-Version: 1.0
376 Message-Id: <dummy_test_message_id>
377 X-Roundup-Name: Roundup issue tracker
378 X-Roundup-Loop: hello
379 X-Roundup-Issue-Status: unread
380 Content-Transfer-Encoding: quoted-printable
382 New submission from Bork, Chef:
384 This is a test submission of a new issue.
386 ----------
387 assignedto: richard
388 messages: 1
389 nosy: Chef, mary, richard
390 status: unread
391 title: Testing...
393 _______________________________________________________________________
394 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
395 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
396 _______________________________________________________________________
397 ''')
399 multipart_msg = '''From: mary <mary@test.test>
400 To: issue_tracker@your.tracker.email.domain.example
401 Message-Id: <followup_dummy_id>
402 In-Reply-To: <dummy_test_message_id>
403 Subject: [issue1] Testing...
404 Content-Type: multipart/mixed; boundary="bxyzzy"
405 Content-Disposition: inline
408 --bxyzzy
409 Content-Type: multipart/alternative; boundary="bCsyhTFzCvuiizWE"
410 Content-Disposition: inline
412 --bCsyhTFzCvuiizWE
413 Content-Type: text/plain; charset=us-ascii
414 Content-Disposition: inline
416 test attachment first text/plain
418 --bCsyhTFzCvuiizWE
419 Content-Type: application/octet-stream
420 Content-Disposition: attachment; filename="first.dvi"
421 Content-Transfer-Encoding: base64
423 SnVzdCBhIHRlc3QgAQo=
425 --bCsyhTFzCvuiizWE
426 Content-Type: text/plain; charset=us-ascii
427 Content-Disposition: inline
429 test attachment second text/plain
431 --bCsyhTFzCvuiizWE
432 Content-Type: text/html
433 Content-Disposition: inline
435 <html>
436 to be ignored.
437 </html>
439 --bCsyhTFzCvuiizWE--
441 --bxyzzy
442 Content-Type: multipart/alternative; boundary="bCsyhTFzCvuiizWF"
443 Content-Disposition: inline
445 --bCsyhTFzCvuiizWF
446 Content-Type: text/plain; charset=us-ascii
447 Content-Disposition: inline
449 test attachment third text/plain
451 --bCsyhTFzCvuiizWF
452 Content-Type: application/octet-stream
453 Content-Disposition: attachment; filename="second.dvi"
454 Content-Transfer-Encoding: base64
456 SnVzdCBhIHRlc3QK
458 --bCsyhTFzCvuiizWF--
460 --bxyzzy--
461 '''
463 def testMultipartKeepAlternatives(self):
464 self.doNewIssue()
465 self._handle_mail(self.multipart_msg)
466 messages = self.db.issue.get('1', 'messages')
467 messages.sort()
468 msg = self.db.msg.getnode (messages[-1])
469 assert(len(msg.files) == 5)
470 names = {0 : 'first.dvi', 4 : 'second.dvi'}
471 content = {3 : 'test attachment third text/plain\n',
472 4 : 'Just a test\n'}
473 for n, id in enumerate (msg.files):
474 f = self.db.file.getnode (id)
475 self.assertEqual(f.name, names.get (n, 'unnamed'))
476 if n in content :
477 self.assertEqual(f.content, content [n])
478 self.assertEqual(msg.content, 'test attachment second text/plain')
480 def testMultipartDropAlternatives(self):
481 self.doNewIssue()
482 self.db.config.MAILGW_IGNORE_ALTERNATIVES = True
483 self._handle_mail(self.multipart_msg)
484 messages = self.db.issue.get('1', 'messages')
485 messages.sort()
486 msg = self.db.msg.getnode (messages[-1])
487 assert(len(msg.files) == 2)
488 names = {1 : 'second.dvi'}
489 content = {0 : 'test attachment third text/plain\n',
490 1 : 'Just a test\n'}
491 for n, id in enumerate (msg.files):
492 f = self.db.file.getnode (id)
493 self.assertEqual(f.name, names.get (n, 'unnamed'))
494 if n in content :
495 self.assertEqual(f.content, content [n])
496 self.assertEqual(msg.content, 'test attachment second text/plain')
498 def testSimpleFollowup(self):
499 self.doNewIssue()
500 self._handle_mail('''Content-Type: text/plain;
501 charset="iso-8859-1"
502 From: mary <mary@test.test>
503 To: issue_tracker@your.tracker.email.domain.example
504 Message-Id: <followup_dummy_id>
505 In-Reply-To: <dummy_test_message_id>
506 Subject: [issue1] Testing...
508 This is a second followup
509 ''')
510 self.compareMessages(self._get_mail(),
511 '''FROM: roundup-admin@your.tracker.email.domain.example
512 TO: chef@bork.bork.bork, richard@test.test
513 Content-Type: text/plain; charset="utf-8"
514 Subject: [issue1] Testing...
515 To: chef@bork.bork.bork, richard@test.test
516 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
517 Reply-To: Roundup issue tracker
518 <issue_tracker@your.tracker.email.domain.example>
519 MIME-Version: 1.0
520 Message-Id: <followup_dummy_id>
521 In-Reply-To: <dummy_test_message_id>
522 X-Roundup-Name: Roundup issue tracker
523 X-Roundup-Loop: hello
524 X-Roundup-Issue-Status: chatting
525 Content-Transfer-Encoding: quoted-printable
528 Contrary, Mary <mary@test.test> added the comment:
530 This is a second followup
532 ----------
533 status: unread -> chatting
535 _______________________________________________________________________
536 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
537 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
538 _______________________________________________________________________
539 ''')
541 def testFollowup(self):
542 self.doNewIssue()
544 self._handle_mail('''Content-Type: text/plain;
545 charset="iso-8859-1"
546 From: richard <richard@test.test>
547 To: issue_tracker@your.tracker.email.domain.example
548 Message-Id: <followup_dummy_id>
549 In-Reply-To: <dummy_test_message_id>
550 Subject: [issue1] Testing... [assignedto=mary; nosy=+john]
552 This is a followup
553 ''')
554 l = self.db.issue.get('1', 'nosy')
555 l.sort()
556 self.assertEqual(l, [self.chef_id, self.richard_id, self.mary_id,
557 self.john_id])
559 self.compareMessages(self._get_mail(),
560 '''FROM: roundup-admin@your.tracker.email.domain.example
561 TO: chef@bork.bork.bork, john@test.test, mary@test.test
562 Content-Type: text/plain; charset="utf-8"
563 Subject: [issue1] Testing...
564 To: chef@bork.bork.bork, john@test.test, mary@test.test
565 From: richard <issue_tracker@your.tracker.email.domain.example>
566 Reply-To: Roundup issue tracker
567 <issue_tracker@your.tracker.email.domain.example>
568 MIME-Version: 1.0
569 Message-Id: <followup_dummy_id>
570 In-Reply-To: <dummy_test_message_id>
571 X-Roundup-Name: Roundup issue tracker
572 X-Roundup-Loop: hello
573 X-Roundup-Issue-Status: chatting
574 Content-Transfer-Encoding: quoted-printable
577 richard <richard@test.test> added the comment:
579 This is a followup
581 ----------
582 assignedto: -> mary
583 nosy: +john, mary
584 status: unread -> chatting
586 _______________________________________________________________________
587 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
588 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
589 _______________________________________________________________________
590 ''')
592 def testFollowupNoSubjectChange(self):
593 self.db.config.MAILGW_SUBJECT_UPDATES_TITLE = 'no'
594 self.doNewIssue()
596 self._handle_mail('''Content-Type: text/plain;
597 charset="iso-8859-1"
598 From: richard <richard@test.test>
599 To: issue_tracker@your.tracker.email.domain.example
600 Message-Id: <followup_dummy_id>
601 In-Reply-To: <dummy_test_message_id>
602 Subject: [issue1] Wrzlbrmft... [assignedto=mary; nosy=+john]
604 This is a followup
605 ''')
606 l = self.db.issue.get('1', 'nosy')
607 l.sort()
608 self.assertEqual(l, [self.chef_id, self.richard_id, self.mary_id,
609 self.john_id])
611 self.compareMessages(self._get_mail(),
612 '''FROM: roundup-admin@your.tracker.email.domain.example
613 TO: chef@bork.bork.bork, john@test.test, mary@test.test
614 Content-Type: text/plain; charset="utf-8"
615 Subject: [issue1] Testing...
616 To: chef@bork.bork.bork, john@test.test, mary@test.test
617 From: richard <issue_tracker@your.tracker.email.domain.example>
618 Reply-To: Roundup issue tracker
619 <issue_tracker@your.tracker.email.domain.example>
620 MIME-Version: 1.0
621 Message-Id: <followup_dummy_id>
622 In-Reply-To: <dummy_test_message_id>
623 X-Roundup-Name: Roundup issue tracker
624 X-Roundup-Loop: hello
625 X-Roundup-Issue-Status: chatting
626 Content-Transfer-Encoding: quoted-printable
629 richard <richard@test.test> added the comment:
631 This is a followup
633 ----------
634 assignedto: -> mary
635 nosy: +john, mary
636 status: unread -> chatting
638 _______________________________________________________________________
639 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
640 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
641 _______________________________________________________________________
642 ''')
643 self.assertEqual(self.db.issue.get('1','title'), 'Testing...')
645 def testFollowupExplicitSubjectChange(self):
646 self.doNewIssue()
648 self._handle_mail('''Content-Type: text/plain;
649 charset="iso-8859-1"
650 From: richard <richard@test.test>
651 To: issue_tracker@your.tracker.email.domain.example
652 Message-Id: <followup_dummy_id>
653 In-Reply-To: <dummy_test_message_id>
654 Subject: [issue1] Wrzlbrmft... [assignedto=mary; nosy=+john; title=new title]
656 This is a followup
657 ''')
658 l = self.db.issue.get('1', 'nosy')
659 l.sort()
660 self.assertEqual(l, [self.chef_id, self.richard_id, self.mary_id,
661 self.john_id])
663 self.compareMessages(self._get_mail(),
664 '''FROM: roundup-admin@your.tracker.email.domain.example
665 TO: chef@bork.bork.bork, john@test.test, mary@test.test
666 Content-Type: text/plain; charset="utf-8"
667 Subject: [issue1] new title
668 To: chef@bork.bork.bork, john@test.test, mary@test.test
669 From: richard <issue_tracker@your.tracker.email.domain.example>
670 Reply-To: Roundup issue tracker
671 <issue_tracker@your.tracker.email.domain.example>
672 MIME-Version: 1.0
673 Message-Id: <followup_dummy_id>
674 In-Reply-To: <dummy_test_message_id>
675 X-Roundup-Name: Roundup issue tracker
676 X-Roundup-Loop: hello
677 X-Roundup-Issue-Status: chatting
678 Content-Transfer-Encoding: quoted-printable
681 richard <richard@test.test> added the comment:
683 This is a followup
685 ----------
686 assignedto: -> mary
687 nosy: +john, mary
688 status: unread -> chatting
689 title: Testing... -> new title
691 _______________________________________________________________________
692 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
693 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
694 _______________________________________________________________________
695 ''')
697 def testNosyGeneration(self):
698 self.db.issue.create(title='test')
700 # create a nosy message
701 msg = self.db.msg.create(content='This is a test',
702 author=self.richard_id, messageid='<dummy_test_message_id>')
703 self.db.journaltag = 'richard'
704 l = self.db.issue.create(title='test', messages=[msg],
705 nosy=[self.chef_id, self.mary_id, self.john_id])
707 self.compareMessages(self._get_mail(),
708 '''FROM: roundup-admin@your.tracker.email.domain.example
709 TO: chef@bork.bork.bork, john@test.test, mary@test.test
710 Content-Type: text/plain; charset="utf-8"
711 Subject: [issue2] test
712 To: chef@bork.bork.bork, john@test.test, mary@test.test
713 From: richard <issue_tracker@your.tracker.email.domain.example>
714 Reply-To: Roundup issue tracker
715 <issue_tracker@your.tracker.email.domain.example>
716 MIME-Version: 1.0
717 Message-Id: <dummy_test_message_id>
718 X-Roundup-Name: Roundup issue tracker
719 X-Roundup-Loop: hello
720 X-Roundup-Issue-Status: unread
721 Content-Transfer-Encoding: quoted-printable
724 New submission from richard <richard@test.test>:
726 This is a test
728 ----------
729 messages: 1
730 nosy: Chef, john, mary, richard
731 status: unread
732 title: test
734 _______________________________________________________________________
735 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
736 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue2>
737 _______________________________________________________________________
738 ''')
740 def testPropertyChangeOnly(self):
741 self.doNewIssue()
742 oldvalues = self.db.getnode('issue', '1').copy()
743 oldvalues['assignedto'] = None
744 # reconstruct old behaviour: This would reuse the
745 # database-handle from the doNewIssue above which has committed
746 # as user "Chef". So we close and reopen the db as that user.
747 #self.db.close() actually don't close 'cos this empties memorydb
748 self.db = self.instance.open('Chef')
749 self.db.issue.set('1', assignedto=self.chef_id)
750 self.db.commit()
751 self.db.issue.nosymessage('1', None, oldvalues)
753 new_mail = ""
754 for line in self._get_mail().split("\n"):
755 if "Message-Id: " in line:
756 continue
757 if "Date: " in line:
758 continue
759 new_mail += line+"\n"
761 self.compareMessages(new_mail, """
762 FROM: roundup-admin@your.tracker.email.domain.example
763 TO: chef@bork.bork.bork, richard@test.test
764 Content-Type: text/plain; charset="utf-8"
765 Subject: [issue1] Testing...
766 To: chef@bork.bork.bork, richard@test.test
767 From: "Bork, Chef" <issue_tracker@your.tracker.email.domain.example>
768 X-Roundup-Name: Roundup issue tracker
769 X-Roundup-Loop: hello
770 X-Roundup-Issue-Status: unread
771 X-Roundup-Version: 1.3.3
772 In-Reply-To: <dummy_test_message_id>
773 MIME-Version: 1.0
774 Reply-To: Roundup issue tracker
775 <issue_tracker@your.tracker.email.domain.example>
776 Content-Transfer-Encoding: quoted-printable
779 Change by Bork, Chef <chef@bork.bork.bork>:
782 ----------
783 assignedto: -> Chef
785 _______________________________________________________________________
786 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
787 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
788 _______________________________________________________________________
789 """)
792 #
793 # FOLLOWUP TITLE MATCH
794 #
795 def testFollowupTitleMatch(self):
796 self.doNewIssue()
797 self._handle_mail('''Content-Type: text/plain;
798 charset="iso-8859-1"
799 From: richard <richard@test.test>
800 To: issue_tracker@your.tracker.email.domain.example
801 Message-Id: <followup_dummy_id>
802 Subject: Re: Testing... [assignedto=mary; nosy=+john]
804 This is a followup
805 ''')
806 self.compareMessages(self._get_mail(),
807 '''FROM: roundup-admin@your.tracker.email.domain.example
808 TO: chef@bork.bork.bork, john@test.test, mary@test.test
809 Content-Type: text/plain; charset="utf-8"
810 Subject: [issue1] Testing...
811 To: chef@bork.bork.bork, john@test.test, mary@test.test
812 From: richard <issue_tracker@your.tracker.email.domain.example>
813 Reply-To: Roundup issue tracker
814 <issue_tracker@your.tracker.email.domain.example>
815 MIME-Version: 1.0
816 Message-Id: <followup_dummy_id>
817 In-Reply-To: <dummy_test_message_id>
818 X-Roundup-Name: Roundup issue tracker
819 X-Roundup-Loop: hello
820 X-Roundup-Issue-Status: chatting
821 Content-Transfer-Encoding: quoted-printable
824 richard <richard@test.test> added the comment:
826 This is a followup
828 ----------
829 assignedto: -> mary
830 nosy: +john, mary
831 status: unread -> chatting
833 _______________________________________________________________________
834 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
835 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
836 _______________________________________________________________________
837 ''')
839 def testFollowupTitleMatchMultiRe(self):
840 nodeid1 = self.doNewIssue()
841 nodeid2 = self._handle_mail('''Content-Type: text/plain;
842 charset="iso-8859-1"
843 From: richard <richard@test.test>
844 To: issue_tracker@your.tracker.email.domain.example
845 Message-Id: <followup_dummy_id>
846 Subject: Re: Testing... [assignedto=mary; nosy=+john]
848 This is a followup
849 ''')
851 nodeid3 = self._handle_mail('''Content-Type: text/plain;
852 charset="iso-8859-1"
853 From: richard <richard@test.test>
854 To: issue_tracker@your.tracker.email.domain.example
855 Message-Id: <followup2_dummy_id>
856 Subject: Ang: Re: Testing...
858 This is a followup
859 ''')
860 self.assertEqual(nodeid1, nodeid2)
861 self.assertEqual(nodeid1, nodeid3)
863 def testFollowupTitleMatchNever(self):
864 nodeid = self.doNewIssue()
865 self.db.config.MAILGW_SUBJECT_CONTENT_MATCH = 'never'
866 self.assertNotEqual(self._handle_mail('''Content-Type: text/plain;
867 charset="iso-8859-1"
868 From: richard <richard@test.test>
869 To: issue_tracker@your.tracker.email.domain.example
870 Message-Id: <followup_dummy_id>
871 Subject: Re: Testing...
873 This is a followup
874 '''), nodeid)
876 def testFollowupTitleMatchNeverInterval(self):
877 nodeid = self.doNewIssue()
878 # force failure of the interval
879 time.sleep(2)
880 self.db.config.MAILGW_SUBJECT_CONTENT_MATCH = 'creation 00:00:01'
881 self.assertNotEqual(self._handle_mail('''Content-Type: text/plain;
882 charset="iso-8859-1"
883 From: richard <richard@test.test>
884 To: issue_tracker@your.tracker.email.domain.example
885 Message-Id: <followup_dummy_id>
886 Subject: Re: Testing...
888 This is a followup
889 '''), nodeid)
892 def testFollowupTitleMatchInterval(self):
893 nodeid = self.doNewIssue()
894 self.db.config.MAILGW_SUBJECT_CONTENT_MATCH = 'creation +1d'
895 self.assertEqual(self._handle_mail('''Content-Type: text/plain;
896 charset="iso-8859-1"
897 From: richard <richard@test.test>
898 To: issue_tracker@your.tracker.email.domain.example
899 Message-Id: <followup_dummy_id>
900 Subject: Re: Testing...
902 This is a followup
903 '''), nodeid)
906 def testFollowupNosyAuthor(self):
907 self.doNewIssue()
908 self.db.config.ADD_AUTHOR_TO_NOSY = 'yes'
909 self._handle_mail('''Content-Type: text/plain;
910 charset="iso-8859-1"
911 From: john@test.test
912 To: issue_tracker@your.tracker.email.domain.example
913 Message-Id: <followup_dummy_id>
914 In-Reply-To: <dummy_test_message_id>
915 Subject: [issue1] Testing...
917 This is a followup
918 ''')
920 self.compareMessages(self._get_mail(),
921 '''FROM: roundup-admin@your.tracker.email.domain.example
922 TO: chef@bork.bork.bork, richard@test.test
923 Content-Type: text/plain; charset="utf-8"
924 Subject: [issue1] Testing...
925 To: chef@bork.bork.bork, richard@test.test
926 From: John Doe <issue_tracker@your.tracker.email.domain.example>
927 Reply-To: Roundup issue tracker
928 <issue_tracker@your.tracker.email.domain.example>
929 MIME-Version: 1.0
930 Message-Id: <followup_dummy_id>
931 In-Reply-To: <dummy_test_message_id>
932 X-Roundup-Name: Roundup issue tracker
933 X-Roundup-Loop: hello
934 X-Roundup-Issue-Status: chatting
935 Content-Transfer-Encoding: quoted-printable
938 John Doe <john@test.test> added the comment:
940 This is a followup
942 ----------
943 nosy: +john
944 status: unread -> chatting
946 _______________________________________________________________________
947 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
948 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
949 _______________________________________________________________________
951 ''')
953 def testFollowupNosyRecipients(self):
954 self.doNewIssue()
955 self.db.config.ADD_RECIPIENTS_TO_NOSY = 'yes'
956 self._handle_mail('''Content-Type: text/plain;
957 charset="iso-8859-1"
958 From: richard@test.test
959 To: issue_tracker@your.tracker.email.domain.example
960 Cc: john@test.test
961 Message-Id: <followup_dummy_id>
962 In-Reply-To: <dummy_test_message_id>
963 Subject: [issue1] Testing...
965 This is a followup
966 ''')
967 self.compareMessages(self._get_mail(),
968 '''FROM: roundup-admin@your.tracker.email.domain.example
969 TO: chef@bork.bork.bork
970 Content-Type: text/plain; charset="utf-8"
971 Subject: [issue1] Testing...
972 To: chef@bork.bork.bork
973 From: richard <issue_tracker@your.tracker.email.domain.example>
974 Reply-To: Roundup issue tracker
975 <issue_tracker@your.tracker.email.domain.example>
976 MIME-Version: 1.0
977 Message-Id: <followup_dummy_id>
978 In-Reply-To: <dummy_test_message_id>
979 X-Roundup-Name: Roundup issue tracker
980 X-Roundup-Loop: hello
981 X-Roundup-Issue-Status: chatting
982 Content-Transfer-Encoding: quoted-printable
985 richard <richard@test.test> added the comment:
987 This is a followup
989 ----------
990 nosy: +john
991 status: unread -> chatting
993 _______________________________________________________________________
994 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
995 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
996 _______________________________________________________________________
998 ''')
1000 def testFollowupNosyAuthorAndCopy(self):
1001 self.doNewIssue()
1002 self.db.config.ADD_AUTHOR_TO_NOSY = 'yes'
1003 self.db.config.MESSAGES_TO_AUTHOR = 'yes'
1004 self._handle_mail('''Content-Type: text/plain;
1005 charset="iso-8859-1"
1006 From: john@test.test
1007 To: issue_tracker@your.tracker.email.domain.example
1008 Message-Id: <followup_dummy_id>
1009 In-Reply-To: <dummy_test_message_id>
1010 Subject: [issue1] Testing...
1012 This is a followup
1013 ''')
1014 self.compareMessages(self._get_mail(),
1015 '''FROM: roundup-admin@your.tracker.email.domain.example
1016 TO: chef@bork.bork.bork, john@test.test, richard@test.test
1017 Content-Type: text/plain; charset="utf-8"
1018 Subject: [issue1] Testing...
1019 To: chef@bork.bork.bork, john@test.test, richard@test.test
1020 From: John Doe <issue_tracker@your.tracker.email.domain.example>
1021 Reply-To: Roundup issue tracker
1022 <issue_tracker@your.tracker.email.domain.example>
1023 MIME-Version: 1.0
1024 Message-Id: <followup_dummy_id>
1025 In-Reply-To: <dummy_test_message_id>
1026 X-Roundup-Name: Roundup issue tracker
1027 X-Roundup-Loop: hello
1028 X-Roundup-Issue-Status: chatting
1029 Content-Transfer-Encoding: quoted-printable
1032 John Doe <john@test.test> added the comment:
1034 This is a followup
1036 ----------
1037 nosy: +john
1038 status: unread -> chatting
1040 _______________________________________________________________________
1041 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1042 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1043 _______________________________________________________________________
1045 ''')
1047 def testFollowupNoNosyAuthor(self):
1048 self.doNewIssue()
1049 self.instance.config.ADD_AUTHOR_TO_NOSY = 'no'
1050 self._handle_mail('''Content-Type: text/plain;
1051 charset="iso-8859-1"
1052 From: john@test.test
1053 To: issue_tracker@your.tracker.email.domain.example
1054 Message-Id: <followup_dummy_id>
1055 In-Reply-To: <dummy_test_message_id>
1056 Subject: [issue1] Testing...
1058 This is a followup
1059 ''')
1060 self.compareMessages(self._get_mail(),
1061 '''FROM: roundup-admin@your.tracker.email.domain.example
1062 TO: chef@bork.bork.bork, richard@test.test
1063 Content-Type: text/plain; charset="utf-8"
1064 Subject: [issue1] Testing...
1065 To: chef@bork.bork.bork, richard@test.test
1066 From: John Doe <issue_tracker@your.tracker.email.domain.example>
1067 Reply-To: Roundup issue tracker
1068 <issue_tracker@your.tracker.email.domain.example>
1069 MIME-Version: 1.0
1070 Message-Id: <followup_dummy_id>
1071 In-Reply-To: <dummy_test_message_id>
1072 X-Roundup-Name: Roundup issue tracker
1073 X-Roundup-Loop: hello
1074 X-Roundup-Issue-Status: chatting
1075 Content-Transfer-Encoding: quoted-printable
1078 John Doe <john@test.test> added the comment:
1080 This is a followup
1082 ----------
1083 status: unread -> chatting
1085 _______________________________________________________________________
1086 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1087 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1088 _______________________________________________________________________
1090 ''')
1092 def testFollowupNoNosyRecipients(self):
1093 self.doNewIssue()
1094 self.instance.config.ADD_RECIPIENTS_TO_NOSY = 'no'
1095 self._handle_mail('''Content-Type: text/plain;
1096 charset="iso-8859-1"
1097 From: richard@test.test
1098 To: issue_tracker@your.tracker.email.domain.example
1099 Cc: john@test.test
1100 Message-Id: <followup_dummy_id>
1101 In-Reply-To: <dummy_test_message_id>
1102 Subject: [issue1] Testing...
1104 This is a followup
1105 ''')
1106 self.compareMessages(self._get_mail(),
1107 '''FROM: roundup-admin@your.tracker.email.domain.example
1108 TO: chef@bork.bork.bork
1109 Content-Type: text/plain; charset="utf-8"
1110 Subject: [issue1] Testing...
1111 To: chef@bork.bork.bork
1112 From: richard <issue_tracker@your.tracker.email.domain.example>
1113 Reply-To: Roundup issue tracker
1114 <issue_tracker@your.tracker.email.domain.example>
1115 MIME-Version: 1.0
1116 Message-Id: <followup_dummy_id>
1117 In-Reply-To: <dummy_test_message_id>
1118 X-Roundup-Name: Roundup issue tracker
1119 X-Roundup-Loop: hello
1120 X-Roundup-Issue-Status: chatting
1121 Content-Transfer-Encoding: quoted-printable
1124 richard <richard@test.test> added the comment:
1126 This is a followup
1128 ----------
1129 status: unread -> chatting
1131 _______________________________________________________________________
1132 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1133 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1134 _______________________________________________________________________
1136 ''')
1138 def testFollowupEmptyMessage(self):
1139 self.doNewIssue()
1141 self._handle_mail('''Content-Type: text/plain;
1142 charset="iso-8859-1"
1143 From: richard <richard@test.test>
1144 To: issue_tracker@your.tracker.email.domain.example
1145 Message-Id: <followup_dummy_id>
1146 In-Reply-To: <dummy_test_message_id>
1147 Subject: [issue1] Testing... [assignedto=mary; nosy=+john]
1149 ''')
1150 l = self.db.issue.get('1', 'nosy')
1151 l.sort()
1152 self.assertEqual(l, [self.chef_id, self.richard_id, self.mary_id,
1153 self.john_id])
1155 # should be no file created (ie. no message)
1156 assert not os.path.exists(SENDMAILDEBUG)
1158 def testFollowupEmptyMessageNoSubject(self):
1159 self.doNewIssue()
1161 self._handle_mail('''Content-Type: text/plain;
1162 charset="iso-8859-1"
1163 From: richard <richard@test.test>
1164 To: issue_tracker@your.tracker.email.domain.example
1165 Message-Id: <followup_dummy_id>
1166 In-Reply-To: <dummy_test_message_id>
1167 Subject: [issue1] [assignedto=mary; nosy=+john]
1169 ''')
1170 l = self.db.issue.get('1', 'nosy')
1171 l.sort()
1172 self.assertEqual(l, [self.chef_id, self.richard_id, self.mary_id,
1173 self.john_id])
1175 # should be no file created (ie. no message)
1176 assert not os.path.exists(SENDMAILDEBUG)
1178 def testNosyRemove(self):
1179 self.doNewIssue()
1181 self._handle_mail('''Content-Type: text/plain;
1182 charset="iso-8859-1"
1183 From: richard <richard@test.test>
1184 To: issue_tracker@your.tracker.email.domain.example
1185 Message-Id: <followup_dummy_id>
1186 In-Reply-To: <dummy_test_message_id>
1187 Subject: [issue1] Testing... [nosy=-richard]
1189 ''')
1190 l = self.db.issue.get('1', 'nosy')
1191 l.sort()
1192 self.assertEqual(l, [self.chef_id])
1194 # NO NOSY MESSAGE SHOULD BE SENT!
1195 assert not os.path.exists(SENDMAILDEBUG)
1197 def testNewUserAuthor(self):
1198 self.db.commit()
1199 l = self.db.user.list()
1200 l.sort()
1201 message = '''Content-Type: text/plain;
1202 charset="iso-8859-1"
1203 From: fubar <fubar@bork.bork.bork>
1204 To: issue_tracker@your.tracker.email.domain.example
1205 Message-Id: <dummy_test_message_id>
1206 Subject: [issue] Testing...
1208 This is a test submission of a new issue.
1209 '''
1210 self.db.security.role['anonymous'].permissions=[]
1211 anonid = self.db.user.lookup('anonymous')
1212 self.db.user.set(anonid, roles='Anonymous')
1213 try:
1214 self._handle_mail(message)
1215 except Unauthorized, value:
1216 body_diff = self.compareMessages(str(value), """
1217 You are not a registered user.
1219 Unknown address: fubar@bork.bork.bork
1220 """)
1221 assert not body_diff, body_diff
1222 else:
1223 raise AssertionError, "Unathorized not raised when handling mail"
1225 # Add Web Access role to anonymous, and try again to make sure
1226 # we get a "please register at:" message this time.
1227 p = [
1228 self.db.security.getPermission('Register', 'user'),
1229 self.db.security.getPermission('Web Access', None),
1230 ]
1231 self.db.security.role['anonymous'].permissions=p
1232 try:
1233 self._handle_mail(message)
1234 except Unauthorized, value:
1235 body_diff = self.compareMessages(str(value), """
1236 You are not a registered user. Please register at:
1238 http://tracker.example/cgi-bin/roundup.cgi/bugs/user?template=register
1240 ...before sending mail to the tracker.
1242 Unknown address: fubar@bork.bork.bork
1243 """)
1244 assert not body_diff, body_diff
1245 else:
1246 raise AssertionError, "Unathorized not raised when handling mail"
1248 # Make sure list of users is the same as before.
1249 m = self.db.user.list()
1250 m.sort()
1251 self.assertEqual(l, m)
1253 # now with the permission
1254 p = [
1255 self.db.security.getPermission('Register', 'user'),
1256 self.db.security.getPermission('Email Access', None),
1257 ]
1258 self.db.security.role['anonymous'].permissions=p
1259 self._handle_mail(message)
1260 m = self.db.user.list()
1261 m.sort()
1262 self.assertNotEqual(l, m)
1264 def testNewUserAuthorEncodedName(self):
1265 l = set(self.db.user.list())
1266 # From: name has Euro symbol in it
1267 message = '''Content-Type: text/plain;
1268 charset="iso-8859-1"
1269 From: =?utf8?b?SOKCrGxsbw==?= <fubar@bork.bork.bork>
1270 To: issue_tracker@your.tracker.email.domain.example
1271 Message-Id: <dummy_test_message_id>
1272 Subject: [issue] Testing...
1274 This is a test submission of a new issue.
1275 '''
1276 p = [
1277 self.db.security.getPermission('Register', 'user'),
1278 self.db.security.getPermission('Email Access', None),
1279 self.db.security.getPermission('Create', 'issue'),
1280 self.db.security.getPermission('Create', 'msg'),
1281 ]
1282 self.db.security.role['anonymous'].permissions = p
1283 self._handle_mail(message)
1284 m = set(self.db.user.list())
1285 new = list(m - l)[0]
1286 name = self.db.user.get(new, 'realname')
1287 self.assertEquals(name, 'H€llo')
1289 def testUnknownUser(self):
1290 l = set(self.db.user.list())
1291 message = '''Content-Type: text/plain;
1292 charset="iso-8859-1"
1293 From: Nonexisting User <nonexisting@bork.bork.bork>
1294 To: issue_tracker@your.tracker.email.domain.example
1295 Message-Id: <dummy_test_message_id>
1296 Subject: [issue] Testing nonexisting user...
1298 This is a test submission of a new issue.
1299 '''
1300 handler = self._create_mailgw(message)
1301 # we want a bounce message:
1302 handler.trapExceptions = 1
1303 ret = handler.main(StringIO(message))
1304 self.compareMessages(self._get_mail(),
1305 '''FROM: Roundup issue tracker <roundup-admin@your.tracker.email.domain.example>
1306 TO: nonexisting@bork.bork.bork
1307 From nobody Tue Jul 14 12:04:11 2009
1308 Content-Type: multipart/mixed; boundary="===============0639262320=="
1309 MIME-Version: 1.0
1310 Subject: Failed issue tracker submission
1311 To: nonexisting@bork.bork.bork
1312 From: Roundup issue tracker <roundup-admin@your.tracker.email.domain.example>
1313 Date: Tue, 14 Jul 2009 12:04:11 +0000
1314 Precedence: bulk
1315 X-Roundup-Name: Roundup issue tracker
1316 X-Roundup-Loop: hello
1317 X-Roundup-Version: 1.4.8
1318 MIME-Version: 1.0
1320 --===============0639262320==
1321 Content-Type: text/plain; charset="us-ascii"
1322 MIME-Version: 1.0
1323 Content-Transfer-Encoding: 7bit
1327 You are not a registered user. Please register at:
1329 http://tracker.example/cgi-bin/roundup.cgi/bugs/user?template=register
1331 ...before sending mail to the tracker.
1333 Unknown address: nonexisting@bork.bork.bork
1335 --===============0639262320==
1336 Content-Type: text/plain; charset="us-ascii"
1337 MIME-Version: 1.0
1338 Content-Transfer-Encoding: 7bit
1340 Content-Type: text/plain;
1341 charset="iso-8859-1"
1342 From: Nonexisting User <nonexisting@bork.bork.bork>
1343 To: issue_tracker@your.tracker.email.domain.example
1344 Message-Id: <dummy_test_message_id>
1345 Subject: [issue] Testing nonexisting user...
1347 This is a test submission of a new issue.
1349 --===============0639262320==--
1350 ''')
1352 def testEnc01(self):
1353 self.db.user.set(self.mary_id,
1354 realname='\xe4\xf6\xfc\xc4\xd6\xdc\xdf, Mary'.decode
1355 ('latin-1').encode('utf-8'))
1356 self.doNewIssue()
1357 self._handle_mail('''Content-Type: text/plain;
1358 charset="iso-8859-1"
1359 From: mary <mary@test.test>
1360 To: issue_tracker@your.tracker.email.domain.example
1361 Message-Id: <followup_dummy_id>
1362 In-Reply-To: <dummy_test_message_id>
1363 Subject: [issue1] Testing...
1364 Content-Type: text/plain;
1365 charset="iso-8859-1"
1366 Content-Transfer-Encoding: quoted-printable
1368 A message with encoding (encoded oe =F6)
1370 ''')
1371 self.compareMessages(self._get_mail(),
1372 '''FROM: roundup-admin@your.tracker.email.domain.example
1373 TO: chef@bork.bork.bork, richard@test.test
1374 Content-Type: text/plain; charset="utf-8"
1375 Subject: [issue1] Testing...
1376 To: chef@bork.bork.bork, richard@test.test
1377 From: =?utf-8?b?w6TDtsO8w4TDlsOcw58sIE1hcnk=?=
1378 <issue_tracker@your.tracker.email.domain.example>
1379 Reply-To: Roundup issue tracker
1380 <issue_tracker@your.tracker.email.domain.example>
1381 MIME-Version: 1.0
1382 Message-Id: <followup_dummy_id>
1383 In-Reply-To: <dummy_test_message_id>
1384 X-Roundup-Name: Roundup issue tracker
1385 X-Roundup-Loop: hello
1386 X-Roundup-Issue-Status: chatting
1387 Content-Transfer-Encoding: quoted-printable
1390 =C3=A4=C3=B6=C3=BC=C3=84=C3=96=C3=9C=C3=9F, Mary <mary@test.test> added the=
1391 comment:
1393 A message with encoding (encoded oe =C3=B6)
1395 ----------
1396 status: unread -> chatting
1398 _______________________________________________________________________
1399 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1400 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1401 _______________________________________________________________________
1402 ''')
1404 def testEncNonUTF8(self):
1405 self.doNewIssue()
1406 self.instance.config.EMAIL_CHARSET = 'iso-8859-1'
1407 self._handle_mail('''Content-Type: text/plain;
1408 charset="iso-8859-1"
1409 From: mary <mary@test.test>
1410 To: issue_tracker@your.tracker.email.domain.example
1411 Message-Id: <followup_dummy_id>
1412 In-Reply-To: <dummy_test_message_id>
1413 Subject: [issue1] Testing...
1414 Content-Type: text/plain;
1415 charset="iso-8859-1"
1416 Content-Transfer-Encoding: quoted-printable
1418 A message with encoding (encoded oe =F6)
1420 ''')
1421 self.compareMessages(self._get_mail(),
1422 '''FROM: roundup-admin@your.tracker.email.domain.example
1423 TO: chef@bork.bork.bork, richard@test.test
1424 Content-Type: text/plain; charset="iso-8859-1"
1425 Subject: [issue1] Testing...
1426 To: chef@bork.bork.bork, richard@test.test
1427 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
1428 Reply-To: Roundup issue tracker
1429 <issue_tracker@your.tracker.email.domain.example>
1430 MIME-Version: 1.0
1431 Message-Id: <followup_dummy_id>
1432 In-Reply-To: <dummy_test_message_id>
1433 X-Roundup-Name: Roundup issue tracker
1434 X-Roundup-Loop: hello
1435 X-Roundup-Issue-Status: chatting
1436 Content-Transfer-Encoding: quoted-printable
1439 Contrary, Mary <mary@test.test> added the comment:
1441 A message with encoding (encoded oe =F6)
1443 ----------
1444 status: unread -> chatting
1446 _______________________________________________________________________
1447 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1448 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1449 _______________________________________________________________________
1450 ''')
1453 def testMultipartEnc01(self):
1454 self.doNewIssue()
1455 self._handle_mail('''Content-Type: text/plain;
1456 charset="iso-8859-1"
1457 From: mary <mary@test.test>
1458 To: issue_tracker@your.tracker.email.domain.example
1459 Message-Id: <followup_dummy_id>
1460 In-Reply-To: <dummy_test_message_id>
1461 Subject: [issue1] Testing...
1462 Content-Type: multipart/mixed;
1463 boundary="----_=_NextPart_000_01"
1465 This message is in MIME format. Since your mail reader does not understand
1466 this format, some or all of this message may not be legible.
1468 ------_=_NextPart_000_01
1469 Content-Type: text/plain;
1470 charset="iso-8859-1"
1471 Content-Transfer-Encoding: quoted-printable
1473 A message with first part encoded (encoded oe =F6)
1475 ''')
1476 self.compareMessages(self._get_mail(),
1477 '''FROM: roundup-admin@your.tracker.email.domain.example
1478 TO: chef@bork.bork.bork, richard@test.test
1479 Content-Type: text/plain; charset="utf-8"
1480 Subject: [issue1] Testing...
1481 To: chef@bork.bork.bork, richard@test.test
1482 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
1483 Reply-To: Roundup issue tracker
1484 <issue_tracker@your.tracker.email.domain.example>
1485 MIME-Version: 1.0
1486 Message-Id: <followup_dummy_id>
1487 In-Reply-To: <dummy_test_message_id>
1488 X-Roundup-Name: Roundup issue tracker
1489 X-Roundup-Loop: hello
1490 X-Roundup-Issue-Status: chatting
1491 Content-Transfer-Encoding: quoted-printable
1494 Contrary, Mary <mary@test.test> added the comment:
1496 A message with first part encoded (encoded oe =C3=B6)
1498 ----------
1499 status: unread -> chatting
1501 _______________________________________________________________________
1502 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1503 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1504 _______________________________________________________________________
1505 ''')
1507 def testContentDisposition(self):
1508 self.doNewIssue()
1509 self._handle_mail('''Content-Type: text/plain;
1510 charset="iso-8859-1"
1511 From: mary <mary@test.test>
1512 To: issue_tracker@your.tracker.email.domain.example
1513 Message-Id: <followup_dummy_id>
1514 In-Reply-To: <dummy_test_message_id>
1515 Subject: [issue1] Testing...
1516 Content-Type: multipart/mixed; boundary="bCsyhTFzCvuiizWE"
1517 Content-Disposition: inline
1520 --bCsyhTFzCvuiizWE
1521 Content-Type: text/plain; charset=us-ascii
1522 Content-Disposition: inline
1524 test attachment binary
1526 --bCsyhTFzCvuiizWE
1527 Content-Type: application/octet-stream
1528 Content-Disposition: attachment; filename="main.dvi"
1529 Content-Transfer-Encoding: base64
1531 SnVzdCBhIHRlc3QgAQo=
1533 --bCsyhTFzCvuiizWE--
1534 ''')
1535 messages = self.db.issue.get('1', 'messages')
1536 messages.sort()
1537 file = self.db.file.getnode (self.db.msg.get(messages[-1], 'files')[0])
1538 self.assertEqual(file.name, 'main.dvi')
1539 self.assertEqual(file.content, 'Just a test \001\n')
1541 def testFollowupStupidQuoting(self):
1542 self.doNewIssue()
1544 self._handle_mail('''Content-Type: text/plain;
1545 charset="iso-8859-1"
1546 From: richard <richard@test.test>
1547 To: issue_tracker@your.tracker.email.domain.example
1548 Message-Id: <followup_dummy_id>
1549 In-Reply-To: <dummy_test_message_id>
1550 Subject: Re: "[issue1] Testing... "
1552 This is a followup
1553 ''')
1554 self.compareMessages(self._get_mail(),
1555 '''FROM: roundup-admin@your.tracker.email.domain.example
1556 TO: chef@bork.bork.bork
1557 Content-Type: text/plain; charset="utf-8"
1558 Subject: [issue1] Testing...
1559 To: chef@bork.bork.bork
1560 From: richard <issue_tracker@your.tracker.email.domain.example>
1561 Reply-To: Roundup issue tracker
1562 <issue_tracker@your.tracker.email.domain.example>
1563 MIME-Version: 1.0
1564 Message-Id: <followup_dummy_id>
1565 In-Reply-To: <dummy_test_message_id>
1566 X-Roundup-Name: Roundup issue tracker
1567 X-Roundup-Loop: hello
1568 X-Roundup-Issue-Status: chatting
1569 Content-Transfer-Encoding: quoted-printable
1572 richard <richard@test.test> added the comment:
1574 This is a followup
1576 ----------
1577 status: unread -> chatting
1579 _______________________________________________________________________
1580 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1581 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1582 _______________________________________________________________________
1583 ''')
1585 def testEmailQuoting(self):
1586 self.instance.config.EMAIL_KEEP_QUOTED_TEXT = 'no'
1587 self.innerTestQuoting('''This is a followup
1588 ''')
1590 def testEmailQuotingRemove(self):
1591 self.instance.config.EMAIL_KEEP_QUOTED_TEXT = 'yes'
1592 self.innerTestQuoting('''Blah blah wrote:
1593 > Blah bklaskdfj sdf asdf jlaskdf skj sdkfjl asdf
1594 > skdjlkjsdfalsdkfjasdlfkj dlfksdfalksd fj
1595 >
1597 This is a followup
1598 ''')
1600 def innerTestQuoting(self, expect):
1601 nodeid = self.doNewIssue()
1603 messages = self.db.issue.get(nodeid, 'messages')
1605 self._handle_mail('''Content-Type: text/plain;
1606 charset="iso-8859-1"
1607 From: richard <richard@test.test>
1608 To: issue_tracker@your.tracker.email.domain.example
1609 Message-Id: <followup_dummy_id>
1610 In-Reply-To: <dummy_test_message_id>
1611 Subject: Re: [issue1] Testing...
1613 Blah blah wrote:
1614 > Blah bklaskdfj sdf asdf jlaskdf skj sdkfjl asdf
1615 > skdjlkjsdfalsdkfjasdlfkj dlfksdfalksd fj
1616 >
1618 This is a followup
1619 ''')
1620 # figure the new message id
1621 newmessages = self.db.issue.get(nodeid, 'messages')
1622 for msg in messages:
1623 newmessages.remove(msg)
1624 messageid = newmessages[0]
1626 self.compareMessages(self.db.msg.get(messageid, 'content'), expect)
1628 def testUserLookup(self):
1629 i = self.db.user.create(username='user1', address='user1@foo.com')
1630 self.assertEqual(uidFromAddress(self.db, ('', 'user1@foo.com'), 0), i)
1631 self.assertEqual(uidFromAddress(self.db, ('', 'USER1@foo.com'), 0), i)
1632 i = self.db.user.create(username='user2', address='USER2@foo.com')
1633 self.assertEqual(uidFromAddress(self.db, ('', 'USER2@foo.com'), 0), i)
1634 self.assertEqual(uidFromAddress(self.db, ('', 'user2@foo.com'), 0), i)
1636 def testUserAlternateLookup(self):
1637 i = self.db.user.create(username='user1', address='user1@foo.com',
1638 alternate_addresses='user1@bar.com')
1639 self.assertEqual(uidFromAddress(self.db, ('', 'user1@bar.com'), 0), i)
1640 self.assertEqual(uidFromAddress(self.db, ('', 'USER1@bar.com'), 0), i)
1642 def testUserCreate(self):
1643 i = uidFromAddress(self.db, ('', 'user@foo.com'), 1)
1644 self.assertNotEqual(uidFromAddress(self.db, ('', 'user@bar.com'), 1), i)
1646 def testRFC2822(self):
1647 ascii_header = "[issue243] This is a \"test\" - with 'quotation' marks"
1648 unicode_header = '[issue244] \xd0\xb0\xd0\xbd\xd0\xb4\xd1\x80\xd0\xb5\xd0\xb9'
1649 unicode_encoded = '=?utf-8?q?[issue244]_=D0=B0=D0=BD=D0=B4=D1=80=D0=B5=D0=B9?='
1650 self.assertEqual(rfc2822.encode_header(ascii_header), ascii_header)
1651 self.assertEqual(rfc2822.encode_header(unicode_header), unicode_encoded)
1653 def testRegistrationConfirmation(self):
1654 otk = "Aj4euk4LZSAdwePohj90SME5SpopLETL"
1655 self.db.getOTKManager().set(otk, username='johannes')
1656 self._handle_mail('''Content-Type: text/plain;
1657 charset="iso-8859-1"
1658 From: Chef <chef@bork.bork.bork>
1659 To: issue_tracker@your.tracker.email.domain.example
1660 Cc: richard@test.test
1661 Message-Id: <dummy_test_message_id>
1662 Subject: Re: Complete your registration to Roundup issue tracker
1663 -- key %s
1665 This is a test confirmation of registration.
1666 ''' % otk)
1667 self.db.user.lookup('johannes')
1669 def testFollowupOnNonIssue(self):
1670 self.db.keyword.create(name='Foo')
1671 self._handle_mail('''Content-Type: text/plain;
1672 charset="iso-8859-1"
1673 From: richard <richard@test.test>
1674 To: issue_tracker@your.tracker.email.domain.example
1675 Message-Id: <followup_dummy_id>
1676 In-Reply-To: <dummy_test_message_id>
1677 Subject: [keyword1] Testing... [name=Bar]
1679 ''')
1680 self.assertEqual(self.db.keyword.get('1', 'name'), 'Bar')
1682 def testResentFrom(self):
1683 nodeid = self._handle_mail('''Content-Type: text/plain;
1684 charset="iso-8859-1"
1685 From: Chef <chef@bork.bork.bork>
1686 Resent-From: mary <mary@test.test>
1687 To: issue_tracker@your.tracker.email.domain.example
1688 Cc: richard@test.test
1689 Message-Id: <dummy_test_message_id>
1690 Subject: [issue] Testing...
1692 This is a test submission of a new issue.
1693 ''')
1694 assert not os.path.exists(SENDMAILDEBUG)
1695 l = self.db.issue.get(nodeid, 'nosy')
1696 l.sort()
1697 self.assertEqual(l, [self.richard_id, self.mary_id])
1698 return nodeid
1700 def testDejaVu(self):
1701 self.assertRaises(IgnoreLoop, self._handle_mail,
1702 '''Content-Type: text/plain;
1703 charset="iso-8859-1"
1704 From: Chef <chef@bork.bork.bork>
1705 X-Roundup-Loop: hello
1706 To: issue_tracker@your.tracker.email.domain.example
1707 Cc: richard@test.test
1708 Message-Id: <dummy_test_message_id>
1709 Subject: Re: [issue] Testing...
1711 Hi, I've been mis-configured to loop messages back to myself.
1712 ''')
1714 def testItsBulkStupid(self):
1715 self.assertRaises(IgnoreBulk, self._handle_mail,
1716 '''Content-Type: text/plain;
1717 charset="iso-8859-1"
1718 From: Chef <chef@bork.bork.bork>
1719 Precedence: bulk
1720 To: issue_tracker@your.tracker.email.domain.example
1721 Cc: richard@test.test
1722 Message-Id: <dummy_test_message_id>
1723 Subject: Re: [issue] Testing...
1725 Hi, I'm on holidays, and this is a dumb auto-responder.
1726 ''')
1728 def testAutoReplyEmailsAreIgnored(self):
1729 self.assertRaises(IgnoreBulk, self._handle_mail,
1730 '''Content-Type: text/plain;
1731 charset="iso-8859-1"
1732 From: Chef <chef@bork.bork.bork>
1733 To: issue_tracker@your.tracker.email.domain.example
1734 Cc: richard@test.test
1735 Message-Id: <dummy_test_message_id>
1736 Subject: Re: [issue] Out of office AutoReply: Back next week
1738 Hi, I am back in the office next week
1739 ''')
1741 def testNoSubject(self):
1742 self.assertRaises(MailUsageError, self._handle_mail,
1743 '''Content-Type: text/plain;
1744 charset="iso-8859-1"
1745 From: Chef <chef@bork.bork.bork>
1746 To: issue_tracker@your.tracker.email.domain.example
1747 Cc: richard@test.test
1748 Reply-To: chef@bork.bork.bork
1749 Message-Id: <dummy_test_message_id>
1751 ''')
1753 #
1754 # TEST FOR INVALID DESIGNATOR HANDLING
1755 #
1756 def testInvalidDesignator(self):
1757 self.assertRaises(MailUsageError, self._handle_mail,
1758 '''Content-Type: text/plain;
1759 charset="iso-8859-1"
1760 From: Chef <chef@bork.bork.bork>
1761 To: issue_tracker@your.tracker.email.domain.example
1762 Subject: [frobulated] testing
1763 Cc: richard@test.test
1764 Reply-To: chef@bork.bork.bork
1765 Message-Id: <dummy_test_message_id>
1767 ''')
1768 self.assertRaises(MailUsageError, self._handle_mail,
1769 '''Content-Type: text/plain;
1770 charset="iso-8859-1"
1771 From: Chef <chef@bork.bork.bork>
1772 To: issue_tracker@your.tracker.email.domain.example
1773 Subject: [issue12345] testing
1774 Cc: richard@test.test
1775 Reply-To: chef@bork.bork.bork
1776 Message-Id: <dummy_test_message_id>
1778 ''')
1780 def testInvalidClassLoose(self):
1781 self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'loose'
1782 nodeid = self._handle_mail('''Content-Type: text/plain;
1783 charset="iso-8859-1"
1784 From: Chef <chef@bork.bork.bork>
1785 To: issue_tracker@your.tracker.email.domain.example
1786 Subject: [frobulated] testing
1787 Cc: richard@test.test
1788 Reply-To: chef@bork.bork.bork
1789 Message-Id: <dummy_test_message_id>
1791 ''')
1792 assert not os.path.exists(SENDMAILDEBUG)
1793 self.assertEqual(self.db.issue.get(nodeid, 'title'),
1794 '[frobulated] testing')
1796 def testInvalidClassLooseReply(self):
1797 self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'loose'
1798 nodeid = self._handle_mail('''Content-Type: text/plain;
1799 charset="iso-8859-1"
1800 From: Chef <chef@bork.bork.bork>
1801 To: issue_tracker@your.tracker.email.domain.example
1802 Subject: Re: [frobulated] testing
1803 Cc: richard@test.test
1804 Reply-To: chef@bork.bork.bork
1805 Message-Id: <dummy_test_message_id>
1807 ''')
1808 assert not os.path.exists(SENDMAILDEBUG)
1809 self.assertEqual(self.db.issue.get(nodeid, 'title'),
1810 '[frobulated] testing')
1812 def testInvalidClassLoose(self):
1813 self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'loose'
1814 nodeid = self._handle_mail('''Content-Type: text/plain;
1815 charset="iso-8859-1"
1816 From: Chef <chef@bork.bork.bork>
1817 To: issue_tracker@your.tracker.email.domain.example
1818 Subject: [issue1234] testing
1819 Cc: richard@test.test
1820 Reply-To: chef@bork.bork.bork
1821 Message-Id: <dummy_test_message_id>
1823 ''')
1824 assert not os.path.exists(SENDMAILDEBUG)
1825 self.assertEqual(self.db.issue.get(nodeid, 'title'),
1826 '[issue1234] testing')
1828 def testClassLooseOK(self):
1829 self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'loose'
1830 self.db.keyword.create(name='Foo')
1831 nodeid = self._handle_mail('''Content-Type: text/plain;
1832 charset="iso-8859-1"
1833 From: Chef <chef@bork.bork.bork>
1834 To: issue_tracker@your.tracker.email.domain.example
1835 Subject: [keyword1] Testing... [name=Bar]
1836 Cc: richard@test.test
1837 Reply-To: chef@bork.bork.bork
1838 Message-Id: <dummy_test_message_id>
1840 ''')
1841 assert not os.path.exists(SENDMAILDEBUG)
1842 self.assertEqual(self.db.keyword.get('1', 'name'), 'Bar')
1844 def testClassStrictInvalid(self):
1845 self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'strict'
1846 self.instance.config.MAILGW_DEFAULT_CLASS = ''
1848 message = '''Content-Type: text/plain;
1849 charset="iso-8859-1"
1850 From: Chef <chef@bork.bork.bork>
1851 To: issue_tracker@your.tracker.email.domain.example
1852 Subject: Testing...
1853 Cc: richard@test.test
1854 Reply-To: chef@bork.bork.bork
1855 Message-Id: <dummy_test_message_id>
1857 '''
1858 self.assertRaises(MailUsageError, self._handle_mail, message)
1860 def testClassStrictValid(self):
1861 self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'strict'
1862 self.instance.config.MAILGW_DEFAULT_CLASS = ''
1864 nodeid = self._handle_mail('''Content-Type: text/plain;
1865 charset="iso-8859-1"
1866 From: Chef <chef@bork.bork.bork>
1867 To: issue_tracker@your.tracker.email.domain.example
1868 Subject: [issue] Testing...
1869 Cc: richard@test.test
1870 Reply-To: chef@bork.bork.bork
1871 Message-Id: <dummy_test_message_id>
1873 ''')
1875 assert not os.path.exists(SENDMAILDEBUG)
1876 self.assertEqual(self.db.issue.get(nodeid, 'title'), 'Testing...')
1878 #
1879 # TEST FOR INVALID COMMANDS HANDLING
1880 #
1881 def testInvalidCommands(self):
1882 self.assertRaises(MailUsageError, self._handle_mail,
1883 '''Content-Type: text/plain;
1884 charset="iso-8859-1"
1885 From: Chef <chef@bork.bork.bork>
1886 To: issue_tracker@your.tracker.email.domain.example
1887 Subject: testing [frobulated]
1888 Cc: richard@test.test
1889 Reply-To: chef@bork.bork.bork
1890 Message-Id: <dummy_test_message_id>
1892 ''')
1894 def testInvalidCommandPassthrough(self):
1895 self.instance.config.MAILGW_SUBJECT_SUFFIX_PARSING = 'none'
1896 nodeid = self._handle_mail('''Content-Type: text/plain;
1897 charset="iso-8859-1"
1898 From: Chef <chef@bork.bork.bork>
1899 To: issue_tracker@your.tracker.email.domain.example
1900 Subject: testing [frobulated]
1901 Cc: richard@test.test
1902 Reply-To: chef@bork.bork.bork
1903 Message-Id: <dummy_test_message_id>
1905 ''')
1906 assert not os.path.exists(SENDMAILDEBUG)
1907 self.assertEqual(self.db.issue.get(nodeid, 'title'),
1908 'testing [frobulated]')
1910 def testInvalidCommandPassthroughLoose(self):
1911 self.instance.config.MAILGW_SUBJECT_SUFFIX_PARSING = 'loose'
1912 nodeid = self._handle_mail('''Content-Type: text/plain;
1913 charset="iso-8859-1"
1914 From: Chef <chef@bork.bork.bork>
1915 To: issue_tracker@your.tracker.email.domain.example
1916 Subject: testing [frobulated]
1917 Cc: richard@test.test
1918 Reply-To: chef@bork.bork.bork
1919 Message-Id: <dummy_test_message_id>
1921 ''')
1922 assert not os.path.exists(SENDMAILDEBUG)
1923 self.assertEqual(self.db.issue.get(nodeid, 'title'),
1924 'testing [frobulated]')
1926 def testInvalidCommandPassthroughLooseOK(self):
1927 self.instance.config.MAILGW_SUBJECT_SUFFIX_PARSING = 'loose'
1928 nodeid = self._handle_mail('''Content-Type: text/plain;
1929 charset="iso-8859-1"
1930 From: Chef <chef@bork.bork.bork>
1931 To: issue_tracker@your.tracker.email.domain.example
1932 Subject: testing [assignedto=mary]
1933 Cc: richard@test.test
1934 Reply-To: chef@bork.bork.bork
1935 Message-Id: <dummy_test_message_id>
1937 ''')
1938 assert not os.path.exists(SENDMAILDEBUG)
1939 self.assertEqual(self.db.issue.get(nodeid, 'title'), 'testing')
1940 self.assertEqual(self.db.issue.get(nodeid, 'assignedto'), self.mary_id)
1942 def testCommandDelimiters(self):
1943 self.instance.config.MAILGW_SUBJECT_SUFFIX_DELIMITERS = '{}'
1944 nodeid = self._handle_mail('''Content-Type: text/plain;
1945 charset="iso-8859-1"
1946 From: Chef <chef@bork.bork.bork>
1947 To: issue_tracker@your.tracker.email.domain.example
1948 Subject: testing {assignedto=mary}
1949 Cc: richard@test.test
1950 Reply-To: chef@bork.bork.bork
1951 Message-Id: <dummy_test_message_id>
1953 ''')
1954 assert not os.path.exists(SENDMAILDEBUG)
1955 self.assertEqual(self.db.issue.get(nodeid, 'title'), 'testing')
1956 self.assertEqual(self.db.issue.get(nodeid, 'assignedto'), self.mary_id)
1958 def testPrefixDelimiters(self):
1959 self.instance.config.MAILGW_SUBJECT_SUFFIX_DELIMITERS = '{}'
1960 self.db.keyword.create(name='Foo')
1961 self._handle_mail('''Content-Type: text/plain;
1962 charset="iso-8859-1"
1963 From: richard <richard@test.test>
1964 To: issue_tracker@your.tracker.email.domain.example
1965 Message-Id: <followup_dummy_id>
1966 In-Reply-To: <dummy_test_message_id>
1967 Subject: {keyword1} Testing... {name=Bar}
1969 ''')
1970 assert not os.path.exists(SENDMAILDEBUG)
1971 self.assertEqual(self.db.keyword.get('1', 'name'), 'Bar')
1973 def testCommandDelimitersIgnore(self):
1974 self.instance.config.MAILGW_SUBJECT_SUFFIX_DELIMITERS = '{}'
1975 nodeid = self._handle_mail('''Content-Type: text/plain;
1976 charset="iso-8859-1"
1977 From: Chef <chef@bork.bork.bork>
1978 To: issue_tracker@your.tracker.email.domain.example
1979 Subject: testing [assignedto=mary]
1980 Cc: richard@test.test
1981 Reply-To: chef@bork.bork.bork
1982 Message-Id: <dummy_test_message_id>
1984 ''')
1985 assert not os.path.exists(SENDMAILDEBUG)
1986 self.assertEqual(self.db.issue.get(nodeid, 'title'),
1987 'testing [assignedto=mary]')
1988 self.assertEqual(self.db.issue.get(nodeid, 'assignedto'), None)
1990 def testReplytoMatch(self):
1991 self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'loose'
1992 nodeid = self.doNewIssue()
1993 nodeid2 = self._handle_mail('''Content-Type: text/plain;
1994 charset="iso-8859-1"
1995 From: Chef <chef@bork.bork.bork>
1996 To: issue_tracker@your.tracker.email.domain.example
1997 Message-Id: <dummy_test_message_id2>
1998 In-Reply-To: <dummy_test_message_id>
1999 Subject: Testing...
2001 Followup message.
2002 ''')
2004 nodeid3 = self._handle_mail('''Content-Type: text/plain;
2005 charset="iso-8859-1"
2006 From: Chef <chef@bork.bork.bork>
2007 To: issue_tracker@your.tracker.email.domain.example
2008 Message-Id: <dummy_test_message_id3>
2009 In-Reply-To: <dummy_test_message_id2>
2010 Subject: Testing...
2012 Yet another message in the same thread/issue.
2013 ''')
2015 self.assertEqual(nodeid, nodeid2)
2016 self.assertEqual(nodeid, nodeid3)
2018 def testHelpSubject(self):
2019 message = '''Content-Type: text/plain;
2020 charset="iso-8859-1"
2021 From: Chef <chef@bork.bork.bork>
2022 To: issue_tracker@your.tracker.email.domain.example
2023 Message-Id: <dummy_test_message_id2>
2024 In-Reply-To: <dummy_test_message_id>
2025 Subject: hElp
2028 '''
2029 self.assertRaises(MailUsageHelp, self._handle_mail, message)
2031 def testMaillistSubject(self):
2032 self.instance.config.MAILGW_SUBJECT_SUFFIX_DELIMITERS = '[]'
2033 self.db.keyword.create(name='Foo')
2034 self._handle_mail('''Content-Type: text/plain;
2035 charset="iso-8859-1"
2036 From: Chef <chef@bork.bork.bork>
2037 To: issue_tracker@your.tracker.email.domain.example
2038 Subject: [mailinglist-name] [keyword1] Testing.. [name=Bar]
2039 Cc: richard@test.test
2040 Reply-To: chef@bork.bork.bork
2041 Message-Id: <dummy_test_message_id>
2043 ''')
2045 assert not os.path.exists(SENDMAILDEBUG)
2046 self.assertEqual(self.db.keyword.get('1', 'name'), 'Bar')
2048 def testUnknownPrefixSubject(self):
2049 self.db.keyword.create(name='Foo')
2050 self._handle_mail('''Content-Type: text/plain;
2051 charset="iso-8859-1"
2052 From: Chef <chef@bork.bork.bork>
2053 To: issue_tracker@your.tracker.email.domain.example
2054 Subject: VeryStrangeRe: [keyword1] Testing.. [name=Bar]
2055 Cc: richard@test.test
2056 Reply-To: chef@bork.bork.bork
2057 Message-Id: <dummy_test_message_id>
2059 ''')
2061 assert not os.path.exists(SENDMAILDEBUG)
2062 self.assertEqual(self.db.keyword.get('1', 'name'), 'Bar')
2064 def testOneCharSubject(self):
2065 message = '''Content-Type: text/plain;
2066 charset="iso-8859-1"
2067 From: Chef <chef@bork.bork.bork>
2068 To: issue_tracker@your.tracker.email.domain.example
2069 Subject: b
2070 Cc: richard@test.test
2071 Reply-To: chef@bork.bork.bork
2072 Message-Id: <dummy_test_message_id>
2074 '''
2075 try:
2076 self._handle_mail(message)
2077 except MailUsageError:
2078 self.fail('MailUsageError raised')
2080 def testIssueidLast(self):
2081 nodeid1 = self.doNewIssue()
2082 nodeid2 = self._handle_mail('''Content-Type: text/plain;
2083 charset="iso-8859-1"
2084 From: mary <mary@test.test>
2085 To: issue_tracker@your.tracker.email.domain.example
2086 Message-Id: <followup_dummy_id>
2087 In-Reply-To: <dummy_test_message_id>
2088 Subject: New title [issue1]
2090 This is a second followup
2091 ''')
2093 assert nodeid1 == nodeid2
2094 self.assertEqual(self.db.issue.get(nodeid2, 'title'), "Testing...")
2096 def testSecurityMessagePermissionContent(self):
2097 id = self.doNewIssue()
2098 issue = self.db.issue.getnode (id)
2099 self.db.security.addRole(name='Nomsg')
2100 self.db.security.addPermissionToRole('Nomsg', 'Email Access')
2101 for cl in 'issue', 'file', 'keyword':
2102 for p in 'View', 'Edit', 'Create':
2103 self.db.security.addPermissionToRole('Nomsg', p, cl)
2104 self.db.user.set(self.mary_id, roles='Nomsg')
2105 nodeid = self._handle_mail('''Content-Type: text/plain;
2106 charset="iso-8859-1"
2107 From: Chef <chef@bork.bork.bork>
2108 To: issue_tracker@your.tracker.email.domain.example
2109 Message-Id: <dummy_test_message_id_2>
2110 Subject: [issue%(id)s] Testing... [nosy=+mary]
2112 Just a test reply
2113 '''%locals())
2114 assert os.path.exists(SENDMAILDEBUG)
2115 self.compareMessages(self._get_mail(),
2116 '''FROM: roundup-admin@your.tracker.email.domain.example
2117 TO: chef@bork.bork.bork, richard@test.test
2118 Content-Type: text/plain; charset="utf-8"
2119 Subject: [issue1] Testing...
2120 To: richard@test.test
2121 From: "Bork, Chef" <issue_tracker@your.tracker.email.domain.example>
2122 Reply-To: Roundup issue tracker
2123 <issue_tracker@your.tracker.email.domain.example>
2124 MIME-Version: 1.0
2125 Message-Id: <dummy_test_message_id_2>
2126 In-Reply-To: <dummy_test_message_id>
2127 X-Roundup-Name: Roundup issue tracker
2128 X-Roundup-Loop: hello
2129 X-Roundup-Issue-Status: chatting
2130 Content-Transfer-Encoding: quoted-printable
2133 Bork, Chef <chef@bork.bork.bork> added the comment:
2135 Just a test reply
2137 ----------
2138 nosy: +mary
2139 status: unread -> chatting
2141 _______________________________________________________________________
2142 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
2143 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
2144 _______________________________________________________________________
2145 ''')
2147 def testOutlookAttachment(self):
2148 message = '''X-MimeOLE: Produced By Microsoft Exchange V6.5
2149 Content-class: urn:content-classes:message
2150 MIME-Version: 1.0
2151 Content-Type: multipart/mixed;
2152 boundary="----_=_NextPart_001_01CACA65.40A51CBC"
2153 Subject: Example of a failed outlook attachment e-mail
2154 Date: Tue, 23 Mar 2010 01:43:44 -0700
2155 Message-ID: <CA37F17219784343816CA6613D2E339205E7D0F9@nrcwstexb1.nrc.ca>
2156 X-MS-Has-Attach: yes
2157 X-MS-TNEF-Correlator:
2158 Thread-Topic: Example of a failed outlook attachment e-mail
2159 Thread-Index: AcrKJo/t3pUBBwTpSwWNE3LE67UBDQ==
2160 From: "Hugh" <richard@test.test>
2161 To: <richard@test.test>
2162 X-OriginalArrivalTime: 23 Mar 2010 08:45:57.0350 (UTC) FILETIME=[41893860:01CACA65]
2164 This is a multi-part message in MIME format.
2166 ------_=_NextPart_001_01CACA65.40A51CBC
2167 Content-Type: multipart/alternative;
2168 boundary="----_=_NextPart_002_01CACA65.40A51CBC"
2171 ------_=_NextPart_002_01CACA65.40A51CBC
2172 Content-Type: text/plain;
2173 charset="us-ascii"
2174 Content-Transfer-Encoding: quoted-printable
2177 Hi Richard,
2179 I suppose this isn't the exact message that was sent but is a resend of
2180 one of my trial messages that failed. For your benefit I changed the
2181 subject line and am adding these words to the message body. Should
2182 still be as problematic, but if you like I can resend an exact copy of a
2183 failed message changing nothing except putting your address instead of
2184 our tracker.
2186 Thanks very much for taking time to look into this. Much appreciated.
2188 <<battery backup>>=20
2190 ------_=_NextPart_002_01CACA65.40A51CBC
2191 Content-Type: text/html;
2192 charset="us-ascii"
2193 Content-Transfer-Encoding: quoted-printable
2195 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
2196 <HTML>
2197 <HEAD>
2198 <META HTTP-EQUIV=3D"Content-Type" CONTENT=3D"text/html; =
2199 charset=3Dus-ascii">
2200 <META NAME=3D"Generator" CONTENT=3D"MS Exchange Server version =
2201 6.5.7654.12">
2202 <TITLE>Example of a failed outlook attachment e-mail</TITLE>
2203 </HEAD>
2204 <BODY>
2205 <!-- Converted from text/rtf format -->
2206 <BR>
2208 <P><FONT SIZE=3D2 FACE=3D"Arial">Hi Richard,</FONT>
2209 </P>
2211 <P><FONT SIZE=3D2 FACE=3D"Arial">I suppose this isn't the exact message =
2212 that was sent but is a resend of one of my trial messages that =
2213 failed. For your benefit I changed the subject line and am adding =
2214 these words to the message body. Should still be as problematic, =
2215 but if you like I can resend an exact copy of a failed message changing =
2216 nothing except putting your address instead of our tracker.</FONT></P>
2218 <P><FONT SIZE=3D2 FACE=3D"Arial">Thanks very much for taking time to =
2219 look into this. Much appreciated.</FONT>
2220 </P>
2221 <BR>
2223 <P><FONT FACE=3D"Arial" SIZE=3D2 COLOR=3D"#000000"> <<battery =
2224 backup>> </FONT>
2225 </P>
2227 </BODY>
2228 </HTML>
2229 ------_=_NextPart_002_01CACA65.40A51CBC--
2231 ------_=_NextPart_001_01CACA65.40A51CBC
2232 Content-Type: message/rfc822
2233 Content-Transfer-Encoding: 7bit
2235 X-MimeOLE: Produced By Microsoft Exchange V6.5
2236 MIME-Version: 1.0
2237 Content-Type: multipart/alternative;
2238 boundary="----_=_NextPart_003_01CAC15A.29717800"
2239 X-OriginalArrivalTime: 11 Mar 2010 20:33:51.0249 (UTC) FILETIME=[28FEE010:01CAC15A]
2240 Content-class: urn:content-classes:message
2241 Subject: battery backup
2242 Date: Thu, 11 Mar 2010 13:33:43 -0700
2243 Message-ID: <p06240809c7bf02f9624c@[128.114.22.203]>
2244 X-MS-Has-Attach:
2245 X-MS-TNEF-Correlator:
2246 Thread-Topic: battery backup
2247 Thread-Index: AcrBWimtulTrSvBdQ2CcfZ8lyQdxmQ==
2248 From: "Jerry" <jerry@test.test>
2249 To: "Hugh" <hugh@test.test>
2251 This is a multi-part message in MIME format.
2253 ------_=_NextPart_003_01CAC15A.29717800
2254 Content-Type: text/plain;
2255 charset="iso-8859-1"
2256 Content-Transfer-Encoding: quoted-printable
2258 Dear Hugh,
2259 A car batter has an energy capacity of ~ 500Wh. A UPS=20
2260 battery is worse than this.
2262 if we need to provied 100kW for 30 minutes that will take 100 car=20
2263 batteries. This seems like an awful lot of batteries.
2265 Of course I like your idea of making the time 1 minute, so we get to=20
2266 a more modest number of batteries
2268 Jerry
2271 ------_=_NextPart_003_01CAC15A.29717800
2272 Content-Type: text/html;
2273 charset="iso-8859-1"
2274 Content-Transfer-Encoding: quoted-printable
2276 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
2277 <HTML>
2278 <HEAD>
2279 <META HTTP-EQUIV=3D"Content-Type" CONTENT=3D"text/html; =
2280 charset=3Diso-8859-1">
2281 <META NAME=3D"Generator" CONTENT=3D"MS Exchange Server version =
2282 6.5.7654.12">
2283 <TITLE>battery backup</TITLE>
2284 </HEAD>
2285 <BODY>
2286 <!-- Converted from text/plain format -->
2288 <P><FONT SIZE=3D2>Dear Hugh,</FONT>
2290 <BR> <FONT SIZE=3D2>A car =
2291 batter has an energy capacity of ~ 500Wh. A UPS </FONT>
2293 <BR><FONT SIZE=3D2>battery is worse than this.</FONT>
2294 </P>
2296 <P><FONT SIZE=3D2>if we need to provied 100kW for 30 minutes that will =
2297 take 100 car </FONT>
2299 <BR><FONT SIZE=3D2>batteries. This seems like an awful lot of =
2300 batteries.</FONT>
2301 </P>
2303 <P><FONT SIZE=3D2>Of course I like your idea of making the time 1 =
2304 minute, so we get to </FONT>
2306 <BR><FONT SIZE=3D2>a more modest number of batteries</FONT>
2307 </P>
2309 <P><FONT SIZE=3D2>Jerry</FONT>
2310 </P>
2312 </BODY>
2313 </HTML>
2314 ------_=_NextPart_003_01CAC15A.29717800--
2316 ------_=_NextPart_001_01CACA65.40A51CBC--
2317 '''
2318 nodeid = self._handle_mail(message)
2319 assert not os.path.exists(SENDMAILDEBUG)
2320 msgid = self.db.issue.get(nodeid, 'messages')[0]
2321 self.assert_(self.db.msg.get(msgid, 'content').startswith('Hi Richard'))
2322 self.assertEqual(self.db.msg.get(msgid, 'files'), ['1', '2'])
2323 fileid = self.db.msg.get(msgid, 'files')[0]
2324 self.assertEqual(self.db.file.get(fileid, 'type'), 'text/html')
2325 fileid = self.db.msg.get(msgid, 'files')[1]
2326 self.assertEqual(self.db.file.get(fileid, 'type'), 'message/rfc822')
2328 def testForwardedMessageAttachment(self):
2329 message = '''Return-Path: <rgg@test.test>
2330 Received: from localhost(127.0.0.1), claiming to be "[115.130.26.69]"
2331 via SMTP by localhost, id smtpdAAApLaWrq; Tue Apr 13 23:10:05 2010
2332 Message-ID: <4BC4F9C7.50409@test.test>
2333 Date: Wed, 14 Apr 2010 09:09:59 +1000
2334 From: Rupert Goldie <rgg@test.test>
2335 User-Agent: Thunderbird 2.0.0.24 (Windows/20100228)
2336 MIME-Version: 1.0
2337 To: ekit issues <issues@test.test>
2338 Subject: [Fwd: PHP ERROR (fb)] post limit reached
2339 Content-Type: multipart/mixed; boundary="------------000807090608060304010403"
2341 This is a multi-part message in MIME format.
2342 --------------000807090608060304010403
2343 Content-Type: text/plain; charset=ISO-8859-1; format=flowed
2344 Content-Transfer-Encoding: 7bit
2346 Catch this exception and log it without emailing.
2348 --------------000807090608060304010403
2349 Content-Type: message/rfc822; name="PHP ERROR (fb).eml"
2350 Content-Transfer-Encoding: 7bit
2351 Content-Disposition: inline; filename="PHP ERROR (fb).eml"
2353 Return-Path: <ektravj@test.test>
2354 X-Sieve: CMU Sieve 2.2
2355 via SMTP by crown.off.ekorp.com, id smtpdAAA1JaW1o; Tue Apr 13 23:01:04 2010
2356 X-Virus-Scanned: by amavisd-new at ekit.com
2357 To: facebook-errors@test.test
2358 From: ektravj@test.test
2359 Subject: PHP ERROR (fb)
2360 Message-Id: <20100413230100.D601D27E84@mail2.elax3.ekorp.com>
2361 Date: Tue, 13 Apr 2010 23:01:00 +0000 (UTC)
2363 [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
2364 Stack trace:
2365 #0 /app/01/www/virtual/fb.ekit.com/htdocs/gateway/ekit/feed/index.php(178): fb_exceptions(Object(FacebookRestClientException))
2366 #1 {main}
2367 thrown in /app/01/www/virtual/fb.ekit.com/htdocs/includes/functions.php on line 280
2370 --------------000807090608060304010403--
2371 '''
2372 nodeid = self._handle_mail(message)
2373 assert not os.path.exists(SENDMAILDEBUG)
2374 msgid = self.db.issue.get(nodeid, 'messages')[0]
2375 self.assertEqual(self.db.msg.get(msgid, 'content'),
2376 'Catch this exception and log it without emailing.')
2377 self.assertEqual(self.db.msg.get(msgid, 'files'), ['1'])
2378 fileid = self.db.msg.get(msgid, 'files')[0]
2379 self.assertEqual(self.db.file.get(fileid, 'type'), 'message/rfc822')
2381 def test_suite():
2382 suite = unittest.TestSuite()
2383 suite.addTest(unittest.makeSuite(MailgwTestCase))
2384 return suite
2386 if __name__ == '__main__':
2387 runner = unittest.TextTestRunner()
2388 unittest.main(testRunner=runner)
2390 # vim: set filetype=python sts=4 sw=4 et si :