295d06a1e3a64d8b8fc76a1c777ebca06ea48d3a
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.mailgw import MailGW, Unauthorized, uidFromAddress, \
25 parseContent, IgnoreLoop, IgnoreBulk, MailUsageError, MailUsageHelp
26 from roundup import init, instance, password, rfc2822, __version__
27 from roundup.anypy.sets_ import set
29 #import db_test_base
30 import memorydb
32 class Message(rfc822.Message):
33 """String-based Message class with equivalence test."""
34 def __init__(self, s):
35 rfc822.Message.__init__(self, StringIO(s.strip()))
37 def __eq__(self, other):
38 return (self.dict == other.dict and
39 self.fp.read() == other.fp.read())
41 class Tracker(object):
42 def open(self, journaltag):
43 return self.db
45 class DiffHelper:
46 def compareMessages(self, new, old):
47 """Compare messages for semantic equivalence."""
48 new, old = Message(new), Message(old)
50 # all Roundup-generated messages have "Precedence: bulk"
51 old['Precedence'] = 'bulk'
53 # don't try to compare the date
54 del new['date'], old['date']
56 if not new == old:
57 res = []
59 replace = {}
60 for key in new.keys():
61 if key.startswith('from '):
62 # skip the unix from line
63 continue
64 if key.lower() == 'x-roundup-version':
65 # version changes constantly, so handle it specially
66 if new[key] != __version__:
67 res.append(' %s: %r != %r' % (key, __version__,
68 new[key]))
69 elif key.lower() == 'content-type' and 'boundary=' in new[key]:
70 # handle mime messages
71 newmime = new[key].split('=',1)[-1].strip('"')
72 oldmime = old.get(key, '').split('=',1)[-1].strip('"')
73 replace ['--' + newmime] = '--' + oldmime
74 replace ['--' + newmime + '--'] = '--' + oldmime + '--'
75 elif new.get(key, '') != old.get(key, ''):
76 res.append(' %s: %r != %r' % (key, old.get(key, ''),
77 new.get(key, '')))
79 body_diff = self.compareStrings(new.fp.read(), old.fp.read(),
80 replace=replace)
81 if body_diff:
82 res.append('')
83 res.extend(body_diff)
85 if res:
86 res.insert(0, 'Generated message not correct (diff follows, expected vs. actual):')
87 raise AssertionError, '\n'.join(res)
89 def compareStrings(self, s2, s1, replace={}):
90 '''Note the reversal of s2 and s1 - difflib.SequenceMatcher wants
91 the first to be the "original" but in the calls in this file,
92 the second arg is the original. Ho hum.
93 Do replacements over the replace dict -- used for mime boundary
94 '''
95 l1 = s1.strip().split('\n')
96 l2 = [replace.get(i,i) for i in s2.strip().split('\n')]
97 if l1 == l2:
98 return
99 s = difflib.SequenceMatcher(None, l1, l2)
100 res = []
101 for value, s1s, s1e, s2s, s2e in s.get_opcodes():
102 if value == 'equal':
103 for i in range(s1s, s1e):
104 res.append(' %s'%l1[i])
105 elif value == 'delete':
106 for i in range(s1s, s1e):
107 res.append('- %s'%l1[i])
108 elif value == 'insert':
109 for i in range(s2s, s2e):
110 res.append('+ %s'%l2[i])
111 elif value == 'replace':
112 for i, j in zip(range(s1s, s1e), range(s2s, s2e)):
113 res.append('- %s'%l1[i])
114 res.append('+ %s'%l2[j])
116 return res
118 class MailgwTestCase(unittest.TestCase, DiffHelper):
119 count = 0
120 schema = 'classic'
121 def setUp(self):
122 MailgwTestCase.count = MailgwTestCase.count + 1
124 # and open the database / "instance"
125 self.db = memorydb.create('admin')
126 self.instance = Tracker()
127 self.instance.db = self.db
128 self.instance.config = self.db.config
129 self.instance.MailGW = MailGW
131 self.chef_id = self.db.user.create(username='Chef',
132 address='chef@bork.bork.bork', realname='Bork, Chef', roles='User')
133 self.richard_id = self.db.user.create(username='richard',
134 address='richard@test.test', roles='User')
135 self.mary_id = self.db.user.create(username='mary',
136 address='mary@test.test', roles='User', realname='Contrary, Mary')
137 self.john_id = self.db.user.create(username='john',
138 address='john@test.test', roles='User', realname='John Doe',
139 alternate_addresses='jondoe@test.test\njohn.doe@test.test')
140 self.rgg_id = self.db.user.create(username='rgg',
141 address='rgg@test.test', roles='User')
143 def tearDown(self):
144 if os.path.exists(SENDMAILDEBUG):
145 os.remove(SENDMAILDEBUG)
146 self.db.close()
148 def _create_mailgw(self, message):
149 class MailGW(self.instance.MailGW):
150 def handle_message(self, message):
151 return self._handle_message(message)
152 handler = MailGW(self.instance)
153 handler.db = self.db
154 return handler
156 def _handle_mail(self, message):
157 handler = self._create_mailgw(message)
158 handler.trapExceptions = 0
159 return handler.main(StringIO(message))
161 def _get_mail(self):
162 f = open(SENDMAILDEBUG)
163 try:
164 return f.read()
165 finally:
166 f.close()
168 def testEmptyMessage(self):
169 nodeid = self._handle_mail('''Content-Type: text/plain;
170 charset="iso-8859-1"
171 From: Chef <chef@bork.bork.bork>
172 To: issue_tracker@your.tracker.email.domain.example
173 Cc: richard@test.test
174 Reply-To: chef@bork.bork.bork
175 Message-Id: <dummy_test_message_id>
176 Subject: [issue] Testing...
178 ''')
179 assert not os.path.exists(SENDMAILDEBUG)
180 self.assertEqual(self.db.issue.get(nodeid, 'title'), 'Testing...')
182 def testMessageWithFromInIt(self):
183 nodeid = self._handle_mail('''Content-Type: text/plain;
184 charset="iso-8859-1"
185 From: Chef <chef@bork.bork.bork>
186 To: issue_tracker@your.tracker.email.domain.example
187 Cc: richard@test.test
188 Reply-To: chef@bork.bork.bork
189 Message-Id: <dummy_test_message_id>
190 Subject: [issue] Testing...
192 From here to there!
193 ''')
194 assert not os.path.exists(SENDMAILDEBUG)
195 msgid = self.db.issue.get(nodeid, 'messages')[0]
196 self.assertEqual(self.db.msg.get(msgid, 'content'), 'From here to there!')
198 def doNewIssue(self):
199 nodeid = self._handle_mail('''Content-Type: text/plain;
200 charset="iso-8859-1"
201 From: Chef <chef@bork.bork.bork>
202 To: issue_tracker@your.tracker.email.domain.example
203 Cc: richard@test.test
204 Message-Id: <dummy_test_message_id>
205 Subject: [issue] Testing...
207 This is a test submission of a new issue.
208 ''')
209 assert not os.path.exists(SENDMAILDEBUG)
210 l = self.db.issue.get(nodeid, 'nosy')
211 l.sort()
212 self.assertEqual(l, [self.chef_id, self.richard_id])
213 return nodeid
215 def testNewIssue(self):
216 self.doNewIssue()
218 def testNewIssueNosy(self):
219 self.instance.config.ADD_AUTHOR_TO_NOSY = 'yes'
220 nodeid = self._handle_mail('''Content-Type: text/plain;
221 charset="iso-8859-1"
222 From: Chef <chef@bork.bork.bork>
223 To: issue_tracker@your.tracker.email.domain.example
224 Cc: richard@test.test
225 Message-Id: <dummy_test_message_id>
226 Subject: [issue] Testing...
228 This is a test submission of a new issue.
229 ''')
230 assert not os.path.exists(SENDMAILDEBUG)
231 l = self.db.issue.get(nodeid, 'nosy')
232 l.sort()
233 self.assertEqual(l, [self.chef_id, self.richard_id])
235 def testAlternateAddress(self):
236 self._handle_mail('''Content-Type: text/plain;
237 charset="iso-8859-1"
238 From: John Doe <john.doe@test.test>
239 To: issue_tracker@your.tracker.email.domain.example
240 Message-Id: <dummy_test_message_id>
241 Subject: [issue] Testing...
243 This is a test submission of a new issue.
244 ''')
245 userlist = self.db.user.list()
246 assert not os.path.exists(SENDMAILDEBUG)
247 self.assertEqual(userlist, self.db.user.list(),
248 "user created when it shouldn't have been")
250 def testNewIssueNoClass(self):
251 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 Cc: richard@test.test
256 Message-Id: <dummy_test_message_id>
257 Subject: Testing...
259 This is a test submission of a new issue.
260 ''')
261 assert not os.path.exists(SENDMAILDEBUG)
263 def testNewIssueAuthMsg(self):
264 # TODO: fix the damn config - this is apalling
265 self.db.config.MESSAGES_TO_AUTHOR = 'yes'
266 self._handle_mail('''Content-Type: text/plain;
267 charset="iso-8859-1"
268 From: Chef <chef@bork.bork.bork>
269 To: issue_tracker@your.tracker.email.domain.example
270 Message-Id: <dummy_test_message_id>
271 Subject: [issue] Testing... [nosy=mary; assignedto=richard]
273 This is a test submission of a new issue.
274 ''')
275 self.compareMessages(self._get_mail(),
276 '''FROM: roundup-admin@your.tracker.email.domain.example
277 TO: chef@bork.bork.bork, mary@test.test, richard@test.test
278 Content-Type: text/plain; charset="utf-8"
279 Subject: [issue1] Testing...
280 To: chef@bork.bork.bork, mary@test.test, richard@test.test
281 From: "Bork, Chef" <issue_tracker@your.tracker.email.domain.example>
282 Reply-To: Roundup issue tracker
283 <issue_tracker@your.tracker.email.domain.example>
284 MIME-Version: 1.0
285 Message-Id: <dummy_test_message_id>
286 X-Roundup-Name: Roundup issue tracker
287 X-Roundup-Loop: hello
288 X-Roundup-Issue-Status: unread
289 Content-Transfer-Encoding: quoted-printable
292 New submission from Bork, Chef <chef@bork.bork.bork>:
294 This is a test submission of a new issue.
296 ----------
297 assignedto: richard
298 messages: 1
299 nosy: Chef, mary, richard
300 status: unread
301 title: Testing...
303 _______________________________________________________________________
304 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
305 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
306 _______________________________________________________________________
307 ''')
309 def testNewIssueNoAuthorInfo(self):
310 self.db.config.MAIL_ADD_AUTHORINFO = 'no'
311 self._handle_mail('''Content-Type: text/plain;
312 charset="iso-8859-1"
313 From: Chef <chef@bork.bork.bork>
314 To: issue_tracker@your.tracker.email.domain.example
315 Message-Id: <dummy_test_message_id>
316 Subject: [issue] Testing... [nosy=mary; assignedto=richard]
318 This is a test submission of a new issue.
319 ''')
320 self.compareMessages(self._get_mail(),
321 '''FROM: roundup-admin@your.tracker.email.domain.example
322 TO: chef@bork.bork.bork, mary@test.test, richard@test.test
323 Content-Type: text/plain; charset="utf-8"
324 Subject: [issue1] Testing...
325 To: mary@test.test, richard@test.test
326 From: "Bork, Chef" <issue_tracker@your.tracker.email.domain.example>
327 Reply-To: Roundup issue tracker
328 <issue_tracker@your.tracker.email.domain.example>
329 MIME-Version: 1.0
330 Message-Id: <dummy_test_message_id>
331 X-Roundup-Name: Roundup issue tracker
332 X-Roundup-Loop: hello
333 X-Roundup-Issue-Status: unread
334 Content-Transfer-Encoding: quoted-printable
336 This is a test submission of a new issue.
338 ----------
339 assignedto: richard
340 messages: 1
341 nosy: Chef, mary, richard
342 status: unread
343 title: Testing...
345 _______________________________________________________________________
346 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
347 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
348 _______________________________________________________________________
349 ''')
351 def testNewIssueNoAuthorEmail(self):
352 self.db.config.MAIL_ADD_AUTHOREMAIL = 'no'
353 self._handle_mail('''Content-Type: text/plain;
354 charset="iso-8859-1"
355 From: Chef <chef@bork.bork.bork>
356 To: issue_tracker@your.tracker.email.domain.example
357 Message-Id: <dummy_test_message_id>
358 Subject: [issue] Testing... [nosy=mary; assignedto=richard]
360 This is a test submission of a new issue.
361 ''')
362 self.compareMessages(self._get_mail(),
363 '''FROM: roundup-admin@your.tracker.email.domain.example
364 TO: chef@bork.bork.bork, mary@test.test, richard@test.test
365 Content-Type: text/plain; charset="utf-8"
366 Subject: [issue1] Testing...
367 To: mary@test.test, richard@test.test
368 From: "Bork, Chef" <issue_tracker@your.tracker.email.domain.example>
369 Reply-To: Roundup issue tracker
370 <issue_tracker@your.tracker.email.domain.example>
371 MIME-Version: 1.0
372 Message-Id: <dummy_test_message_id>
373 X-Roundup-Name: Roundup issue tracker
374 X-Roundup-Loop: hello
375 X-Roundup-Issue-Status: unread
376 Content-Transfer-Encoding: quoted-printable
378 New submission from Bork, Chef:
380 This is a test submission of a new issue.
382 ----------
383 assignedto: richard
384 messages: 1
385 nosy: Chef, mary, richard
386 status: unread
387 title: Testing...
389 _______________________________________________________________________
390 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
391 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
392 _______________________________________________________________________
393 ''')
395 multipart_msg = '''From: mary <mary@test.test>
396 To: issue_tracker@your.tracker.email.domain.example
397 Message-Id: <followup_dummy_id>
398 In-Reply-To: <dummy_test_message_id>
399 Subject: [issue1] Testing...
400 Content-Type: multipart/mixed; boundary="bxyzzy"
401 Content-Disposition: inline
404 --bxyzzy
405 Content-Type: multipart/alternative; boundary="bCsyhTFzCvuiizWE"
406 Content-Disposition: inline
408 --bCsyhTFzCvuiizWE
409 Content-Type: text/plain; charset=us-ascii
410 Content-Disposition: inline
412 test attachment first text/plain
414 --bCsyhTFzCvuiizWE
415 Content-Type: application/octet-stream
416 Content-Disposition: attachment; filename="first.dvi"
417 Content-Transfer-Encoding: base64
419 SnVzdCBhIHRlc3QgAQo=
421 --bCsyhTFzCvuiizWE
422 Content-Type: text/plain; charset=us-ascii
423 Content-Disposition: inline
425 test attachment second text/plain
427 --bCsyhTFzCvuiizWE
428 Content-Type: text/html
429 Content-Disposition: inline
431 <html>
432 to be ignored.
433 </html>
435 --bCsyhTFzCvuiizWE--
437 --bxyzzy
438 Content-Type: multipart/alternative; boundary="bCsyhTFzCvuiizWF"
439 Content-Disposition: inline
441 --bCsyhTFzCvuiizWF
442 Content-Type: text/plain; charset=us-ascii
443 Content-Disposition: inline
445 test attachment third text/plain
447 --bCsyhTFzCvuiizWF
448 Content-Type: application/octet-stream
449 Content-Disposition: attachment; filename="second.dvi"
450 Content-Transfer-Encoding: base64
452 SnVzdCBhIHRlc3QK
454 --bCsyhTFzCvuiizWF--
456 --bxyzzy--
457 '''
459 def testMultipartKeepAlternatives(self):
460 self.doNewIssue()
461 self._handle_mail(self.multipart_msg)
462 messages = self.db.issue.get('1', 'messages')
463 messages.sort()
464 msg = self.db.msg.getnode (messages[-1])
465 assert(len(msg.files) == 5)
466 names = {0 : 'first.dvi', 4 : 'second.dvi'}
467 content = {3 : 'test attachment third text/plain\n',
468 4 : 'Just a test\n'}
469 for n, id in enumerate (msg.files):
470 f = self.db.file.getnode (id)
471 self.assertEqual(f.name, names.get (n, 'unnamed'))
472 if n in content :
473 self.assertEqual(f.content, content [n])
474 self.assertEqual(msg.content, 'test attachment second text/plain')
476 def testMultipartDropAlternatives(self):
477 self.doNewIssue()
478 self.db.config.MAILGW_IGNORE_ALTERNATIVES = True
479 self._handle_mail(self.multipart_msg)
480 messages = self.db.issue.get('1', 'messages')
481 messages.sort()
482 msg = self.db.msg.getnode (messages[-1])
483 assert(len(msg.files) == 2)
484 names = {1 : 'second.dvi'}
485 content = {0 : 'test attachment third text/plain\n',
486 1 : 'Just a test\n'}
487 for n, id in enumerate (msg.files):
488 f = self.db.file.getnode (id)
489 self.assertEqual(f.name, names.get (n, 'unnamed'))
490 if n in content :
491 self.assertEqual(f.content, content [n])
492 self.assertEqual(msg.content, 'test attachment second text/plain')
494 def testSimpleFollowup(self):
495 self.doNewIssue()
496 self._handle_mail('''Content-Type: text/plain;
497 charset="iso-8859-1"
498 From: mary <mary@test.test>
499 To: issue_tracker@your.tracker.email.domain.example
500 Message-Id: <followup_dummy_id>
501 In-Reply-To: <dummy_test_message_id>
502 Subject: [issue1] Testing...
504 This is a second followup
505 ''')
506 self.compareMessages(self._get_mail(),
507 '''FROM: roundup-admin@your.tracker.email.domain.example
508 TO: chef@bork.bork.bork, richard@test.test
509 Content-Type: text/plain; charset="utf-8"
510 Subject: [issue1] Testing...
511 To: chef@bork.bork.bork, richard@test.test
512 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
513 Reply-To: Roundup issue tracker
514 <issue_tracker@your.tracker.email.domain.example>
515 MIME-Version: 1.0
516 Message-Id: <followup_dummy_id>
517 In-Reply-To: <dummy_test_message_id>
518 X-Roundup-Name: Roundup issue tracker
519 X-Roundup-Loop: hello
520 X-Roundup-Issue-Status: chatting
521 Content-Transfer-Encoding: quoted-printable
524 Contrary, Mary <mary@test.test> added the comment:
526 This is a second followup
528 ----------
529 status: unread -> chatting
531 _______________________________________________________________________
532 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
533 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
534 _______________________________________________________________________
535 ''')
537 def testFollowup(self):
538 self.doNewIssue()
540 self._handle_mail('''Content-Type: text/plain;
541 charset="iso-8859-1"
542 From: richard <richard@test.test>
543 To: issue_tracker@your.tracker.email.domain.example
544 Message-Id: <followup_dummy_id>
545 In-Reply-To: <dummy_test_message_id>
546 Subject: [issue1] Testing... [assignedto=mary; nosy=+john]
548 This is a followup
549 ''')
550 l = self.db.issue.get('1', 'nosy')
551 l.sort()
552 self.assertEqual(l, [self.chef_id, self.richard_id, self.mary_id,
553 self.john_id])
555 self.compareMessages(self._get_mail(),
556 '''FROM: roundup-admin@your.tracker.email.domain.example
557 TO: chef@bork.bork.bork, john@test.test, mary@test.test
558 Content-Type: text/plain; charset="utf-8"
559 Subject: [issue1] Testing...
560 To: chef@bork.bork.bork, john@test.test, mary@test.test
561 From: richard <issue_tracker@your.tracker.email.domain.example>
562 Reply-To: Roundup issue tracker
563 <issue_tracker@your.tracker.email.domain.example>
564 MIME-Version: 1.0
565 Message-Id: <followup_dummy_id>
566 In-Reply-To: <dummy_test_message_id>
567 X-Roundup-Name: Roundup issue tracker
568 X-Roundup-Loop: hello
569 X-Roundup-Issue-Status: chatting
570 Content-Transfer-Encoding: quoted-printable
573 richard <richard@test.test> added the comment:
575 This is a followup
577 ----------
578 assignedto: -> mary
579 nosy: +john, mary
580 status: unread -> chatting
582 _______________________________________________________________________
583 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
584 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
585 _______________________________________________________________________
586 ''')
588 def testNosyGeneration(self):
589 self.db.issue.create(title='test')
591 # create a nosy message
592 msg = self.db.msg.create(content='This is a test',
593 author=self.richard_id, messageid='<dummy_test_message_id>')
594 self.db.journaltag = 'richard'
595 l = self.db.issue.create(title='test', messages=[msg],
596 nosy=[self.chef_id, self.mary_id, self.john_id])
598 self.compareMessages(self._get_mail(),
599 '''FROM: roundup-admin@your.tracker.email.domain.example
600 TO: chef@bork.bork.bork, john@test.test, mary@test.test
601 Content-Type: text/plain; charset="utf-8"
602 Subject: [issue2] test
603 To: chef@bork.bork.bork, john@test.test, mary@test.test
604 From: richard <issue_tracker@your.tracker.email.domain.example>
605 Reply-To: Roundup issue tracker
606 <issue_tracker@your.tracker.email.domain.example>
607 MIME-Version: 1.0
608 Message-Id: <dummy_test_message_id>
609 X-Roundup-Name: Roundup issue tracker
610 X-Roundup-Loop: hello
611 X-Roundup-Issue-Status: unread
612 Content-Transfer-Encoding: quoted-printable
615 New submission from richard <richard@test.test>:
617 This is a test
619 ----------
620 messages: 1
621 nosy: Chef, john, mary, richard
622 status: unread
623 title: test
625 _______________________________________________________________________
626 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
627 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue2>
628 _______________________________________________________________________
629 ''')
631 def testPropertyChangeOnly(self):
632 self.doNewIssue()
633 oldvalues = self.db.getnode('issue', '1').copy()
634 oldvalues['assignedto'] = None
635 # reconstruct old behaviour: This would reuse the
636 # database-handle from the doNewIssue above which has committed
637 # as user "Chef". So we close and reopen the db as that user.
638 #self.db.close() actually don't close 'cos this empties memorydb
639 self.db = self.instance.open('Chef')
640 self.db.issue.set('1', assignedto=self.chef_id)
641 self.db.commit()
642 self.db.issue.nosymessage('1', None, oldvalues)
644 new_mail = ""
645 for line in self._get_mail().split("\n"):
646 if "Message-Id: " in line:
647 continue
648 if "Date: " in line:
649 continue
650 new_mail += line+"\n"
652 self.compareMessages(new_mail, """
653 FROM: roundup-admin@your.tracker.email.domain.example
654 TO: chef@bork.bork.bork, richard@test.test
655 Content-Type: text/plain; charset="utf-8"
656 Subject: [issue1] Testing...
657 To: chef@bork.bork.bork, richard@test.test
658 From: "Bork, Chef" <issue_tracker@your.tracker.email.domain.example>
659 X-Roundup-Name: Roundup issue tracker
660 X-Roundup-Loop: hello
661 X-Roundup-Issue-Status: unread
662 X-Roundup-Version: 1.3.3
663 In-Reply-To: <dummy_test_message_id>
664 MIME-Version: 1.0
665 Reply-To: Roundup issue tracker
666 <issue_tracker@your.tracker.email.domain.example>
667 Content-Transfer-Encoding: quoted-printable
670 Change by Bork, Chef <chef@bork.bork.bork>:
673 ----------
674 assignedto: -> Chef
676 _______________________________________________________________________
677 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
678 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
679 _______________________________________________________________________
680 """)
683 #
684 # FOLLOWUP TITLE MATCH
685 #
686 def testFollowupTitleMatch(self):
687 self.doNewIssue()
688 self._handle_mail('''Content-Type: text/plain;
689 charset="iso-8859-1"
690 From: richard <richard@test.test>
691 To: issue_tracker@your.tracker.email.domain.example
692 Message-Id: <followup_dummy_id>
693 Subject: Re: Testing... [assignedto=mary; nosy=+john]
695 This is a followup
696 ''')
697 self.compareMessages(self._get_mail(),
698 '''FROM: roundup-admin@your.tracker.email.domain.example
699 TO: chef@bork.bork.bork, john@test.test, mary@test.test
700 Content-Type: text/plain; charset="utf-8"
701 Subject: [issue1] Testing...
702 To: chef@bork.bork.bork, john@test.test, mary@test.test
703 From: richard <issue_tracker@your.tracker.email.domain.example>
704 Reply-To: Roundup issue tracker
705 <issue_tracker@your.tracker.email.domain.example>
706 MIME-Version: 1.0
707 Message-Id: <followup_dummy_id>
708 In-Reply-To: <dummy_test_message_id>
709 X-Roundup-Name: Roundup issue tracker
710 X-Roundup-Loop: hello
711 X-Roundup-Issue-Status: chatting
712 Content-Transfer-Encoding: quoted-printable
715 richard <richard@test.test> added the comment:
717 This is a followup
719 ----------
720 assignedto: -> mary
721 nosy: +john, mary
722 status: unread -> chatting
724 _______________________________________________________________________
725 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
726 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
727 _______________________________________________________________________
728 ''')
730 def testFollowupTitleMatchMultiRe(self):
731 nodeid1 = self.doNewIssue()
732 nodeid2 = self._handle_mail('''Content-Type: text/plain;
733 charset="iso-8859-1"
734 From: richard <richard@test.test>
735 To: issue_tracker@your.tracker.email.domain.example
736 Message-Id: <followup_dummy_id>
737 Subject: Re: Testing... [assignedto=mary; nosy=+john]
739 This is a followup
740 ''')
742 nodeid3 = self._handle_mail('''Content-Type: text/plain;
743 charset="iso-8859-1"
744 From: richard <richard@test.test>
745 To: issue_tracker@your.tracker.email.domain.example
746 Message-Id: <followup2_dummy_id>
747 Subject: Ang: Re: Testing...
749 This is a followup
750 ''')
751 self.assertEqual(nodeid1, nodeid2)
752 self.assertEqual(nodeid1, nodeid3)
754 def testFollowupTitleMatchNever(self):
755 nodeid = self.doNewIssue()
756 self.db.config.MAILGW_SUBJECT_CONTENT_MATCH = 'never'
757 self.assertNotEqual(self._handle_mail('''Content-Type: text/plain;
758 charset="iso-8859-1"
759 From: richard <richard@test.test>
760 To: issue_tracker@your.tracker.email.domain.example
761 Message-Id: <followup_dummy_id>
762 Subject: Re: Testing...
764 This is a followup
765 '''), nodeid)
767 def testFollowupTitleMatchNeverInterval(self):
768 nodeid = self.doNewIssue()
769 # force failure of the interval
770 time.sleep(2)
771 self.db.config.MAILGW_SUBJECT_CONTENT_MATCH = 'creation 00:00:01'
772 self.assertNotEqual(self._handle_mail('''Content-Type: text/plain;
773 charset="iso-8859-1"
774 From: richard <richard@test.test>
775 To: issue_tracker@your.tracker.email.domain.example
776 Message-Id: <followup_dummy_id>
777 Subject: Re: Testing...
779 This is a followup
780 '''), nodeid)
783 def testFollowupTitleMatchInterval(self):
784 nodeid = self.doNewIssue()
785 self.db.config.MAILGW_SUBJECT_CONTENT_MATCH = 'creation +1d'
786 self.assertEqual(self._handle_mail('''Content-Type: text/plain;
787 charset="iso-8859-1"
788 From: richard <richard@test.test>
789 To: issue_tracker@your.tracker.email.domain.example
790 Message-Id: <followup_dummy_id>
791 Subject: Re: Testing...
793 This is a followup
794 '''), nodeid)
797 def testFollowupNosyAuthor(self):
798 self.doNewIssue()
799 self.db.config.ADD_AUTHOR_TO_NOSY = 'yes'
800 self._handle_mail('''Content-Type: text/plain;
801 charset="iso-8859-1"
802 From: john@test.test
803 To: issue_tracker@your.tracker.email.domain.example
804 Message-Id: <followup_dummy_id>
805 In-Reply-To: <dummy_test_message_id>
806 Subject: [issue1] Testing...
808 This is a followup
809 ''')
811 self.compareMessages(self._get_mail(),
812 '''FROM: roundup-admin@your.tracker.email.domain.example
813 TO: chef@bork.bork.bork, richard@test.test
814 Content-Type: text/plain; charset="utf-8"
815 Subject: [issue1] Testing...
816 To: chef@bork.bork.bork, richard@test.test
817 From: John Doe <issue_tracker@your.tracker.email.domain.example>
818 Reply-To: Roundup issue tracker
819 <issue_tracker@your.tracker.email.domain.example>
820 MIME-Version: 1.0
821 Message-Id: <followup_dummy_id>
822 In-Reply-To: <dummy_test_message_id>
823 X-Roundup-Name: Roundup issue tracker
824 X-Roundup-Loop: hello
825 X-Roundup-Issue-Status: chatting
826 Content-Transfer-Encoding: quoted-printable
829 John Doe <john@test.test> added the comment:
831 This is a followup
833 ----------
834 nosy: +john
835 status: unread -> chatting
837 _______________________________________________________________________
838 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
839 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
840 _______________________________________________________________________
842 ''')
844 def testFollowupNosyRecipients(self):
845 self.doNewIssue()
846 self.db.config.ADD_RECIPIENTS_TO_NOSY = 'yes'
847 self._handle_mail('''Content-Type: text/plain;
848 charset="iso-8859-1"
849 From: richard@test.test
850 To: issue_tracker@your.tracker.email.domain.example
851 Cc: john@test.test
852 Message-Id: <followup_dummy_id>
853 In-Reply-To: <dummy_test_message_id>
854 Subject: [issue1] Testing...
856 This is a followup
857 ''')
858 self.compareMessages(self._get_mail(),
859 '''FROM: roundup-admin@your.tracker.email.domain.example
860 TO: chef@bork.bork.bork
861 Content-Type: text/plain; charset="utf-8"
862 Subject: [issue1] Testing...
863 To: chef@bork.bork.bork
864 From: richard <issue_tracker@your.tracker.email.domain.example>
865 Reply-To: Roundup issue tracker
866 <issue_tracker@your.tracker.email.domain.example>
867 MIME-Version: 1.0
868 Message-Id: <followup_dummy_id>
869 In-Reply-To: <dummy_test_message_id>
870 X-Roundup-Name: Roundup issue tracker
871 X-Roundup-Loop: hello
872 X-Roundup-Issue-Status: chatting
873 Content-Transfer-Encoding: quoted-printable
876 richard <richard@test.test> added the comment:
878 This is a followup
880 ----------
881 nosy: +john
882 status: unread -> chatting
884 _______________________________________________________________________
885 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
886 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
887 _______________________________________________________________________
889 ''')
891 def testFollowupNosyAuthorAndCopy(self):
892 self.doNewIssue()
893 self.db.config.ADD_AUTHOR_TO_NOSY = 'yes'
894 self.db.config.MESSAGES_TO_AUTHOR = 'yes'
895 self._handle_mail('''Content-Type: text/plain;
896 charset="iso-8859-1"
897 From: john@test.test
898 To: issue_tracker@your.tracker.email.domain.example
899 Message-Id: <followup_dummy_id>
900 In-Reply-To: <dummy_test_message_id>
901 Subject: [issue1] Testing...
903 This is a followup
904 ''')
905 self.compareMessages(self._get_mail(),
906 '''FROM: roundup-admin@your.tracker.email.domain.example
907 TO: chef@bork.bork.bork, john@test.test, richard@test.test
908 Content-Type: text/plain; charset="utf-8"
909 Subject: [issue1] Testing...
910 To: chef@bork.bork.bork, john@test.test, richard@test.test
911 From: John Doe <issue_tracker@your.tracker.email.domain.example>
912 Reply-To: Roundup issue tracker
913 <issue_tracker@your.tracker.email.domain.example>
914 MIME-Version: 1.0
915 Message-Id: <followup_dummy_id>
916 In-Reply-To: <dummy_test_message_id>
917 X-Roundup-Name: Roundup issue tracker
918 X-Roundup-Loop: hello
919 X-Roundup-Issue-Status: chatting
920 Content-Transfer-Encoding: quoted-printable
923 John Doe <john@test.test> added the comment:
925 This is a followup
927 ----------
928 nosy: +john
929 status: unread -> chatting
931 _______________________________________________________________________
932 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
933 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
934 _______________________________________________________________________
936 ''')
938 def testFollowupNoNosyAuthor(self):
939 self.doNewIssue()
940 self.instance.config.ADD_AUTHOR_TO_NOSY = 'no'
941 self._handle_mail('''Content-Type: text/plain;
942 charset="iso-8859-1"
943 From: john@test.test
944 To: issue_tracker@your.tracker.email.domain.example
945 Message-Id: <followup_dummy_id>
946 In-Reply-To: <dummy_test_message_id>
947 Subject: [issue1] Testing...
949 This is a followup
950 ''')
951 self.compareMessages(self._get_mail(),
952 '''FROM: roundup-admin@your.tracker.email.domain.example
953 TO: chef@bork.bork.bork, richard@test.test
954 Content-Type: text/plain; charset="utf-8"
955 Subject: [issue1] Testing...
956 To: chef@bork.bork.bork, richard@test.test
957 From: John Doe <issue_tracker@your.tracker.email.domain.example>
958 Reply-To: Roundup issue tracker
959 <issue_tracker@your.tracker.email.domain.example>
960 MIME-Version: 1.0
961 Message-Id: <followup_dummy_id>
962 In-Reply-To: <dummy_test_message_id>
963 X-Roundup-Name: Roundup issue tracker
964 X-Roundup-Loop: hello
965 X-Roundup-Issue-Status: chatting
966 Content-Transfer-Encoding: quoted-printable
969 John Doe <john@test.test> added the comment:
971 This is a followup
973 ----------
974 status: unread -> chatting
976 _______________________________________________________________________
977 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
978 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
979 _______________________________________________________________________
981 ''')
983 def testFollowupNoNosyRecipients(self):
984 self.doNewIssue()
985 self.instance.config.ADD_RECIPIENTS_TO_NOSY = 'no'
986 self._handle_mail('''Content-Type: text/plain;
987 charset="iso-8859-1"
988 From: richard@test.test
989 To: issue_tracker@your.tracker.email.domain.example
990 Cc: john@test.test
991 Message-Id: <followup_dummy_id>
992 In-Reply-To: <dummy_test_message_id>
993 Subject: [issue1] Testing...
995 This is a followup
996 ''')
997 self.compareMessages(self._get_mail(),
998 '''FROM: roundup-admin@your.tracker.email.domain.example
999 TO: chef@bork.bork.bork
1000 Content-Type: text/plain; charset="utf-8"
1001 Subject: [issue1] Testing...
1002 To: chef@bork.bork.bork
1003 From: richard <issue_tracker@your.tracker.email.domain.example>
1004 Reply-To: Roundup issue tracker
1005 <issue_tracker@your.tracker.email.domain.example>
1006 MIME-Version: 1.0
1007 Message-Id: <followup_dummy_id>
1008 In-Reply-To: <dummy_test_message_id>
1009 X-Roundup-Name: Roundup issue tracker
1010 X-Roundup-Loop: hello
1011 X-Roundup-Issue-Status: chatting
1012 Content-Transfer-Encoding: quoted-printable
1015 richard <richard@test.test> added the comment:
1017 This is a followup
1019 ----------
1020 status: unread -> chatting
1022 _______________________________________________________________________
1023 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1024 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1025 _______________________________________________________________________
1027 ''')
1029 def testFollowupEmptyMessage(self):
1030 self.doNewIssue()
1032 self._handle_mail('''Content-Type: text/plain;
1033 charset="iso-8859-1"
1034 From: richard <richard@test.test>
1035 To: issue_tracker@your.tracker.email.domain.example
1036 Message-Id: <followup_dummy_id>
1037 In-Reply-To: <dummy_test_message_id>
1038 Subject: [issue1] Testing... [assignedto=mary; nosy=+john]
1040 ''')
1041 l = self.db.issue.get('1', 'nosy')
1042 l.sort()
1043 self.assertEqual(l, [self.chef_id, self.richard_id, self.mary_id,
1044 self.john_id])
1046 # should be no file created (ie. no message)
1047 assert not os.path.exists(SENDMAILDEBUG)
1049 def testFollowupEmptyMessageNoSubject(self):
1050 self.doNewIssue()
1052 self._handle_mail('''Content-Type: text/plain;
1053 charset="iso-8859-1"
1054 From: richard <richard@test.test>
1055 To: issue_tracker@your.tracker.email.domain.example
1056 Message-Id: <followup_dummy_id>
1057 In-Reply-To: <dummy_test_message_id>
1058 Subject: [issue1] [assignedto=mary; nosy=+john]
1060 ''')
1061 l = self.db.issue.get('1', 'nosy')
1062 l.sort()
1063 self.assertEqual(l, [self.chef_id, self.richard_id, self.mary_id,
1064 self.john_id])
1066 # should be no file created (ie. no message)
1067 assert not os.path.exists(SENDMAILDEBUG)
1069 def testNosyRemove(self):
1070 self.doNewIssue()
1072 self._handle_mail('''Content-Type: text/plain;
1073 charset="iso-8859-1"
1074 From: richard <richard@test.test>
1075 To: issue_tracker@your.tracker.email.domain.example
1076 Message-Id: <followup_dummy_id>
1077 In-Reply-To: <dummy_test_message_id>
1078 Subject: [issue1] Testing... [nosy=-richard]
1080 ''')
1081 l = self.db.issue.get('1', 'nosy')
1082 l.sort()
1083 self.assertEqual(l, [self.chef_id])
1085 # NO NOSY MESSAGE SHOULD BE SENT!
1086 assert not os.path.exists(SENDMAILDEBUG)
1088 def testNewUserAuthor(self):
1089 self.db.commit()
1090 l = self.db.user.list()
1091 l.sort()
1092 message = '''Content-Type: text/plain;
1093 charset="iso-8859-1"
1094 From: fubar <fubar@bork.bork.bork>
1095 To: issue_tracker@your.tracker.email.domain.example
1096 Message-Id: <dummy_test_message_id>
1097 Subject: [issue] Testing...
1099 This is a test submission of a new issue.
1100 '''
1101 self.db.security.role['anonymous'].permissions=[]
1102 anonid = self.db.user.lookup('anonymous')
1103 self.db.user.set(anonid, roles='Anonymous')
1104 try:
1105 self._handle_mail(message)
1106 except Unauthorized, value:
1107 body_diff = self.compareMessages(str(value), """
1108 You are not a registered user.
1110 Unknown address: fubar@bork.bork.bork
1111 """)
1112 assert not body_diff, body_diff
1113 else:
1114 raise AssertionError, "Unathorized not raised when handling mail"
1116 # Add Web Access role to anonymous, and try again to make sure
1117 # we get a "please register at:" message this time.
1118 p = [
1119 self.db.security.getPermission('Register', 'user'),
1120 self.db.security.getPermission('Web Access', None),
1121 ]
1122 self.db.security.role['anonymous'].permissions=p
1123 try:
1124 self._handle_mail(message)
1125 except Unauthorized, value:
1126 body_diff = self.compareMessages(str(value), """
1127 You are not a registered user. Please register at:
1129 http://tracker.example/cgi-bin/roundup.cgi/bugs/user?template=register
1131 ...before sending mail to the tracker.
1133 Unknown address: fubar@bork.bork.bork
1134 """)
1135 assert not body_diff, body_diff
1136 else:
1137 raise AssertionError, "Unathorized not raised when handling mail"
1139 # Make sure list of users is the same as before.
1140 m = self.db.user.list()
1141 m.sort()
1142 self.assertEqual(l, m)
1144 # now with the permission
1145 p = [
1146 self.db.security.getPermission('Register', 'user'),
1147 self.db.security.getPermission('Email Access', None),
1148 ]
1149 self.db.security.role['anonymous'].permissions=p
1150 self._handle_mail(message)
1151 m = self.db.user.list()
1152 m.sort()
1153 self.assertNotEqual(l, m)
1155 def testNewUserAuthorEncodedName(self):
1156 l = set(self.db.user.list())
1157 # From: name has Euro symbol in it
1158 message = '''Content-Type: text/plain;
1159 charset="iso-8859-1"
1160 From: =?utf8?b?SOKCrGxsbw==?= <fubar@bork.bork.bork>
1161 To: issue_tracker@your.tracker.email.domain.example
1162 Message-Id: <dummy_test_message_id>
1163 Subject: [issue] Testing...
1165 This is a test submission of a new issue.
1166 '''
1167 p = [
1168 self.db.security.getPermission('Register', 'user'),
1169 self.db.security.getPermission('Email Access', None),
1170 self.db.security.getPermission('Create', 'issue'),
1171 self.db.security.getPermission('Create', 'msg'),
1172 ]
1173 self.db.security.role['anonymous'].permissions = p
1174 self._handle_mail(message)
1175 m = set(self.db.user.list())
1176 new = list(m - l)[0]
1177 name = self.db.user.get(new, 'realname')
1178 self.assertEquals(name, 'H€llo')
1180 def testUnknownUser(self):
1181 l = set(self.db.user.list())
1182 message = '''Content-Type: text/plain;
1183 charset="iso-8859-1"
1184 From: Nonexisting User <nonexisting@bork.bork.bork>
1185 To: issue_tracker@your.tracker.email.domain.example
1186 Message-Id: <dummy_test_message_id>
1187 Subject: [issue] Testing nonexisting user...
1189 This is a test submission of a new issue.
1190 '''
1191 handler = self._create_mailgw(message)
1192 # we want a bounce message:
1193 handler.trapExceptions = 1
1194 ret = handler.main(StringIO(message))
1195 self.compareMessages(self._get_mail(),
1196 '''FROM: Roundup issue tracker <roundup-admin@your.tracker.email.domain.example>
1197 TO: nonexisting@bork.bork.bork
1198 From nobody Tue Jul 14 12:04:11 2009
1199 Content-Type: multipart/mixed; boundary="===============0639262320=="
1200 MIME-Version: 1.0
1201 Subject: Failed issue tracker submission
1202 To: nonexisting@bork.bork.bork
1203 From: Roundup issue tracker <roundup-admin@your.tracker.email.domain.example>
1204 Date: Tue, 14 Jul 2009 12:04:11 +0000
1205 Precedence: bulk
1206 X-Roundup-Name: Roundup issue tracker
1207 X-Roundup-Loop: hello
1208 X-Roundup-Version: 1.4.8
1209 MIME-Version: 1.0
1211 --===============0639262320==
1212 Content-Type: text/plain; charset="us-ascii"
1213 MIME-Version: 1.0
1214 Content-Transfer-Encoding: 7bit
1218 You are not a registered user. Please register at:
1220 http://tracker.example/cgi-bin/roundup.cgi/bugs/user?template=register
1222 ...before sending mail to the tracker.
1224 Unknown address: nonexisting@bork.bork.bork
1226 --===============0639262320==
1227 Content-Type: text/plain; charset="us-ascii"
1228 MIME-Version: 1.0
1229 Content-Transfer-Encoding: 7bit
1231 Content-Type: text/plain;
1232 charset="iso-8859-1"
1233 From: Nonexisting User <nonexisting@bork.bork.bork>
1234 To: issue_tracker@your.tracker.email.domain.example
1235 Message-Id: <dummy_test_message_id>
1236 Subject: [issue] Testing nonexisting user...
1238 This is a test submission of a new issue.
1240 --===============0639262320==--
1241 ''')
1243 def testEnc01(self):
1244 self.db.user.set(self.mary_id,
1245 realname='\xe4\xf6\xfc\xc4\xd6\xdc\xdf, Mary'.decode
1246 ('latin-1').encode('utf-8'))
1247 self.doNewIssue()
1248 self._handle_mail('''Content-Type: text/plain;
1249 charset="iso-8859-1"
1250 From: mary <mary@test.test>
1251 To: issue_tracker@your.tracker.email.domain.example
1252 Message-Id: <followup_dummy_id>
1253 In-Reply-To: <dummy_test_message_id>
1254 Subject: [issue1] Testing...
1255 Content-Type: text/plain;
1256 charset="iso-8859-1"
1257 Content-Transfer-Encoding: quoted-printable
1259 A message with encoding (encoded oe =F6)
1261 ''')
1262 self.compareMessages(self._get_mail(),
1263 '''FROM: roundup-admin@your.tracker.email.domain.example
1264 TO: chef@bork.bork.bork, richard@test.test
1265 Content-Type: text/plain; charset="utf-8"
1266 Subject: [issue1] Testing...
1267 To: chef@bork.bork.bork, richard@test.test
1268 From: =?utf-8?b?w6TDtsO8w4TDlsOcw58sIE1hcnk=?=
1269 <issue_tracker@your.tracker.email.domain.example>
1270 Reply-To: Roundup issue tracker
1271 <issue_tracker@your.tracker.email.domain.example>
1272 MIME-Version: 1.0
1273 Message-Id: <followup_dummy_id>
1274 In-Reply-To: <dummy_test_message_id>
1275 X-Roundup-Name: Roundup issue tracker
1276 X-Roundup-Loop: hello
1277 X-Roundup-Issue-Status: chatting
1278 Content-Transfer-Encoding: quoted-printable
1281 =C3=A4=C3=B6=C3=BC=C3=84=C3=96=C3=9C=C3=9F, Mary <mary@test.test> added the=
1282 comment:
1284 A message with encoding (encoded oe =C3=B6)
1286 ----------
1287 status: unread -> chatting
1289 _______________________________________________________________________
1290 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1291 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1292 _______________________________________________________________________
1293 ''')
1295 def testEncNonUTF8(self):
1296 self.doNewIssue()
1297 self.instance.config.EMAIL_CHARSET = 'iso-8859-1'
1298 self._handle_mail('''Content-Type: text/plain;
1299 charset="iso-8859-1"
1300 From: mary <mary@test.test>
1301 To: issue_tracker@your.tracker.email.domain.example
1302 Message-Id: <followup_dummy_id>
1303 In-Reply-To: <dummy_test_message_id>
1304 Subject: [issue1] Testing...
1305 Content-Type: text/plain;
1306 charset="iso-8859-1"
1307 Content-Transfer-Encoding: quoted-printable
1309 A message with encoding (encoded oe =F6)
1311 ''')
1312 self.compareMessages(self._get_mail(),
1313 '''FROM: roundup-admin@your.tracker.email.domain.example
1314 TO: chef@bork.bork.bork, richard@test.test
1315 Content-Type: text/plain; charset="iso-8859-1"
1316 Subject: [issue1] Testing...
1317 To: chef@bork.bork.bork, richard@test.test
1318 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
1319 Reply-To: Roundup issue tracker
1320 <issue_tracker@your.tracker.email.domain.example>
1321 MIME-Version: 1.0
1322 Message-Id: <followup_dummy_id>
1323 In-Reply-To: <dummy_test_message_id>
1324 X-Roundup-Name: Roundup issue tracker
1325 X-Roundup-Loop: hello
1326 X-Roundup-Issue-Status: chatting
1327 Content-Transfer-Encoding: quoted-printable
1330 Contrary, Mary <mary@test.test> added the comment:
1332 A message with encoding (encoded oe =F6)
1334 ----------
1335 status: unread -> chatting
1337 _______________________________________________________________________
1338 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1339 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1340 _______________________________________________________________________
1341 ''')
1344 def testMultipartEnc01(self):
1345 self.doNewIssue()
1346 self._handle_mail('''Content-Type: text/plain;
1347 charset="iso-8859-1"
1348 From: mary <mary@test.test>
1349 To: issue_tracker@your.tracker.email.domain.example
1350 Message-Id: <followup_dummy_id>
1351 In-Reply-To: <dummy_test_message_id>
1352 Subject: [issue1] Testing...
1353 Content-Type: multipart/mixed;
1354 boundary="----_=_NextPart_000_01"
1356 This message is in MIME format. Since your mail reader does not understand
1357 this format, some or all of this message may not be legible.
1359 ------_=_NextPart_000_01
1360 Content-Type: text/plain;
1361 charset="iso-8859-1"
1362 Content-Transfer-Encoding: quoted-printable
1364 A message with first part encoded (encoded oe =F6)
1366 ''')
1367 self.compareMessages(self._get_mail(),
1368 '''FROM: roundup-admin@your.tracker.email.domain.example
1369 TO: chef@bork.bork.bork, richard@test.test
1370 Content-Type: text/plain; charset="utf-8"
1371 Subject: [issue1] Testing...
1372 To: chef@bork.bork.bork, richard@test.test
1373 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
1374 Reply-To: Roundup issue tracker
1375 <issue_tracker@your.tracker.email.domain.example>
1376 MIME-Version: 1.0
1377 Message-Id: <followup_dummy_id>
1378 In-Reply-To: <dummy_test_message_id>
1379 X-Roundup-Name: Roundup issue tracker
1380 X-Roundup-Loop: hello
1381 X-Roundup-Issue-Status: chatting
1382 Content-Transfer-Encoding: quoted-printable
1385 Contrary, Mary <mary@test.test> added the comment:
1387 A message with first part encoded (encoded oe =C3=B6)
1389 ----------
1390 status: unread -> chatting
1392 _______________________________________________________________________
1393 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1394 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1395 _______________________________________________________________________
1396 ''')
1398 def testContentDisposition(self):
1399 self.doNewIssue()
1400 self._handle_mail('''Content-Type: text/plain;
1401 charset="iso-8859-1"
1402 From: mary <mary@test.test>
1403 To: issue_tracker@your.tracker.email.domain.example
1404 Message-Id: <followup_dummy_id>
1405 In-Reply-To: <dummy_test_message_id>
1406 Subject: [issue1] Testing...
1407 Content-Type: multipart/mixed; boundary="bCsyhTFzCvuiizWE"
1408 Content-Disposition: inline
1411 --bCsyhTFzCvuiizWE
1412 Content-Type: text/plain; charset=us-ascii
1413 Content-Disposition: inline
1415 test attachment binary
1417 --bCsyhTFzCvuiizWE
1418 Content-Type: application/octet-stream
1419 Content-Disposition: attachment; filename="main.dvi"
1420 Content-Transfer-Encoding: base64
1422 SnVzdCBhIHRlc3QgAQo=
1424 --bCsyhTFzCvuiizWE--
1425 ''')
1426 messages = self.db.issue.get('1', 'messages')
1427 messages.sort()
1428 file = self.db.file.getnode (self.db.msg.get(messages[-1], 'files')[0])
1429 self.assertEqual(file.name, 'main.dvi')
1430 self.assertEqual(file.content, 'Just a test \001\n')
1432 def testFollowupStupidQuoting(self):
1433 self.doNewIssue()
1435 self._handle_mail('''Content-Type: text/plain;
1436 charset="iso-8859-1"
1437 From: richard <richard@test.test>
1438 To: issue_tracker@your.tracker.email.domain.example
1439 Message-Id: <followup_dummy_id>
1440 In-Reply-To: <dummy_test_message_id>
1441 Subject: Re: "[issue1] Testing... "
1443 This is a followup
1444 ''')
1445 self.compareMessages(self._get_mail(),
1446 '''FROM: roundup-admin@your.tracker.email.domain.example
1447 TO: chef@bork.bork.bork
1448 Content-Type: text/plain; charset="utf-8"
1449 Subject: [issue1] Testing...
1450 To: chef@bork.bork.bork
1451 From: richard <issue_tracker@your.tracker.email.domain.example>
1452 Reply-To: Roundup issue tracker
1453 <issue_tracker@your.tracker.email.domain.example>
1454 MIME-Version: 1.0
1455 Message-Id: <followup_dummy_id>
1456 In-Reply-To: <dummy_test_message_id>
1457 X-Roundup-Name: Roundup issue tracker
1458 X-Roundup-Loop: hello
1459 X-Roundup-Issue-Status: chatting
1460 Content-Transfer-Encoding: quoted-printable
1463 richard <richard@test.test> added the comment:
1465 This is a followup
1467 ----------
1468 status: unread -> chatting
1470 _______________________________________________________________________
1471 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1472 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1473 _______________________________________________________________________
1474 ''')
1476 def testEmailQuoting(self):
1477 self.instance.config.EMAIL_KEEP_QUOTED_TEXT = 'no'
1478 self.innerTestQuoting('''This is a followup
1479 ''')
1481 def testEmailQuotingRemove(self):
1482 self.instance.config.EMAIL_KEEP_QUOTED_TEXT = 'yes'
1483 self.innerTestQuoting('''Blah blah wrote:
1484 > Blah bklaskdfj sdf asdf jlaskdf skj sdkfjl asdf
1485 > skdjlkjsdfalsdkfjasdlfkj dlfksdfalksd fj
1486 >
1488 This is a followup
1489 ''')
1491 def innerTestQuoting(self, expect):
1492 nodeid = self.doNewIssue()
1494 messages = self.db.issue.get(nodeid, 'messages')
1496 self._handle_mail('''Content-Type: text/plain;
1497 charset="iso-8859-1"
1498 From: richard <richard@test.test>
1499 To: issue_tracker@your.tracker.email.domain.example
1500 Message-Id: <followup_dummy_id>
1501 In-Reply-To: <dummy_test_message_id>
1502 Subject: Re: [issue1] Testing...
1504 Blah blah wrote:
1505 > Blah bklaskdfj sdf asdf jlaskdf skj sdkfjl asdf
1506 > skdjlkjsdfalsdkfjasdlfkj dlfksdfalksd fj
1507 >
1509 This is a followup
1510 ''')
1511 # figure the new message id
1512 newmessages = self.db.issue.get(nodeid, 'messages')
1513 for msg in messages:
1514 newmessages.remove(msg)
1515 messageid = newmessages[0]
1517 self.compareMessages(self.db.msg.get(messageid, 'content'), expect)
1519 def testUserLookup(self):
1520 i = self.db.user.create(username='user1', address='user1@foo.com')
1521 self.assertEqual(uidFromAddress(self.db, ('', 'user1@foo.com'), 0), i)
1522 self.assertEqual(uidFromAddress(self.db, ('', 'USER1@foo.com'), 0), i)
1523 i = self.db.user.create(username='user2', address='USER2@foo.com')
1524 self.assertEqual(uidFromAddress(self.db, ('', 'USER2@foo.com'), 0), i)
1525 self.assertEqual(uidFromAddress(self.db, ('', 'user2@foo.com'), 0), i)
1527 def testUserAlternateLookup(self):
1528 i = self.db.user.create(username='user1', address='user1@foo.com',
1529 alternate_addresses='user1@bar.com')
1530 self.assertEqual(uidFromAddress(self.db, ('', 'user1@bar.com'), 0), i)
1531 self.assertEqual(uidFromAddress(self.db, ('', 'USER1@bar.com'), 0), i)
1533 def testUserCreate(self):
1534 i = uidFromAddress(self.db, ('', 'user@foo.com'), 1)
1535 self.assertNotEqual(uidFromAddress(self.db, ('', 'user@bar.com'), 1), i)
1537 def testRFC2822(self):
1538 ascii_header = "[issue243] This is a \"test\" - with 'quotation' marks"
1539 unicode_header = '[issue244] \xd0\xb0\xd0\xbd\xd0\xb4\xd1\x80\xd0\xb5\xd0\xb9'
1540 unicode_encoded = '=?utf-8?q?[issue244]_=D0=B0=D0=BD=D0=B4=D1=80=D0=B5=D0=B9?='
1541 self.assertEqual(rfc2822.encode_header(ascii_header), ascii_header)
1542 self.assertEqual(rfc2822.encode_header(unicode_header), unicode_encoded)
1544 def testRegistrationConfirmation(self):
1545 otk = "Aj4euk4LZSAdwePohj90SME5SpopLETL"
1546 self.db.getOTKManager().set(otk, username='johannes')
1547 self._handle_mail('''Content-Type: text/plain;
1548 charset="iso-8859-1"
1549 From: Chef <chef@bork.bork.bork>
1550 To: issue_tracker@your.tracker.email.domain.example
1551 Cc: richard@test.test
1552 Message-Id: <dummy_test_message_id>
1553 Subject: Re: Complete your registration to Roundup issue tracker
1554 -- key %s
1556 This is a test confirmation of registration.
1557 ''' % otk)
1558 self.db.user.lookup('johannes')
1560 def testFollowupOnNonIssue(self):
1561 self.db.keyword.create(name='Foo')
1562 self._handle_mail('''Content-Type: text/plain;
1563 charset="iso-8859-1"
1564 From: richard <richard@test.test>
1565 To: issue_tracker@your.tracker.email.domain.example
1566 Message-Id: <followup_dummy_id>
1567 In-Reply-To: <dummy_test_message_id>
1568 Subject: [keyword1] Testing... [name=Bar]
1570 ''')
1571 self.assertEqual(self.db.keyword.get('1', 'name'), 'Bar')
1573 def testResentFrom(self):
1574 nodeid = self._handle_mail('''Content-Type: text/plain;
1575 charset="iso-8859-1"
1576 From: Chef <chef@bork.bork.bork>
1577 Resent-From: mary <mary@test.test>
1578 To: issue_tracker@your.tracker.email.domain.example
1579 Cc: richard@test.test
1580 Message-Id: <dummy_test_message_id>
1581 Subject: [issue] Testing...
1583 This is a test submission of a new issue.
1584 ''')
1585 assert not os.path.exists(SENDMAILDEBUG)
1586 l = self.db.issue.get(nodeid, 'nosy')
1587 l.sort()
1588 self.assertEqual(l, [self.richard_id, self.mary_id])
1589 return nodeid
1591 def testDejaVu(self):
1592 self.assertRaises(IgnoreLoop, self._handle_mail,
1593 '''Content-Type: text/plain;
1594 charset="iso-8859-1"
1595 From: Chef <chef@bork.bork.bork>
1596 X-Roundup-Loop: hello
1597 To: issue_tracker@your.tracker.email.domain.example
1598 Cc: richard@test.test
1599 Message-Id: <dummy_test_message_id>
1600 Subject: Re: [issue] Testing...
1602 Hi, I've been mis-configured to loop messages back to myself.
1603 ''')
1605 def testItsBulkStupid(self):
1606 self.assertRaises(IgnoreBulk, self._handle_mail,
1607 '''Content-Type: text/plain;
1608 charset="iso-8859-1"
1609 From: Chef <chef@bork.bork.bork>
1610 Precedence: bulk
1611 To: issue_tracker@your.tracker.email.domain.example
1612 Cc: richard@test.test
1613 Message-Id: <dummy_test_message_id>
1614 Subject: Re: [issue] Testing...
1616 Hi, I'm on holidays, and this is a dumb auto-responder.
1617 ''')
1619 def testAutoReplyEmailsAreIgnored(self):
1620 self.assertRaises(IgnoreBulk, self._handle_mail,
1621 '''Content-Type: text/plain;
1622 charset="iso-8859-1"
1623 From: Chef <chef@bork.bork.bork>
1624 To: issue_tracker@your.tracker.email.domain.example
1625 Cc: richard@test.test
1626 Message-Id: <dummy_test_message_id>
1627 Subject: Re: [issue] Out of office AutoReply: Back next week
1629 Hi, I am back in the office next week
1630 ''')
1632 def testNoSubject(self):
1633 self.assertRaises(MailUsageError, self._handle_mail,
1634 '''Content-Type: text/plain;
1635 charset="iso-8859-1"
1636 From: Chef <chef@bork.bork.bork>
1637 To: issue_tracker@your.tracker.email.domain.example
1638 Cc: richard@test.test
1639 Reply-To: chef@bork.bork.bork
1640 Message-Id: <dummy_test_message_id>
1642 ''')
1644 #
1645 # TEST FOR INVALID DESIGNATOR HANDLING
1646 #
1647 def testInvalidDesignator(self):
1648 self.assertRaises(MailUsageError, self._handle_mail,
1649 '''Content-Type: text/plain;
1650 charset="iso-8859-1"
1651 From: Chef <chef@bork.bork.bork>
1652 To: issue_tracker@your.tracker.email.domain.example
1653 Subject: [frobulated] testing
1654 Cc: richard@test.test
1655 Reply-To: chef@bork.bork.bork
1656 Message-Id: <dummy_test_message_id>
1658 ''')
1659 self.assertRaises(MailUsageError, self._handle_mail,
1660 '''Content-Type: text/plain;
1661 charset="iso-8859-1"
1662 From: Chef <chef@bork.bork.bork>
1663 To: issue_tracker@your.tracker.email.domain.example
1664 Subject: [issue12345] testing
1665 Cc: richard@test.test
1666 Reply-To: chef@bork.bork.bork
1667 Message-Id: <dummy_test_message_id>
1669 ''')
1671 def testInvalidClassLoose(self):
1672 self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'loose'
1673 nodeid = self._handle_mail('''Content-Type: text/plain;
1674 charset="iso-8859-1"
1675 From: Chef <chef@bork.bork.bork>
1676 To: issue_tracker@your.tracker.email.domain.example
1677 Subject: [frobulated] testing
1678 Cc: richard@test.test
1679 Reply-To: chef@bork.bork.bork
1680 Message-Id: <dummy_test_message_id>
1682 ''')
1683 assert not os.path.exists(SENDMAILDEBUG)
1684 self.assertEqual(self.db.issue.get(nodeid, 'title'),
1685 '[frobulated] testing')
1687 def testInvalidClassLooseReply(self):
1688 self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'loose'
1689 nodeid = self._handle_mail('''Content-Type: text/plain;
1690 charset="iso-8859-1"
1691 From: Chef <chef@bork.bork.bork>
1692 To: issue_tracker@your.tracker.email.domain.example
1693 Subject: Re: [frobulated] testing
1694 Cc: richard@test.test
1695 Reply-To: chef@bork.bork.bork
1696 Message-Id: <dummy_test_message_id>
1698 ''')
1699 assert not os.path.exists(SENDMAILDEBUG)
1700 self.assertEqual(self.db.issue.get(nodeid, 'title'),
1701 '[frobulated] testing')
1703 def testInvalidClassLoose(self):
1704 self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'loose'
1705 nodeid = self._handle_mail('''Content-Type: text/plain;
1706 charset="iso-8859-1"
1707 From: Chef <chef@bork.bork.bork>
1708 To: issue_tracker@your.tracker.email.domain.example
1709 Subject: [issue1234] testing
1710 Cc: richard@test.test
1711 Reply-To: chef@bork.bork.bork
1712 Message-Id: <dummy_test_message_id>
1714 ''')
1715 assert not os.path.exists(SENDMAILDEBUG)
1716 self.assertEqual(self.db.issue.get(nodeid, 'title'),
1717 '[issue1234] testing')
1719 def testClassLooseOK(self):
1720 self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'loose'
1721 self.db.keyword.create(name='Foo')
1722 nodeid = self._handle_mail('''Content-Type: text/plain;
1723 charset="iso-8859-1"
1724 From: Chef <chef@bork.bork.bork>
1725 To: issue_tracker@your.tracker.email.domain.example
1726 Subject: [keyword1] Testing... [name=Bar]
1727 Cc: richard@test.test
1728 Reply-To: chef@bork.bork.bork
1729 Message-Id: <dummy_test_message_id>
1731 ''')
1732 assert not os.path.exists(SENDMAILDEBUG)
1733 self.assertEqual(self.db.keyword.get('1', 'name'), 'Bar')
1735 def testClassStrictInvalid(self):
1736 self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'strict'
1737 self.instance.config.MAILGW_DEFAULT_CLASS = ''
1739 message = '''Content-Type: text/plain;
1740 charset="iso-8859-1"
1741 From: Chef <chef@bork.bork.bork>
1742 To: issue_tracker@your.tracker.email.domain.example
1743 Subject: Testing...
1744 Cc: richard@test.test
1745 Reply-To: chef@bork.bork.bork
1746 Message-Id: <dummy_test_message_id>
1748 '''
1749 self.assertRaises(MailUsageError, self._handle_mail, message)
1751 def testClassStrictValid(self):
1752 self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'strict'
1753 self.instance.config.MAILGW_DEFAULT_CLASS = ''
1755 nodeid = self._handle_mail('''Content-Type: text/plain;
1756 charset="iso-8859-1"
1757 From: Chef <chef@bork.bork.bork>
1758 To: issue_tracker@your.tracker.email.domain.example
1759 Subject: [issue] Testing...
1760 Cc: richard@test.test
1761 Reply-To: chef@bork.bork.bork
1762 Message-Id: <dummy_test_message_id>
1764 ''')
1766 assert not os.path.exists(SENDMAILDEBUG)
1767 self.assertEqual(self.db.issue.get(nodeid, 'title'), 'Testing...')
1769 #
1770 # TEST FOR INVALID COMMANDS HANDLING
1771 #
1772 def testInvalidCommands(self):
1773 self.assertRaises(MailUsageError, self._handle_mail,
1774 '''Content-Type: text/plain;
1775 charset="iso-8859-1"
1776 From: Chef <chef@bork.bork.bork>
1777 To: issue_tracker@your.tracker.email.domain.example
1778 Subject: testing [frobulated]
1779 Cc: richard@test.test
1780 Reply-To: chef@bork.bork.bork
1781 Message-Id: <dummy_test_message_id>
1783 ''')
1785 def testInvalidCommandPassthrough(self):
1786 self.instance.config.MAILGW_SUBJECT_SUFFIX_PARSING = 'none'
1787 nodeid = self._handle_mail('''Content-Type: text/plain;
1788 charset="iso-8859-1"
1789 From: Chef <chef@bork.bork.bork>
1790 To: issue_tracker@your.tracker.email.domain.example
1791 Subject: testing [frobulated]
1792 Cc: richard@test.test
1793 Reply-To: chef@bork.bork.bork
1794 Message-Id: <dummy_test_message_id>
1796 ''')
1797 assert not os.path.exists(SENDMAILDEBUG)
1798 self.assertEqual(self.db.issue.get(nodeid, 'title'),
1799 'testing [frobulated]')
1801 def testInvalidCommandPassthroughLoose(self):
1802 self.instance.config.MAILGW_SUBJECT_SUFFIX_PARSING = 'loose'
1803 nodeid = self._handle_mail('''Content-Type: text/plain;
1804 charset="iso-8859-1"
1805 From: Chef <chef@bork.bork.bork>
1806 To: issue_tracker@your.tracker.email.domain.example
1807 Subject: testing [frobulated]
1808 Cc: richard@test.test
1809 Reply-To: chef@bork.bork.bork
1810 Message-Id: <dummy_test_message_id>
1812 ''')
1813 assert not os.path.exists(SENDMAILDEBUG)
1814 self.assertEqual(self.db.issue.get(nodeid, 'title'),
1815 'testing [frobulated]')
1817 def testInvalidCommandPassthroughLooseOK(self):
1818 self.instance.config.MAILGW_SUBJECT_SUFFIX_PARSING = 'loose'
1819 nodeid = self._handle_mail('''Content-Type: text/plain;
1820 charset="iso-8859-1"
1821 From: Chef <chef@bork.bork.bork>
1822 To: issue_tracker@your.tracker.email.domain.example
1823 Subject: testing [assignedto=mary]
1824 Cc: richard@test.test
1825 Reply-To: chef@bork.bork.bork
1826 Message-Id: <dummy_test_message_id>
1828 ''')
1829 assert not os.path.exists(SENDMAILDEBUG)
1830 self.assertEqual(self.db.issue.get(nodeid, 'title'), 'testing')
1831 self.assertEqual(self.db.issue.get(nodeid, 'assignedto'), self.mary_id)
1833 def testCommandDelimiters(self):
1834 self.instance.config.MAILGW_SUBJECT_SUFFIX_DELIMITERS = '{}'
1835 nodeid = self._handle_mail('''Content-Type: text/plain;
1836 charset="iso-8859-1"
1837 From: Chef <chef@bork.bork.bork>
1838 To: issue_tracker@your.tracker.email.domain.example
1839 Subject: testing {assignedto=mary}
1840 Cc: richard@test.test
1841 Reply-To: chef@bork.bork.bork
1842 Message-Id: <dummy_test_message_id>
1844 ''')
1845 assert not os.path.exists(SENDMAILDEBUG)
1846 self.assertEqual(self.db.issue.get(nodeid, 'title'), 'testing')
1847 self.assertEqual(self.db.issue.get(nodeid, 'assignedto'), self.mary_id)
1849 def testPrefixDelimiters(self):
1850 self.instance.config.MAILGW_SUBJECT_SUFFIX_DELIMITERS = '{}'
1851 self.db.keyword.create(name='Foo')
1852 self._handle_mail('''Content-Type: text/plain;
1853 charset="iso-8859-1"
1854 From: richard <richard@test.test>
1855 To: issue_tracker@your.tracker.email.domain.example
1856 Message-Id: <followup_dummy_id>
1857 In-Reply-To: <dummy_test_message_id>
1858 Subject: {keyword1} Testing... {name=Bar}
1860 ''')
1861 assert not os.path.exists(SENDMAILDEBUG)
1862 self.assertEqual(self.db.keyword.get('1', 'name'), 'Bar')
1864 def testCommandDelimitersIgnore(self):
1865 self.instance.config.MAILGW_SUBJECT_SUFFIX_DELIMITERS = '{}'
1866 nodeid = self._handle_mail('''Content-Type: text/plain;
1867 charset="iso-8859-1"
1868 From: Chef <chef@bork.bork.bork>
1869 To: issue_tracker@your.tracker.email.domain.example
1870 Subject: testing [assignedto=mary]
1871 Cc: richard@test.test
1872 Reply-To: chef@bork.bork.bork
1873 Message-Id: <dummy_test_message_id>
1875 ''')
1876 assert not os.path.exists(SENDMAILDEBUG)
1877 self.assertEqual(self.db.issue.get(nodeid, 'title'),
1878 'testing [assignedto=mary]')
1879 self.assertEqual(self.db.issue.get(nodeid, 'assignedto'), None)
1881 def testReplytoMatch(self):
1882 self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'loose'
1883 nodeid = self.doNewIssue()
1884 nodeid2 = self._handle_mail('''Content-Type: text/plain;
1885 charset="iso-8859-1"
1886 From: Chef <chef@bork.bork.bork>
1887 To: issue_tracker@your.tracker.email.domain.example
1888 Message-Id: <dummy_test_message_id2>
1889 In-Reply-To: <dummy_test_message_id>
1890 Subject: Testing...
1892 Followup message.
1893 ''')
1895 nodeid3 = self._handle_mail('''Content-Type: text/plain;
1896 charset="iso-8859-1"
1897 From: Chef <chef@bork.bork.bork>
1898 To: issue_tracker@your.tracker.email.domain.example
1899 Message-Id: <dummy_test_message_id3>
1900 In-Reply-To: <dummy_test_message_id2>
1901 Subject: Testing...
1903 Yet another message in the same thread/issue.
1904 ''')
1906 self.assertEqual(nodeid, nodeid2)
1907 self.assertEqual(nodeid, nodeid3)
1909 def testHelpSubject(self):
1910 message = '''Content-Type: text/plain;
1911 charset="iso-8859-1"
1912 From: Chef <chef@bork.bork.bork>
1913 To: issue_tracker@your.tracker.email.domain.example
1914 Message-Id: <dummy_test_message_id2>
1915 In-Reply-To: <dummy_test_message_id>
1916 Subject: hElp
1919 '''
1920 self.assertRaises(MailUsageHelp, self._handle_mail, message)
1922 def testMaillistSubject(self):
1923 self.instance.config.MAILGW_SUBJECT_SUFFIX_DELIMITERS = '[]'
1924 self.db.keyword.create(name='Foo')
1925 self._handle_mail('''Content-Type: text/plain;
1926 charset="iso-8859-1"
1927 From: Chef <chef@bork.bork.bork>
1928 To: issue_tracker@your.tracker.email.domain.example
1929 Subject: [mailinglist-name] [keyword1] Testing.. [name=Bar]
1930 Cc: richard@test.test
1931 Reply-To: chef@bork.bork.bork
1932 Message-Id: <dummy_test_message_id>
1934 ''')
1936 assert not os.path.exists(SENDMAILDEBUG)
1937 self.assertEqual(self.db.keyword.get('1', 'name'), 'Bar')
1939 def testUnknownPrefixSubject(self):
1940 self.db.keyword.create(name='Foo')
1941 self._handle_mail('''Content-Type: text/plain;
1942 charset="iso-8859-1"
1943 From: Chef <chef@bork.bork.bork>
1944 To: issue_tracker@your.tracker.email.domain.example
1945 Subject: VeryStrangeRe: [keyword1] Testing.. [name=Bar]
1946 Cc: richard@test.test
1947 Reply-To: chef@bork.bork.bork
1948 Message-Id: <dummy_test_message_id>
1950 ''')
1952 assert not os.path.exists(SENDMAILDEBUG)
1953 self.assertEqual(self.db.keyword.get('1', 'name'), 'Bar')
1955 def testOneCharSubject(self):
1956 message = '''Content-Type: text/plain;
1957 charset="iso-8859-1"
1958 From: Chef <chef@bork.bork.bork>
1959 To: issue_tracker@your.tracker.email.domain.example
1960 Subject: b
1961 Cc: richard@test.test
1962 Reply-To: chef@bork.bork.bork
1963 Message-Id: <dummy_test_message_id>
1965 '''
1966 try:
1967 self._handle_mail(message)
1968 except MailUsageError:
1969 self.fail('MailUsageError raised')
1971 def testIssueidLast(self):
1972 nodeid1 = self.doNewIssue()
1973 nodeid2 = 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: New title [issue1]
1981 This is a second followup
1982 ''')
1984 assert nodeid1 == nodeid2
1985 self.assertEqual(self.db.issue.get(nodeid2, 'title'), "Testing...")
1987 def testSecurityMessagePermissionContent(self):
1988 id = self.doNewIssue()
1989 issue = self.db.issue.getnode (id)
1990 self.db.security.addRole(name='Nomsg')
1991 self.db.security.addPermissionToRole('Nomsg', 'Email Access')
1992 for cl in 'issue', 'file', 'keyword':
1993 for p in 'View', 'Edit', 'Create':
1994 self.db.security.addPermissionToRole('Nomsg', p, cl)
1995 self.db.user.set(self.mary_id, roles='Nomsg')
1996 nodeid = self._handle_mail('''Content-Type: text/plain;
1997 charset="iso-8859-1"
1998 From: Chef <chef@bork.bork.bork>
1999 To: issue_tracker@your.tracker.email.domain.example
2000 Message-Id: <dummy_test_message_id_2>
2001 Subject: [issue%(id)s] Testing... [nosy=+mary]
2003 Just a test reply
2004 '''%locals())
2005 assert os.path.exists(SENDMAILDEBUG)
2006 self.compareMessages(self._get_mail(),
2007 '''FROM: roundup-admin@your.tracker.email.domain.example
2008 TO: chef@bork.bork.bork, richard@test.test
2009 Content-Type: text/plain; charset="utf-8"
2010 Subject: [issue1] Testing...
2011 To: richard@test.test
2012 From: "Bork, Chef" <issue_tracker@your.tracker.email.domain.example>
2013 Reply-To: Roundup issue tracker
2014 <issue_tracker@your.tracker.email.domain.example>
2015 MIME-Version: 1.0
2016 Message-Id: <dummy_test_message_id_2>
2017 In-Reply-To: <dummy_test_message_id>
2018 X-Roundup-Name: Roundup issue tracker
2019 X-Roundup-Loop: hello
2020 X-Roundup-Issue-Status: chatting
2021 Content-Transfer-Encoding: quoted-printable
2024 Bork, Chef <chef@bork.bork.bork> added the comment:
2026 Just a test reply
2028 ----------
2029 nosy: +mary
2030 status: unread -> chatting
2032 _______________________________________________________________________
2033 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
2034 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
2035 _______________________________________________________________________
2036 ''')
2038 def testOutlookAttachment(self):
2039 message = '''X-MimeOLE: Produced By Microsoft Exchange V6.5
2040 Content-class: urn:content-classes:message
2041 MIME-Version: 1.0
2042 Content-Type: multipart/mixed;
2043 boundary="----_=_NextPart_001_01CACA65.40A51CBC"
2044 Subject: Example of a failed outlook attachment e-mail
2045 Date: Tue, 23 Mar 2010 01:43:44 -0700
2046 Message-ID: <CA37F17219784343816CA6613D2E339205E7D0F9@nrcwstexb1.nrc.ca>
2047 X-MS-Has-Attach: yes
2048 X-MS-TNEF-Correlator:
2049 Thread-Topic: Example of a failed outlook attachment e-mail
2050 Thread-Index: AcrKJo/t3pUBBwTpSwWNE3LE67UBDQ==
2051 From: "Hugh" <richard@test.test>
2052 To: <richard@test.test>
2053 X-OriginalArrivalTime: 23 Mar 2010 08:45:57.0350 (UTC) FILETIME=[41893860:01CACA65]
2055 This is a multi-part message in MIME format.
2057 ------_=_NextPart_001_01CACA65.40A51CBC
2058 Content-Type: multipart/alternative;
2059 boundary="----_=_NextPart_002_01CACA65.40A51CBC"
2062 ------_=_NextPart_002_01CACA65.40A51CBC
2063 Content-Type: text/plain;
2064 charset="us-ascii"
2065 Content-Transfer-Encoding: quoted-printable
2068 Hi Richard,
2070 I suppose this isn't the exact message that was sent but is a resend of
2071 one of my trial messages that failed. For your benefit I changed the
2072 subject line and am adding these words to the message body. Should
2073 still be as problematic, but if you like I can resend an exact copy of a
2074 failed message changing nothing except putting your address instead of
2075 our tracker.
2077 Thanks very much for taking time to look into this. Much appreciated.
2079 <<battery backup>>=20
2081 ------_=_NextPart_002_01CACA65.40A51CBC
2082 Content-Type: text/html;
2083 charset="us-ascii"
2084 Content-Transfer-Encoding: quoted-printable
2086 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
2087 <HTML>
2088 <HEAD>
2089 <META HTTP-EQUIV=3D"Content-Type" CONTENT=3D"text/html; =
2090 charset=3Dus-ascii">
2091 <META NAME=3D"Generator" CONTENT=3D"MS Exchange Server version =
2092 6.5.7654.12">
2093 <TITLE>Example of a failed outlook attachment e-mail</TITLE>
2094 </HEAD>
2095 <BODY>
2096 <!-- Converted from text/rtf format -->
2097 <BR>
2099 <P><FONT SIZE=3D2 FACE=3D"Arial">Hi Richard,</FONT>
2100 </P>
2102 <P><FONT SIZE=3D2 FACE=3D"Arial">I suppose this isn't the exact message =
2103 that was sent but is a resend of one of my trial messages that =
2104 failed. For your benefit I changed the subject line and am adding =
2105 these words to the message body. Should still be as problematic, =
2106 but if you like I can resend an exact copy of a failed message changing =
2107 nothing except putting your address instead of our tracker.</FONT></P>
2109 <P><FONT SIZE=3D2 FACE=3D"Arial">Thanks very much for taking time to =
2110 look into this. Much appreciated.</FONT>
2111 </P>
2112 <BR>
2114 <P><FONT FACE=3D"Arial" SIZE=3D2 COLOR=3D"#000000"> <<battery =
2115 backup>> </FONT>
2116 </P>
2118 </BODY>
2119 </HTML>
2120 ------_=_NextPart_002_01CACA65.40A51CBC--
2122 ------_=_NextPart_001_01CACA65.40A51CBC
2123 Content-Type: message/rfc822
2124 Content-Transfer-Encoding: 7bit
2126 X-MimeOLE: Produced By Microsoft Exchange V6.5
2127 MIME-Version: 1.0
2128 Content-Type: multipart/alternative;
2129 boundary="----_=_NextPart_003_01CAC15A.29717800"
2130 X-OriginalArrivalTime: 11 Mar 2010 20:33:51.0249 (UTC) FILETIME=[28FEE010:01CAC15A]
2131 Content-class: urn:content-classes:message
2132 Subject: battery backup
2133 Date: Thu, 11 Mar 2010 13:33:43 -0700
2134 Message-ID: <p06240809c7bf02f9624c@[128.114.22.203]>
2135 X-MS-Has-Attach:
2136 X-MS-TNEF-Correlator:
2137 Thread-Topic: battery backup
2138 Thread-Index: AcrBWimtulTrSvBdQ2CcfZ8lyQdxmQ==
2139 From: "Jerry" <jerry@test.test>
2140 To: "Hugh" <hugh@test.test>
2142 This is a multi-part message in MIME format.
2144 ------_=_NextPart_003_01CAC15A.29717800
2145 Content-Type: text/plain;
2146 charset="iso-8859-1"
2147 Content-Transfer-Encoding: quoted-printable
2149 Dear Hugh,
2150 A car batter has an energy capacity of ~ 500Wh. A UPS=20
2151 battery is worse than this.
2153 if we need to provied 100kW for 30 minutes that will take 100 car=20
2154 batteries. This seems like an awful lot of batteries.
2156 Of course I like your idea of making the time 1 minute, so we get to=20
2157 a more modest number of batteries
2159 Jerry
2162 ------_=_NextPart_003_01CAC15A.29717800
2163 Content-Type: text/html;
2164 charset="iso-8859-1"
2165 Content-Transfer-Encoding: quoted-printable
2167 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
2168 <HTML>
2169 <HEAD>
2170 <META HTTP-EQUIV=3D"Content-Type" CONTENT=3D"text/html; =
2171 charset=3Diso-8859-1">
2172 <META NAME=3D"Generator" CONTENT=3D"MS Exchange Server version =
2173 6.5.7654.12">
2174 <TITLE>battery backup</TITLE>
2175 </HEAD>
2176 <BODY>
2177 <!-- Converted from text/plain format -->
2179 <P><FONT SIZE=3D2>Dear Hugh,</FONT>
2181 <BR> <FONT SIZE=3D2>A car =
2182 batter has an energy capacity of ~ 500Wh. A UPS </FONT>
2184 <BR><FONT SIZE=3D2>battery is worse than this.</FONT>
2185 </P>
2187 <P><FONT SIZE=3D2>if we need to provied 100kW for 30 minutes that will =
2188 take 100 car </FONT>
2190 <BR><FONT SIZE=3D2>batteries. This seems like an awful lot of =
2191 batteries.</FONT>
2192 </P>
2194 <P><FONT SIZE=3D2>Of course I like your idea of making the time 1 =
2195 minute, so we get to </FONT>
2197 <BR><FONT SIZE=3D2>a more modest number of batteries</FONT>
2198 </P>
2200 <P><FONT SIZE=3D2>Jerry</FONT>
2201 </P>
2203 </BODY>
2204 </HTML>
2205 ------_=_NextPart_003_01CAC15A.29717800--
2207 ------_=_NextPart_001_01CACA65.40A51CBC--
2208 '''
2209 nodeid = self._handle_mail(message)
2210 assert not os.path.exists(SENDMAILDEBUG)
2211 msgid = self.db.issue.get(nodeid, 'messages')[0]
2212 self.assert_(self.db.msg.get(msgid, 'content').startswith('Hi Richard'))
2213 self.assertEqual(self.db.msg.get(msgid, 'files'), ['1', '2'])
2214 fileid = self.db.msg.get(msgid, 'files')[0]
2215 self.assertEqual(self.db.file.get(fileid, 'type'), 'text/html')
2216 fileid = self.db.msg.get(msgid, 'files')[1]
2217 self.assertEqual(self.db.file.get(fileid, 'type'), 'message/rfc822')
2219 def testForwardedMessageAttachment(self):
2220 message = '''Return-Path: <rgg@test.test>
2221 Received: from localhost(127.0.0.1), claiming to be "[115.130.26.69]"
2222 via SMTP by localhost, id smtpdAAApLaWrq; Tue Apr 13 23:10:05 2010
2223 Message-ID: <4BC4F9C7.50409@test.test>
2224 Date: Wed, 14 Apr 2010 09:09:59 +1000
2225 From: Rupert Goldie <rgg@test.test>
2226 User-Agent: Thunderbird 2.0.0.24 (Windows/20100228)
2227 MIME-Version: 1.0
2228 To: ekit issues <issues@test.test>
2229 Subject: [Fwd: PHP ERROR (fb)] post limit reached
2230 Content-Type: multipart/mixed; boundary="------------000807090608060304010403"
2232 This is a multi-part message in MIME format.
2233 --------------000807090608060304010403
2234 Content-Type: text/plain; charset=ISO-8859-1; format=flowed
2235 Content-Transfer-Encoding: 7bit
2237 Catch this exception and log it without emailing.
2239 --------------000807090608060304010403
2240 Content-Type: message/rfc822; name="PHP ERROR (fb).eml"
2241 Content-Transfer-Encoding: 7bit
2242 Content-Disposition: inline; filename="PHP ERROR (fb).eml"
2244 Return-Path: <ektravj@test.test>
2245 X-Sieve: CMU Sieve 2.2
2246 via SMTP by crown.off.ekorp.com, id smtpdAAA1JaW1o; Tue Apr 13 23:01:04 2010
2247 X-Virus-Scanned: by amavisd-new at ekit.com
2248 To: facebook-errors@test.test
2249 From: ektravj@test.test
2250 Subject: PHP ERROR (fb)
2251 Message-Id: <20100413230100.D601D27E84@mail2.elax3.ekorp.com>
2252 Date: Tue, 13 Apr 2010 23:01:00 +0000 (UTC)
2254 [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
2255 Stack trace:
2256 #0 /app/01/www/virtual/fb.ekit.com/htdocs/gateway/ekit/feed/index.php(178): fb_exceptions(Object(FacebookRestClientException))
2257 #1 {main}
2258 thrown in /app/01/www/virtual/fb.ekit.com/htdocs/includes/functions.php on line 280
2261 --------------000807090608060304010403--
2262 '''
2263 nodeid = self._handle_mail(message)
2264 assert not os.path.exists(SENDMAILDEBUG)
2265 msgid = self.db.issue.get(nodeid, 'messages')[0]
2266 self.assertEqual(self.db.msg.get(msgid, 'content'),
2267 'Catch this exception and log it without emailing.')
2268 self.assertEqual(self.db.msg.get(msgid, 'files'), ['1'])
2269 fileid = self.db.msg.get(msgid, 'files')[0]
2270 self.assertEqual(self.db.file.get(fileid, 'type'), 'message/rfc822')
2272 def test_suite():
2273 suite = unittest.TestSuite()
2274 suite.addTest(unittest.makeSuite(MailgwTestCase))
2275 return suite
2277 if __name__ == '__main__':
2278 runner = unittest.TextTestRunner()
2279 unittest.main(testRunner=runner)
2281 # vim: set filetype=python sts=4 sw=4 et si :