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
31 class Message(rfc822.Message):
32 """String-based Message class with equivalence test."""
33 def __init__(self, s):
34 rfc822.Message.__init__(self, StringIO(s.strip()))
36 def __eq__(self, other):
37 return (self.dict == other.dict and
38 self.fp.read() == other.fp.read())
40 class DiffHelper:
41 def compareMessages(self, new, old):
42 """Compare messages for semantic equivalence."""
43 new, old = Message(new), Message(old)
45 # all Roundup-generated messages have "Precedence: bulk"
46 old['Precedence'] = 'bulk'
48 # don't try to compare the date
49 del new['date'], old['date']
51 if not new == old:
52 res = []
54 for key in new.keys():
55 if key.startswith('from '):
56 # skip the unix from line
57 continue
58 if key.lower() == 'x-roundup-version':
59 # version changes constantly, so handle it specially
60 if new[key] != __version__:
61 res.append(' %s: %r != %r' % (key, __version__,
62 new[key]))
63 elif new.get(key, '') != old.get(key, ''):
64 res.append(' %s: %r != %r' % (key, old.get(key, ''),
65 new.get(key, '')))
67 body_diff = self.compareStrings(new.fp.read(), old.fp.read())
68 if body_diff:
69 res.append('')
70 res.extend(body_diff)
72 if res:
73 res.insert(0, 'Generated message not correct (diff follows):')
74 raise AssertionError, '\n'.join(res)
76 def compareStrings(self, s2, s1):
77 '''Note the reversal of s2 and s1 - difflib.SequenceMatcher wants
78 the first to be the "original" but in the calls in this file,
79 the second arg is the original. Ho hum.
80 '''
81 l1 = s1.strip().split('\n')
82 l2 = s2.strip().split('\n')
83 if l1 == l2:
84 return
85 s = difflib.SequenceMatcher(None, l1, l2)
86 res = []
87 for value, s1s, s1e, s2s, s2e in s.get_opcodes():
88 if value == 'equal':
89 for i in range(s1s, s1e):
90 res.append(' %s'%l1[i])
91 elif value == 'delete':
92 for i in range(s1s, s1e):
93 res.append('- %s'%l1[i])
94 elif value == 'insert':
95 for i in range(s2s, s2e):
96 res.append('+ %s'%l2[i])
97 elif value == 'replace':
98 for i, j in zip(range(s1s, s1e), range(s2s, s2e)):
99 res.append('- %s'%l1[i])
100 res.append('+ %s'%l2[j])
102 return res
104 class MailgwTestCase(unittest.TestCase, DiffHelper):
105 count = 0
106 schema = 'classic'
107 def setUp(self):
108 MailgwTestCase.count = MailgwTestCase.count + 1
109 self.dirname = '_test_mailgw_%s'%self.count
110 # set up and open a tracker
111 self.instance = db_test_base.setupTracker(self.dirname)
113 # and open the database
114 self.db = self.instance.open('admin')
115 self.chef_id = self.db.user.create(username='Chef',
116 address='chef@bork.bork.bork', realname='Bork, Chef', roles='User')
117 self.richard_id = self.db.user.create(username='richard',
118 address='richard@test.test', roles='User')
119 self.mary_id = self.db.user.create(username='mary',
120 address='mary@test.test', roles='User', realname='Contrary, Mary')
121 self.john_id = self.db.user.create(username='john',
122 address='john@test.test', roles='User', realname='John Doe',
123 alternate_addresses='jondoe@test.test\njohn.doe@test.test')
125 def tearDown(self):
126 if os.path.exists(SENDMAILDEBUG):
127 os.remove(SENDMAILDEBUG)
128 self.db.close()
129 try:
130 shutil.rmtree(self.dirname)
131 except OSError, error:
132 if error.errno not in (errno.ENOENT, errno.ESRCH): raise
134 def _handle_mail(self, message):
135 # handler will open a new db handle. On single-threaded
136 # databases we'll have to close our current connection
137 self.db.commit()
138 self.db.close()
139 handler = self.instance.MailGW(self.instance)
140 handler.trapExceptions = 0
141 ret = handler.main(StringIO(message))
142 # handler had its own database, open new connection
143 self.db = self.instance.open('admin')
144 return ret
146 def _get_mail(self):
147 f = open(SENDMAILDEBUG)
148 try:
149 return f.read()
150 finally:
151 f.close()
153 def testEmptyMessage(self):
154 nodeid = self._handle_mail('''Content-Type: text/plain;
155 charset="iso-8859-1"
156 From: Chef <chef@bork.bork.bork>
157 To: issue_tracker@your.tracker.email.domain.example
158 Cc: richard@test.test
159 Reply-To: chef@bork.bork.bork
160 Message-Id: <dummy_test_message_id>
161 Subject: [issue] Testing...
163 ''')
164 assert not os.path.exists(SENDMAILDEBUG)
165 self.assertEqual(self.db.issue.get(nodeid, 'title'), 'Testing...')
167 def doNewIssue(self):
168 nodeid = self._handle_mail('''Content-Type: text/plain;
169 charset="iso-8859-1"
170 From: Chef <chef@bork.bork.bork>
171 To: issue_tracker@your.tracker.email.domain.example
172 Cc: richard@test.test
173 Message-Id: <dummy_test_message_id>
174 Subject: [issue] Testing...
176 This is a test submission of a new issue.
177 ''')
178 assert not os.path.exists(SENDMAILDEBUG)
179 l = self.db.issue.get(nodeid, 'nosy')
180 l.sort()
181 self.assertEqual(l, [self.chef_id, self.richard_id])
182 return nodeid
184 def testNewIssue(self):
185 self.doNewIssue()
187 def testNewIssueNosy(self):
188 self.instance.config.ADD_AUTHOR_TO_NOSY = 'yes'
189 nodeid = self._handle_mail('''Content-Type: text/plain;
190 charset="iso-8859-1"
191 From: Chef <chef@bork.bork.bork>
192 To: issue_tracker@your.tracker.email.domain.example
193 Cc: richard@test.test
194 Message-Id: <dummy_test_message_id>
195 Subject: [issue] Testing...
197 This is a test submission of a new issue.
198 ''')
199 assert not os.path.exists(SENDMAILDEBUG)
200 l = self.db.issue.get(nodeid, 'nosy')
201 l.sort()
202 self.assertEqual(l, [self.chef_id, self.richard_id])
204 def testAlternateAddress(self):
205 self._handle_mail('''Content-Type: text/plain;
206 charset="iso-8859-1"
207 From: John Doe <john.doe@test.test>
208 To: issue_tracker@your.tracker.email.domain.example
209 Message-Id: <dummy_test_message_id>
210 Subject: [issue] Testing...
212 This is a test submission of a new issue.
213 ''')
214 userlist = self.db.user.list()
215 assert not os.path.exists(SENDMAILDEBUG)
216 self.assertEqual(userlist, self.db.user.list(),
217 "user created when it shouldn't have been")
219 def testNewIssueNoClass(self):
220 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: Testing...
228 This is a test submission of a new issue.
229 ''')
230 assert not os.path.exists(SENDMAILDEBUG)
232 def testNewIssueAuthMsg(self):
233 # TODO: fix the damn config - this is apalling
234 self.db.config.MESSAGES_TO_AUTHOR = 'yes'
235 self._handle_mail('''Content-Type: text/plain;
236 charset="iso-8859-1"
237 From: Chef <chef@bork.bork.bork>
238 To: issue_tracker@your.tracker.email.domain.example
239 Message-Id: <dummy_test_message_id>
240 Subject: [issue] Testing... [nosy=mary; assignedto=richard]
242 This is a test submission of a new issue.
243 ''')
244 self.compareMessages(self._get_mail(),
245 '''FROM: roundup-admin@your.tracker.email.domain.example
246 TO: chef@bork.bork.bork, mary@test.test, richard@test.test
247 Content-Type: text/plain; charset="utf-8"
248 Subject: [issue1] Testing...
249 To: chef@bork.bork.bork, mary@test.test, richard@test.test
250 From: "Bork, Chef" <issue_tracker@your.tracker.email.domain.example>
251 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
252 MIME-Version: 1.0
253 Message-Id: <dummy_test_message_id>
254 X-Roundup-Name: Roundup issue tracker
255 X-Roundup-Loop: hello
256 X-Roundup-Issue-Status: unread
257 Content-Transfer-Encoding: quoted-printable
260 New submission from Bork, Chef <chef@bork.bork.bork>:
262 This is a test submission of a new issue.
264 ----------
265 assignedto: richard
266 messages: 1
267 nosy: Chef, mary, richard
268 status: unread
269 title: Testing...
271 _______________________________________________________________________
272 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
273 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
274 _______________________________________________________________________
275 ''')
277 def testNewIssueNoAuthorInfo(self):
278 self.db.config.MAIL_ADD_AUTHORINFO = 'no'
279 self._handle_mail('''Content-Type: text/plain;
280 charset="iso-8859-1"
281 From: Chef <chef@bork.bork.bork>
282 To: issue_tracker@your.tracker.email.domain.example
283 Message-Id: <dummy_test_message_id>
284 Subject: [issue] Testing... [nosy=mary; assignedto=richard]
286 This is a test submission of a new issue.
287 ''')
288 self.compareMessages(self._get_mail(),
289 '''FROM: roundup-admin@your.tracker.email.domain.example
290 TO: chef@bork.bork.bork, mary@test.test, richard@test.test
291 Content-Type: text/plain; charset="utf-8"
292 Subject: [issue1] Testing...
293 To: mary@test.test, richard@test.test
294 From: "Bork, Chef" <issue_tracker@your.tracker.email.domain.example>
295 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
296 MIME-Version: 1.0
297 Message-Id: <dummy_test_message_id>
298 X-Roundup-Name: Roundup issue tracker
299 X-Roundup-Loop: hello
300 X-Roundup-Issue-Status: unread
301 Content-Transfer-Encoding: quoted-printable
303 This is a test submission of a new issue.
305 ----------
306 assignedto: richard
307 messages: 1
308 nosy: Chef, mary, richard
309 status: unread
310 title: Testing...
312 _______________________________________________________________________
313 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
314 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
315 _______________________________________________________________________
316 ''')
318 def testNewIssueNoAuthorEmail(self):
319 self.db.config.MAIL_ADD_AUTHOREMAIL = 'no'
320 self._handle_mail('''Content-Type: text/plain;
321 charset="iso-8859-1"
322 From: Chef <chef@bork.bork.bork>
323 To: issue_tracker@your.tracker.email.domain.example
324 Message-Id: <dummy_test_message_id>
325 Subject: [issue] Testing... [nosy=mary; assignedto=richard]
327 This is a test submission of a new issue.
328 ''')
329 self.compareMessages(self._get_mail(),
330 '''FROM: roundup-admin@your.tracker.email.domain.example
331 TO: chef@bork.bork.bork, mary@test.test, richard@test.test
332 Content-Type: text/plain; charset="utf-8"
333 Subject: [issue1] Testing...
334 To: mary@test.test, richard@test.test
335 From: "Bork, Chef" <issue_tracker@your.tracker.email.domain.example>
336 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
337 MIME-Version: 1.0
338 Message-Id: <dummy_test_message_id>
339 X-Roundup-Name: Roundup issue tracker
340 X-Roundup-Loop: hello
341 X-Roundup-Issue-Status: unread
342 Content-Transfer-Encoding: quoted-printable
344 New submission from Bork, Chef:
346 This is a test submission of a new issue.
348 ----------
349 assignedto: richard
350 messages: 1
351 nosy: Chef, mary, richard
352 status: unread
353 title: Testing...
355 _______________________________________________________________________
356 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
357 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
358 _______________________________________________________________________
359 ''')
361 multipart_msg = '''From: mary <mary@test.test>
362 To: issue_tracker@your.tracker.email.domain.example
363 Message-Id: <followup_dummy_id>
364 In-Reply-To: <dummy_test_message_id>
365 Subject: [issue1] Testing...
366 Content-Type: multipart/mixed; boundary="bxyzzy"
367 Content-Disposition: inline
370 --bxyzzy
371 Content-Type: multipart/alternative; boundary="bCsyhTFzCvuiizWE"
372 Content-Disposition: inline
374 --bCsyhTFzCvuiizWE
375 Content-Type: text/plain; charset=us-ascii
376 Content-Disposition: inline
378 test attachment first text/plain
380 --bCsyhTFzCvuiizWE
381 Content-Type: application/octet-stream
382 Content-Disposition: attachment; filename="first.dvi"
383 Content-Transfer-Encoding: base64
385 SnVzdCBhIHRlc3QgAQo=
387 --bCsyhTFzCvuiizWE
388 Content-Type: text/plain; charset=us-ascii
389 Content-Disposition: inline
391 test attachment second text/plain
393 --bCsyhTFzCvuiizWE
394 Content-Type: text/html
395 Content-Disposition: inline
397 <html>
398 to be ignored.
399 </html>
401 --bCsyhTFzCvuiizWE--
403 --bxyzzy
404 Content-Type: multipart/alternative; boundary="bCsyhTFzCvuiizWF"
405 Content-Disposition: inline
407 --bCsyhTFzCvuiizWF
408 Content-Type: text/plain; charset=us-ascii
409 Content-Disposition: inline
411 test attachment third text/plain
413 --bCsyhTFzCvuiizWF
414 Content-Type: application/octet-stream
415 Content-Disposition: attachment; filename="second.dvi"
416 Content-Transfer-Encoding: base64
418 SnVzdCBhIHRlc3QK
420 --bCsyhTFzCvuiizWF--
422 --bxyzzy--
423 '''
425 def testMultipartKeepAlternatives(self):
426 self.doNewIssue()
427 self._handle_mail(self.multipart_msg)
428 messages = self.db.issue.get('1', 'messages')
429 messages.sort()
430 msg = self.db.msg.getnode (messages[-1])
431 assert(len(msg.files) == 5)
432 names = {0 : 'first.dvi', 4 : 'second.dvi'}
433 content = {3 : 'test attachment third text/plain\n',
434 4 : 'Just a test\n'}
435 for n, id in enumerate (msg.files):
436 f = self.db.file.getnode (id)
437 self.assertEqual(f.name, names.get (n, 'unnamed'))
438 if n in content :
439 self.assertEqual(f.content, content [n])
440 self.assertEqual(msg.content, 'test attachment second text/plain')
442 def testMultipartDropAlternatives(self):
443 self.doNewIssue()
444 self.db.config.MAILGW_IGNORE_ALTERNATIVES = True
445 self._handle_mail(self.multipart_msg)
446 messages = self.db.issue.get('1', 'messages')
447 messages.sort()
448 msg = self.db.msg.getnode (messages[-1])
449 assert(len(msg.files) == 2)
450 names = {1 : 'second.dvi'}
451 content = {0 : 'test attachment third text/plain\n',
452 1 : 'Just a test\n'}
453 for n, id in enumerate (msg.files):
454 f = self.db.file.getnode (id)
455 self.assertEqual(f.name, names.get (n, 'unnamed'))
456 if n in content :
457 self.assertEqual(f.content, content [n])
458 self.assertEqual(msg.content, 'test attachment second text/plain')
460 def testSimpleFollowup(self):
461 self.doNewIssue()
462 self._handle_mail('''Content-Type: text/plain;
463 charset="iso-8859-1"
464 From: mary <mary@test.test>
465 To: issue_tracker@your.tracker.email.domain.example
466 Message-Id: <followup_dummy_id>
467 In-Reply-To: <dummy_test_message_id>
468 Subject: [issue1] Testing...
470 This is a second followup
471 ''')
472 self.compareMessages(self._get_mail(),
473 '''FROM: roundup-admin@your.tracker.email.domain.example
474 TO: chef@bork.bork.bork, richard@test.test
475 Content-Type: text/plain; charset="utf-8"
476 Subject: [issue1] Testing...
477 To: chef@bork.bork.bork, richard@test.test
478 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
479 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
480 MIME-Version: 1.0
481 Message-Id: <followup_dummy_id>
482 In-Reply-To: <dummy_test_message_id>
483 X-Roundup-Name: Roundup issue tracker
484 X-Roundup-Loop: hello
485 X-Roundup-Issue-Status: chatting
486 Content-Transfer-Encoding: quoted-printable
489 Contrary, Mary <mary@test.test> added the comment:
491 This is a second followup
493 ----------
494 status: unread -> chatting
496 _______________________________________________________________________
497 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
498 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
499 _______________________________________________________________________
500 ''')
502 def testFollowup(self):
503 self.doNewIssue()
505 self._handle_mail('''Content-Type: text/plain;
506 charset="iso-8859-1"
507 From: richard <richard@test.test>
508 To: issue_tracker@your.tracker.email.domain.example
509 Message-Id: <followup_dummy_id>
510 In-Reply-To: <dummy_test_message_id>
511 Subject: [issue1] Testing... [assignedto=mary; nosy=+john]
513 This is a followup
514 ''')
515 l = self.db.issue.get('1', 'nosy')
516 l.sort()
517 self.assertEqual(l, [self.chef_id, self.richard_id, self.mary_id,
518 self.john_id])
520 self.compareMessages(self._get_mail(),
521 '''FROM: roundup-admin@your.tracker.email.domain.example
522 TO: chef@bork.bork.bork, john@test.test, mary@test.test
523 Content-Type: text/plain; charset="utf-8"
524 Subject: [issue1] Testing...
525 To: chef@bork.bork.bork, john@test.test, mary@test.test
526 From: richard <issue_tracker@your.tracker.email.domain.example>
527 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
528 MIME-Version: 1.0
529 Message-Id: <followup_dummy_id>
530 In-Reply-To: <dummy_test_message_id>
531 X-Roundup-Name: Roundup issue tracker
532 X-Roundup-Loop: hello
533 X-Roundup-Issue-Status: chatting
534 Content-Transfer-Encoding: quoted-printable
537 richard <richard@test.test> added the comment:
539 This is a followup
541 ----------
542 assignedto: -> mary
543 nosy: +john, mary
544 status: unread -> chatting
546 _______________________________________________________________________
547 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
548 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
549 _______________________________________________________________________
550 ''')
552 def testPropertyChangeOnly(self):
553 self.doNewIssue()
554 oldvalues = self.db.getnode('issue', '1').copy()
555 oldvalues['assignedto'] = None
556 # reconstruct old behaviour: This would reuse the
557 # database-handle from the doNewIssue above which has committed
558 # as user "Chef". So we close and reopen the db as that user.
559 self.db.close()
560 self.db = self.instance.open('Chef')
561 self.db.issue.set('1', assignedto=self.chef_id)
562 self.db.commit()
563 self.db.issue.nosymessage('1', None, oldvalues)
565 new_mail = ""
566 for line in self._get_mail().split("\n"):
567 if "Message-Id: " in line:
568 continue
569 if "Date: " in line:
570 continue
571 new_mail += line+"\n"
573 self.compareMessages(new_mail, """
574 FROM: roundup-admin@your.tracker.email.domain.example
575 TO: chef@bork.bork.bork, richard@test.test
576 Content-Type: text/plain; charset="utf-8"
577 Subject: [issue1] Testing...
578 To: chef@bork.bork.bork, richard@test.test
579 From: "Bork, Chef" <issue_tracker@your.tracker.email.domain.example>
580 X-Roundup-Name: Roundup issue tracker
581 X-Roundup-Loop: hello
582 X-Roundup-Issue-Status: unread
583 X-Roundup-Version: 1.3.3
584 MIME-Version: 1.0
585 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
586 Content-Transfer-Encoding: quoted-printable
589 Change by Bork, Chef <chef@bork.bork.bork>:
592 ----------
593 assignedto: -> Chef
595 _______________________________________________________________________
596 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
597 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
598 _______________________________________________________________________
599 """)
602 #
603 # FOLLOWUP TITLE MATCH
604 #
605 def testFollowupTitleMatch(self):
606 self.doNewIssue()
607 self._handle_mail('''Content-Type: text/plain;
608 charset="iso-8859-1"
609 From: richard <richard@test.test>
610 To: issue_tracker@your.tracker.email.domain.example
611 Message-Id: <followup_dummy_id>
612 Subject: Re: Testing... [assignedto=mary; nosy=+john]
614 This is a followup
615 ''')
616 self.compareMessages(self._get_mail(),
617 '''FROM: roundup-admin@your.tracker.email.domain.example
618 TO: chef@bork.bork.bork, john@test.test, mary@test.test
619 Content-Type: text/plain; charset="utf-8"
620 Subject: [issue1] Testing...
621 To: chef@bork.bork.bork, john@test.test, mary@test.test
622 From: richard <issue_tracker@your.tracker.email.domain.example>
623 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
624 MIME-Version: 1.0
625 Message-Id: <followup_dummy_id>
626 In-Reply-To: <dummy_test_message_id>
627 X-Roundup-Name: Roundup issue tracker
628 X-Roundup-Loop: hello
629 X-Roundup-Issue-Status: chatting
630 Content-Transfer-Encoding: quoted-printable
633 richard <richard@test.test> added the comment:
635 This is a followup
637 ----------
638 assignedto: -> mary
639 nosy: +john, mary
640 status: unread -> chatting
642 _______________________________________________________________________
643 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
644 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
645 _______________________________________________________________________
646 ''')
648 def testFollowupTitleMatchMultiRe(self):
649 nodeid1 = self.doNewIssue()
650 nodeid2 = self._handle_mail('''Content-Type: text/plain;
651 charset="iso-8859-1"
652 From: richard <richard@test.test>
653 To: issue_tracker@your.tracker.email.domain.example
654 Message-Id: <followup_dummy_id>
655 Subject: Re: Testing... [assignedto=mary; nosy=+john]
657 This is a followup
658 ''')
660 nodeid3 = self._handle_mail('''Content-Type: text/plain;
661 charset="iso-8859-1"
662 From: richard <richard@test.test>
663 To: issue_tracker@your.tracker.email.domain.example
664 Message-Id: <followup2_dummy_id>
665 Subject: Ang: Re: Testing...
667 This is a followup
668 ''')
669 self.assertEqual(nodeid1, nodeid2)
670 self.assertEqual(nodeid1, nodeid3)
672 def testFollowupTitleMatchNever(self):
673 nodeid = self.doNewIssue()
674 self.db.config.MAILGW_SUBJECT_CONTENT_MATCH = 'never'
675 self.assertNotEqual(self._handle_mail('''Content-Type: text/plain;
676 charset="iso-8859-1"
677 From: richard <richard@test.test>
678 To: issue_tracker@your.tracker.email.domain.example
679 Message-Id: <followup_dummy_id>
680 Subject: Re: Testing...
682 This is a followup
683 '''), nodeid)
685 def testFollowupTitleMatchNeverInterval(self):
686 nodeid = self.doNewIssue()
687 # force failure of the interval
688 time.sleep(2)
689 self.db.config.MAILGW_SUBJECT_CONTENT_MATCH = 'creation 00:00:01'
690 self.assertNotEqual(self._handle_mail('''Content-Type: text/plain;
691 charset="iso-8859-1"
692 From: richard <richard@test.test>
693 To: issue_tracker@your.tracker.email.domain.example
694 Message-Id: <followup_dummy_id>
695 Subject: Re: Testing...
697 This is a followup
698 '''), nodeid)
701 def testFollowupTitleMatchInterval(self):
702 nodeid = self.doNewIssue()
703 self.db.config.MAILGW_SUBJECT_CONTENT_MATCH = 'creation +1d'
704 self.assertEqual(self._handle_mail('''Content-Type: text/plain;
705 charset="iso-8859-1"
706 From: richard <richard@test.test>
707 To: issue_tracker@your.tracker.email.domain.example
708 Message-Id: <followup_dummy_id>
709 Subject: Re: Testing...
711 This is a followup
712 '''), nodeid)
715 def testFollowupNosyAuthor(self):
716 self.doNewIssue()
717 self.db.config.ADD_AUTHOR_TO_NOSY = 'yes'
718 self._handle_mail('''Content-Type: text/plain;
719 charset="iso-8859-1"
720 From: john@test.test
721 To: issue_tracker@your.tracker.email.domain.example
722 Message-Id: <followup_dummy_id>
723 In-Reply-To: <dummy_test_message_id>
724 Subject: [issue1] Testing...
726 This is a followup
727 ''')
729 self.compareMessages(self._get_mail(),
730 '''FROM: roundup-admin@your.tracker.email.domain.example
731 TO: chef@bork.bork.bork, richard@test.test
732 Content-Type: text/plain; charset="utf-8"
733 Subject: [issue1] Testing...
734 To: chef@bork.bork.bork, richard@test.test
735 From: John Doe <issue_tracker@your.tracker.email.domain.example>
736 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
737 MIME-Version: 1.0
738 Message-Id: <followup_dummy_id>
739 In-Reply-To: <dummy_test_message_id>
740 X-Roundup-Name: Roundup issue tracker
741 X-Roundup-Loop: hello
742 X-Roundup-Issue-Status: chatting
743 Content-Transfer-Encoding: quoted-printable
746 John Doe <john@test.test> added the comment:
748 This is a followup
750 ----------
751 nosy: +john
752 status: unread -> chatting
754 _______________________________________________________________________
755 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
756 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
757 _______________________________________________________________________
759 ''')
761 def testFollowupNosyRecipients(self):
762 self.doNewIssue()
763 self.db.config.ADD_RECIPIENTS_TO_NOSY = 'yes'
764 self._handle_mail('''Content-Type: text/plain;
765 charset="iso-8859-1"
766 From: richard@test.test
767 To: issue_tracker@your.tracker.email.domain.example
768 Cc: john@test.test
769 Message-Id: <followup_dummy_id>
770 In-Reply-To: <dummy_test_message_id>
771 Subject: [issue1] Testing...
773 This is a followup
774 ''')
775 self.compareMessages(self._get_mail(),
776 '''FROM: roundup-admin@your.tracker.email.domain.example
777 TO: chef@bork.bork.bork
778 Content-Type: text/plain; charset="utf-8"
779 Subject: [issue1] Testing...
780 To: chef@bork.bork.bork
781 From: richard <issue_tracker@your.tracker.email.domain.example>
782 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
783 MIME-Version: 1.0
784 Message-Id: <followup_dummy_id>
785 In-Reply-To: <dummy_test_message_id>
786 X-Roundup-Name: Roundup issue tracker
787 X-Roundup-Loop: hello
788 X-Roundup-Issue-Status: chatting
789 Content-Transfer-Encoding: quoted-printable
792 richard <richard@test.test> added the comment:
794 This is a followup
796 ----------
797 nosy: +john
798 status: unread -> chatting
800 _______________________________________________________________________
801 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
802 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
803 _______________________________________________________________________
805 ''')
807 def testFollowupNosyAuthorAndCopy(self):
808 self.doNewIssue()
809 self.db.config.ADD_AUTHOR_TO_NOSY = 'yes'
810 self.db.config.MESSAGES_TO_AUTHOR = 'yes'
811 self._handle_mail('''Content-Type: text/plain;
812 charset="iso-8859-1"
813 From: john@test.test
814 To: issue_tracker@your.tracker.email.domain.example
815 Message-Id: <followup_dummy_id>
816 In-Reply-To: <dummy_test_message_id>
817 Subject: [issue1] Testing...
819 This is a followup
820 ''')
821 self.compareMessages(self._get_mail(),
822 '''FROM: roundup-admin@your.tracker.email.domain.example
823 TO: chef@bork.bork.bork, john@test.test, richard@test.test
824 Content-Type: text/plain; charset="utf-8"
825 Subject: [issue1] Testing...
826 To: chef@bork.bork.bork, john@test.test, richard@test.test
827 From: John Doe <issue_tracker@your.tracker.email.domain.example>
828 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
829 MIME-Version: 1.0
830 Message-Id: <followup_dummy_id>
831 In-Reply-To: <dummy_test_message_id>
832 X-Roundup-Name: Roundup issue tracker
833 X-Roundup-Loop: hello
834 X-Roundup-Issue-Status: chatting
835 Content-Transfer-Encoding: quoted-printable
838 John Doe <john@test.test> added the comment:
840 This is a followup
842 ----------
843 nosy: +john
844 status: unread -> chatting
846 _______________________________________________________________________
847 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
848 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
849 _______________________________________________________________________
851 ''')
853 def testFollowupNoNosyAuthor(self):
854 self.doNewIssue()
855 self.instance.config.ADD_AUTHOR_TO_NOSY = 'no'
856 self._handle_mail('''Content-Type: text/plain;
857 charset="iso-8859-1"
858 From: john@test.test
859 To: issue_tracker@your.tracker.email.domain.example
860 Message-Id: <followup_dummy_id>
861 In-Reply-To: <dummy_test_message_id>
862 Subject: [issue1] Testing...
864 This is a followup
865 ''')
866 self.compareMessages(self._get_mail(),
867 '''FROM: roundup-admin@your.tracker.email.domain.example
868 TO: chef@bork.bork.bork, richard@test.test
869 Content-Type: text/plain; charset="utf-8"
870 Subject: [issue1] Testing...
871 To: chef@bork.bork.bork, richard@test.test
872 From: John Doe <issue_tracker@your.tracker.email.domain.example>
873 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
874 MIME-Version: 1.0
875 Message-Id: <followup_dummy_id>
876 In-Reply-To: <dummy_test_message_id>
877 X-Roundup-Name: Roundup issue tracker
878 X-Roundup-Loop: hello
879 X-Roundup-Issue-Status: chatting
880 Content-Transfer-Encoding: quoted-printable
883 John Doe <john@test.test> added the comment:
885 This is a followup
887 ----------
888 status: unread -> chatting
890 _______________________________________________________________________
891 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
892 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
893 _______________________________________________________________________
895 ''')
897 def testFollowupNoNosyRecipients(self):
898 self.doNewIssue()
899 self.instance.config.ADD_RECIPIENTS_TO_NOSY = 'no'
900 self._handle_mail('''Content-Type: text/plain;
901 charset="iso-8859-1"
902 From: richard@test.test
903 To: issue_tracker@your.tracker.email.domain.example
904 Cc: john@test.test
905 Message-Id: <followup_dummy_id>
906 In-Reply-To: <dummy_test_message_id>
907 Subject: [issue1] Testing...
909 This is a followup
910 ''')
911 self.compareMessages(self._get_mail(),
912 '''FROM: roundup-admin@your.tracker.email.domain.example
913 TO: chef@bork.bork.bork
914 Content-Type: text/plain; charset="utf-8"
915 Subject: [issue1] Testing...
916 To: chef@bork.bork.bork
917 From: richard <issue_tracker@your.tracker.email.domain.example>
918 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
919 MIME-Version: 1.0
920 Message-Id: <followup_dummy_id>
921 In-Reply-To: <dummy_test_message_id>
922 X-Roundup-Name: Roundup issue tracker
923 X-Roundup-Loop: hello
924 X-Roundup-Issue-Status: chatting
925 Content-Transfer-Encoding: quoted-printable
928 richard <richard@test.test> added the comment:
930 This is a followup
932 ----------
933 status: unread -> chatting
935 _______________________________________________________________________
936 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
937 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
938 _______________________________________________________________________
940 ''')
942 def testFollowupEmptyMessage(self):
943 self.doNewIssue()
945 self._handle_mail('''Content-Type: text/plain;
946 charset="iso-8859-1"
947 From: richard <richard@test.test>
948 To: issue_tracker@your.tracker.email.domain.example
949 Message-Id: <followup_dummy_id>
950 In-Reply-To: <dummy_test_message_id>
951 Subject: [issue1] Testing... [assignedto=mary; nosy=+john]
953 ''')
954 l = self.db.issue.get('1', 'nosy')
955 l.sort()
956 self.assertEqual(l, [self.chef_id, self.richard_id, self.mary_id,
957 self.john_id])
959 # should be no file created (ie. no message)
960 assert not os.path.exists(SENDMAILDEBUG)
962 def testFollowupEmptyMessageNoSubject(self):
963 self.doNewIssue()
965 self._handle_mail('''Content-Type: text/plain;
966 charset="iso-8859-1"
967 From: richard <richard@test.test>
968 To: issue_tracker@your.tracker.email.domain.example
969 Message-Id: <followup_dummy_id>
970 In-Reply-To: <dummy_test_message_id>
971 Subject: [issue1] [assignedto=mary; nosy=+john]
973 ''')
974 l = self.db.issue.get('1', 'nosy')
975 l.sort()
976 self.assertEqual(l, [self.chef_id, self.richard_id, self.mary_id,
977 self.john_id])
979 # should be no file created (ie. no message)
980 assert not os.path.exists(SENDMAILDEBUG)
982 def testNosyRemove(self):
983 self.doNewIssue()
985 self._handle_mail('''Content-Type: text/plain;
986 charset="iso-8859-1"
987 From: richard <richard@test.test>
988 To: issue_tracker@your.tracker.email.domain.example
989 Message-Id: <followup_dummy_id>
990 In-Reply-To: <dummy_test_message_id>
991 Subject: [issue1] Testing... [nosy=-richard]
993 ''')
994 l = self.db.issue.get('1', 'nosy')
995 l.sort()
996 self.assertEqual(l, [self.chef_id])
998 # NO NOSY MESSAGE SHOULD BE SENT!
999 assert not os.path.exists(SENDMAILDEBUG)
1001 def testNewUserAuthor(self):
1003 l = self.db.user.list()
1004 l.sort()
1005 message = '''Content-Type: text/plain;
1006 charset="iso-8859-1"
1007 From: fubar <fubar@bork.bork.bork>
1008 To: issue_tracker@your.tracker.email.domain.example
1009 Message-Id: <dummy_test_message_id>
1010 Subject: [issue] Testing...
1012 This is a test submission of a new issue.
1013 '''
1014 def hook (db, **kw):
1015 ''' set up callback for db open '''
1016 db.security.role['anonymous'].permissions=[]
1017 anonid = db.user.lookup('anonymous')
1018 db.user.set(anonid, roles='Anonymous')
1019 self.instance.schema_hook = hook
1020 try:
1021 self._handle_mail(message)
1022 except Unauthorized, value:
1023 body_diff = self.compareMessages(str(value), """
1024 You are not a registered user.
1026 Unknown address: fubar@bork.bork.bork
1027 """)
1029 assert not body_diff, body_diff
1031 else:
1032 raise AssertionError, "Unathorized not raised when handling mail"
1035 def hook (db, **kw):
1036 ''' set up callback for db open '''
1037 # Add Web Access role to anonymous, and try again to make sure
1038 # we get a "please register at:" message this time.
1039 p = [
1040 db.security.getPermission('Create', 'user'),
1041 db.security.getPermission('Web Access', None),
1042 ]
1043 db.security.role['anonymous'].permissions=p
1044 self.instance.schema_hook = hook
1045 try:
1046 self._handle_mail(message)
1047 except Unauthorized, value:
1048 body_diff = self.compareMessages(str(value), """
1049 You are not a registered user. Please register at:
1051 http://tracker.example/cgi-bin/roundup.cgi/bugs/user?template=register
1053 ...before sending mail to the tracker.
1055 Unknown address: fubar@bork.bork.bork
1056 """)
1058 assert not body_diff, body_diff
1060 else:
1061 raise AssertionError, "Unathorized not raised when handling mail"
1063 # Make sure list of users is the same as before.
1064 m = self.db.user.list()
1065 m.sort()
1066 self.assertEqual(l, m)
1068 def hook (db, **kw):
1069 ''' set up callback for db open '''
1070 # now with the permission
1071 p = [
1072 db.security.getPermission('Create', 'user'),
1073 db.security.getPermission('Email Access', None),
1074 ]
1075 db.security.role['anonymous'].permissions=p
1076 self.instance.schema_hook = hook
1077 self._handle_mail(message)
1078 m = self.db.user.list()
1079 m.sort()
1080 self.assertNotEqual(l, m)
1082 def testNewUserAuthorHighBit(self):
1083 l = set(self.db.user.list())
1084 # From: name has Euro symbol in it
1085 message = '''Content-Type: text/plain;
1086 charset="iso-8859-1"
1087 From: =?utf8?b?SOKCrGxsbw==?= <fubar@bork.bork.bork>
1088 To: issue_tracker@your.tracker.email.domain.example
1089 Message-Id: <dummy_test_message_id>
1090 Subject: [issue] Testing...
1092 This is a test submission of a new issue.
1093 '''
1094 def hook (db, **kw):
1095 ''' set up callback for db open '''
1096 p = [
1097 db.security.getPermission('Create', 'user'),
1098 db.security.getPermission('Email Access', None),
1099 ]
1100 db.security.role['anonymous'].permissions=p
1101 self.instance.schema_hook = hook
1102 self._handle_mail(message)
1103 m = set(self.db.user.list())
1104 new = list(m - l)[0]
1105 name = self.db.user.get(new, 'realname')
1106 self.assertEquals(name, 'H€llo')
1108 def testEnc01(self):
1109 self.doNewIssue()
1110 self._handle_mail('''Content-Type: text/plain;
1111 charset="iso-8859-1"
1112 From: mary <mary@test.test>
1113 To: issue_tracker@your.tracker.email.domain.example
1114 Message-Id: <followup_dummy_id>
1115 In-Reply-To: <dummy_test_message_id>
1116 Subject: [issue1] Testing...
1117 Content-Type: text/plain;
1118 charset="iso-8859-1"
1119 Content-Transfer-Encoding: quoted-printable
1121 A message with encoding (encoded oe =F6)
1123 ''')
1124 self.compareMessages(self._get_mail(),
1125 '''FROM: roundup-admin@your.tracker.email.domain.example
1126 TO: chef@bork.bork.bork, richard@test.test
1127 Content-Type: text/plain; charset="utf-8"
1128 Subject: [issue1] Testing...
1129 To: chef@bork.bork.bork, richard@test.test
1130 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
1131 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1132 MIME-Version: 1.0
1133 Message-Id: <followup_dummy_id>
1134 In-Reply-To: <dummy_test_message_id>
1135 X-Roundup-Name: Roundup issue tracker
1136 X-Roundup-Loop: hello
1137 X-Roundup-Issue-Status: chatting
1138 Content-Transfer-Encoding: quoted-printable
1141 Contrary, Mary <mary@test.test> added the comment:
1143 A message with encoding (encoded oe =C3=B6)
1145 ----------
1146 status: unread -> chatting
1148 _______________________________________________________________________
1149 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1150 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1151 _______________________________________________________________________
1152 ''')
1154 def testEncNonUTF8(self):
1155 self.doNewIssue()
1156 self.instance.config.EMAIL_CHARSET = 'iso-8859-1'
1157 self._handle_mail('''Content-Type: text/plain;
1158 charset="iso-8859-1"
1159 From: mary <mary@test.test>
1160 To: issue_tracker@your.tracker.email.domain.example
1161 Message-Id: <followup_dummy_id>
1162 In-Reply-To: <dummy_test_message_id>
1163 Subject: [issue1] Testing...
1164 Content-Type: text/plain;
1165 charset="iso-8859-1"
1166 Content-Transfer-Encoding: quoted-printable
1168 A message with encoding (encoded oe =F6)
1170 ''')
1171 self.compareMessages(self._get_mail(),
1172 '''FROM: roundup-admin@your.tracker.email.domain.example
1173 TO: chef@bork.bork.bork, richard@test.test
1174 Content-Type: text/plain; charset="iso-8859-1"
1175 Subject: [issue1] Testing...
1176 To: chef@bork.bork.bork, richard@test.test
1177 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
1178 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1179 MIME-Version: 1.0
1180 Message-Id: <followup_dummy_id>
1181 In-Reply-To: <dummy_test_message_id>
1182 X-Roundup-Name: Roundup issue tracker
1183 X-Roundup-Loop: hello
1184 X-Roundup-Issue-Status: chatting
1185 Content-Transfer-Encoding: quoted-printable
1188 Contrary, Mary <mary@test.test> added the comment:
1190 A message with encoding (encoded oe =F6)
1192 ----------
1193 status: unread -> chatting
1195 _______________________________________________________________________
1196 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1197 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1198 _______________________________________________________________________
1199 ''')
1202 def testMultipartEnc01(self):
1203 self.doNewIssue()
1204 self._handle_mail('''Content-Type: text/plain;
1205 charset="iso-8859-1"
1206 From: mary <mary@test.test>
1207 To: issue_tracker@your.tracker.email.domain.example
1208 Message-Id: <followup_dummy_id>
1209 In-Reply-To: <dummy_test_message_id>
1210 Subject: [issue1] Testing...
1211 Content-Type: multipart/mixed;
1212 boundary="----_=_NextPart_000_01"
1214 This message is in MIME format. Since your mail reader does not understand
1215 this format, some or all of this message may not be legible.
1217 ------_=_NextPart_000_01
1218 Content-Type: text/plain;
1219 charset="iso-8859-1"
1220 Content-Transfer-Encoding: quoted-printable
1222 A message with first part encoded (encoded oe =F6)
1224 ''')
1225 self.compareMessages(self._get_mail(),
1226 '''FROM: roundup-admin@your.tracker.email.domain.example
1227 TO: chef@bork.bork.bork, richard@test.test
1228 Content-Type: text/plain; charset="utf-8"
1229 Subject: [issue1] Testing...
1230 To: chef@bork.bork.bork, richard@test.test
1231 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
1232 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1233 MIME-Version: 1.0
1234 Message-Id: <followup_dummy_id>
1235 In-Reply-To: <dummy_test_message_id>
1236 X-Roundup-Name: Roundup issue tracker
1237 X-Roundup-Loop: hello
1238 X-Roundup-Issue-Status: chatting
1239 Content-Transfer-Encoding: quoted-printable
1242 Contrary, Mary <mary@test.test> added the comment:
1244 A message with first part encoded (encoded oe =C3=B6)
1246 ----------
1247 status: unread -> chatting
1249 _______________________________________________________________________
1250 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1251 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1252 _______________________________________________________________________
1253 ''')
1255 def testContentDisposition(self):
1256 self.doNewIssue()
1257 self._handle_mail('''Content-Type: text/plain;
1258 charset="iso-8859-1"
1259 From: mary <mary@test.test>
1260 To: issue_tracker@your.tracker.email.domain.example
1261 Message-Id: <followup_dummy_id>
1262 In-Reply-To: <dummy_test_message_id>
1263 Subject: [issue1] Testing...
1264 Content-Type: multipart/mixed; boundary="bCsyhTFzCvuiizWE"
1265 Content-Disposition: inline
1268 --bCsyhTFzCvuiizWE
1269 Content-Type: text/plain; charset=us-ascii
1270 Content-Disposition: inline
1272 test attachment binary
1274 --bCsyhTFzCvuiizWE
1275 Content-Type: application/octet-stream
1276 Content-Disposition: attachment; filename="main.dvi"
1277 Content-Transfer-Encoding: base64
1279 SnVzdCBhIHRlc3QgAQo=
1281 --bCsyhTFzCvuiizWE--
1282 ''')
1283 messages = self.db.issue.get('1', 'messages')
1284 messages.sort()
1285 file = self.db.file.getnode (self.db.msg.get(messages[-1], 'files')[0])
1286 self.assertEqual(file.name, 'main.dvi')
1287 self.assertEqual(file.content, 'Just a test \001\n')
1289 def testFollowupStupidQuoting(self):
1290 self.doNewIssue()
1292 self._handle_mail('''Content-Type: text/plain;
1293 charset="iso-8859-1"
1294 From: richard <richard@test.test>
1295 To: issue_tracker@your.tracker.email.domain.example
1296 Message-Id: <followup_dummy_id>
1297 In-Reply-To: <dummy_test_message_id>
1298 Subject: Re: "[issue1] Testing... "
1300 This is a followup
1301 ''')
1302 self.compareMessages(self._get_mail(),
1303 '''FROM: roundup-admin@your.tracker.email.domain.example
1304 TO: chef@bork.bork.bork
1305 Content-Type: text/plain; charset="utf-8"
1306 Subject: [issue1] Testing...
1307 To: chef@bork.bork.bork
1308 From: richard <issue_tracker@your.tracker.email.domain.example>
1309 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1310 MIME-Version: 1.0
1311 Message-Id: <followup_dummy_id>
1312 In-Reply-To: <dummy_test_message_id>
1313 X-Roundup-Name: Roundup issue tracker
1314 X-Roundup-Loop: hello
1315 X-Roundup-Issue-Status: chatting
1316 Content-Transfer-Encoding: quoted-printable
1319 richard <richard@test.test> added the comment:
1321 This is a followup
1323 ----------
1324 status: unread -> chatting
1326 _______________________________________________________________________
1327 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1328 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1329 _______________________________________________________________________
1330 ''')
1332 def testEmailQuoting(self):
1333 self.instance.config.EMAIL_KEEP_QUOTED_TEXT = 'no'
1334 self.innerTestQuoting('''This is a followup
1335 ''')
1337 def testEmailQuotingRemove(self):
1338 self.instance.config.EMAIL_KEEP_QUOTED_TEXT = 'yes'
1339 self.innerTestQuoting('''Blah blah wrote:
1340 > Blah bklaskdfj sdf asdf jlaskdf skj sdkfjl asdf
1341 > skdjlkjsdfalsdkfjasdlfkj dlfksdfalksd fj
1342 >
1344 This is a followup
1345 ''')
1347 def innerTestQuoting(self, expect):
1348 nodeid = self.doNewIssue()
1350 messages = self.db.issue.get(nodeid, 'messages')
1352 self._handle_mail('''Content-Type: text/plain;
1353 charset="iso-8859-1"
1354 From: richard <richard@test.test>
1355 To: issue_tracker@your.tracker.email.domain.example
1356 Message-Id: <followup_dummy_id>
1357 In-Reply-To: <dummy_test_message_id>
1358 Subject: Re: [issue1] Testing...
1360 Blah blah wrote:
1361 > Blah bklaskdfj sdf asdf jlaskdf skj sdkfjl asdf
1362 > skdjlkjsdfalsdkfjasdlfkj dlfksdfalksd fj
1363 >
1365 This is a followup
1366 ''')
1367 # figure the new message id
1368 newmessages = self.db.issue.get(nodeid, 'messages')
1369 for msg in messages:
1370 newmessages.remove(msg)
1371 messageid = newmessages[0]
1373 self.compareMessages(self.db.msg.get(messageid, 'content'), expect)
1375 def testUserLookup(self):
1376 i = self.db.user.create(username='user1', address='user1@foo.com')
1377 self.assertEqual(uidFromAddress(self.db, ('', 'user1@foo.com'), 0), i)
1378 self.assertEqual(uidFromAddress(self.db, ('', 'USER1@foo.com'), 0), i)
1379 i = self.db.user.create(username='user2', address='USER2@foo.com')
1380 self.assertEqual(uidFromAddress(self.db, ('', 'USER2@foo.com'), 0), i)
1381 self.assertEqual(uidFromAddress(self.db, ('', 'user2@foo.com'), 0), i)
1383 def testUserAlternateLookup(self):
1384 i = self.db.user.create(username='user1', address='user1@foo.com',
1385 alternate_addresses='user1@bar.com')
1386 self.assertEqual(uidFromAddress(self.db, ('', 'user1@bar.com'), 0), i)
1387 self.assertEqual(uidFromAddress(self.db, ('', 'USER1@bar.com'), 0), i)
1389 def testUserCreate(self):
1390 i = uidFromAddress(self.db, ('', 'user@foo.com'), 1)
1391 self.assertNotEqual(uidFromAddress(self.db, ('', 'user@bar.com'), 1), i)
1393 def testRFC2822(self):
1394 ascii_header = "[issue243] This is a \"test\" - with 'quotation' marks"
1395 unicode_header = '[issue244] \xd0\xb0\xd0\xbd\xd0\xb4\xd1\x80\xd0\xb5\xd0\xb9'
1396 unicode_encoded = '=?utf-8?q?[issue244]_=D0=B0=D0=BD=D0=B4=D1=80=D0=B5=D0=B9?='
1397 self.assertEqual(rfc2822.encode_header(ascii_header), ascii_header)
1398 self.assertEqual(rfc2822.encode_header(unicode_header), unicode_encoded)
1400 def testRegistrationConfirmation(self):
1401 otk = "Aj4euk4LZSAdwePohj90SME5SpopLETL"
1402 self.db.getOTKManager().set(otk, username='johannes')
1403 self._handle_mail('''Content-Type: text/plain;
1404 charset="iso-8859-1"
1405 From: Chef <chef@bork.bork.bork>
1406 To: issue_tracker@your.tracker.email.domain.example
1407 Cc: richard@test.test
1408 Message-Id: <dummy_test_message_id>
1409 Subject: Re: Complete your registration to Roundup issue tracker
1410 -- key %s
1412 This is a test confirmation of registration.
1413 ''' % otk)
1414 self.db.user.lookup('johannes')
1416 def testFollowupOnNonIssue(self):
1417 self.db.keyword.create(name='Foo')
1418 self._handle_mail('''Content-Type: text/plain;
1419 charset="iso-8859-1"
1420 From: richard <richard@test.test>
1421 To: issue_tracker@your.tracker.email.domain.example
1422 Message-Id: <followup_dummy_id>
1423 In-Reply-To: <dummy_test_message_id>
1424 Subject: [keyword1] Testing... [name=Bar]
1426 ''')
1427 self.assertEqual(self.db.keyword.get('1', 'name'), 'Bar')
1429 def testResentFrom(self):
1430 nodeid = self._handle_mail('''Content-Type: text/plain;
1431 charset="iso-8859-1"
1432 From: Chef <chef@bork.bork.bork>
1433 Resent-From: mary <mary@test.test>
1434 To: issue_tracker@your.tracker.email.domain.example
1435 Cc: richard@test.test
1436 Message-Id: <dummy_test_message_id>
1437 Subject: [issue] Testing...
1439 This is a test submission of a new issue.
1440 ''')
1441 assert not os.path.exists(SENDMAILDEBUG)
1442 l = self.db.issue.get(nodeid, 'nosy')
1443 l.sort()
1444 self.assertEqual(l, [self.richard_id, self.mary_id])
1445 return nodeid
1447 def testDejaVu(self):
1448 self.assertRaises(IgnoreLoop, self._handle_mail,
1449 '''Content-Type: text/plain;
1450 charset="iso-8859-1"
1451 From: Chef <chef@bork.bork.bork>
1452 X-Roundup-Loop: hello
1453 To: issue_tracker@your.tracker.email.domain.example
1454 Cc: richard@test.test
1455 Message-Id: <dummy_test_message_id>
1456 Subject: Re: [issue] Testing...
1458 Hi, I've been mis-configured to loop messages back to myself.
1459 ''')
1461 def testItsBulkStupid(self):
1462 self.assertRaises(IgnoreBulk, self._handle_mail,
1463 '''Content-Type: text/plain;
1464 charset="iso-8859-1"
1465 From: Chef <chef@bork.bork.bork>
1466 Precedence: bulk
1467 To: issue_tracker@your.tracker.email.domain.example
1468 Cc: richard@test.test
1469 Message-Id: <dummy_test_message_id>
1470 Subject: Re: [issue] Testing...
1472 Hi, I'm on holidays, and this is a dumb auto-responder.
1473 ''')
1475 def testAutoReplyEmailsAreIgnored(self):
1476 self.assertRaises(IgnoreBulk, self._handle_mail,
1477 '''Content-Type: text/plain;
1478 charset="iso-8859-1"
1479 From: Chef <chef@bork.bork.bork>
1480 To: issue_tracker@your.tracker.email.domain.example
1481 Cc: richard@test.test
1482 Message-Id: <dummy_test_message_id>
1483 Subject: Re: [issue] Out of office AutoReply: Back next week
1485 Hi, I am back in the office next week
1486 ''')
1488 def testNoSubject(self):
1489 self.assertRaises(MailUsageError, self._handle_mail,
1490 '''Content-Type: text/plain;
1491 charset="iso-8859-1"
1492 From: Chef <chef@bork.bork.bork>
1493 To: issue_tracker@your.tracker.email.domain.example
1494 Cc: richard@test.test
1495 Reply-To: chef@bork.bork.bork
1496 Message-Id: <dummy_test_message_id>
1498 ''')
1500 #
1501 # TEST FOR INVALID DESIGNATOR HANDLING
1502 #
1503 def testInvalidDesignator(self):
1504 self.assertRaises(MailUsageError, self._handle_mail,
1505 '''Content-Type: text/plain;
1506 charset="iso-8859-1"
1507 From: Chef <chef@bork.bork.bork>
1508 To: issue_tracker@your.tracker.email.domain.example
1509 Subject: [frobulated] testing
1510 Cc: richard@test.test
1511 Reply-To: chef@bork.bork.bork
1512 Message-Id: <dummy_test_message_id>
1514 ''')
1515 self.assertRaises(MailUsageError, self._handle_mail,
1516 '''Content-Type: text/plain;
1517 charset="iso-8859-1"
1518 From: Chef <chef@bork.bork.bork>
1519 To: issue_tracker@your.tracker.email.domain.example
1520 Subject: [issue12345] testing
1521 Cc: richard@test.test
1522 Reply-To: chef@bork.bork.bork
1523 Message-Id: <dummy_test_message_id>
1525 ''')
1527 def testInvalidClassLoose(self):
1528 self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'loose'
1529 nodeid = self._handle_mail('''Content-Type: text/plain;
1530 charset="iso-8859-1"
1531 From: Chef <chef@bork.bork.bork>
1532 To: issue_tracker@your.tracker.email.domain.example
1533 Subject: [frobulated] testing
1534 Cc: richard@test.test
1535 Reply-To: chef@bork.bork.bork
1536 Message-Id: <dummy_test_message_id>
1538 ''')
1539 assert not os.path.exists(SENDMAILDEBUG)
1540 self.assertEqual(self.db.issue.get(nodeid, 'title'),
1541 '[frobulated] testing')
1543 def testInvalidClassLooseReply(self):
1544 self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'loose'
1545 nodeid = self._handle_mail('''Content-Type: text/plain;
1546 charset="iso-8859-1"
1547 From: Chef <chef@bork.bork.bork>
1548 To: issue_tracker@your.tracker.email.domain.example
1549 Subject: Re: [frobulated] testing
1550 Cc: richard@test.test
1551 Reply-To: chef@bork.bork.bork
1552 Message-Id: <dummy_test_message_id>
1554 ''')
1555 assert not os.path.exists(SENDMAILDEBUG)
1556 self.assertEqual(self.db.issue.get(nodeid, 'title'),
1557 '[frobulated] testing')
1559 def testInvalidClassLoose(self):
1560 self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'loose'
1561 nodeid = self._handle_mail('''Content-Type: text/plain;
1562 charset="iso-8859-1"
1563 From: Chef <chef@bork.bork.bork>
1564 To: issue_tracker@your.tracker.email.domain.example
1565 Subject: [issue1234] testing
1566 Cc: richard@test.test
1567 Reply-To: chef@bork.bork.bork
1568 Message-Id: <dummy_test_message_id>
1570 ''')
1571 assert not os.path.exists(SENDMAILDEBUG)
1572 self.assertEqual(self.db.issue.get(nodeid, 'title'),
1573 '[issue1234] testing')
1575 def testClassLooseOK(self):
1576 self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'loose'
1577 self.db.keyword.create(name='Foo')
1578 nodeid = self._handle_mail('''Content-Type: text/plain;
1579 charset="iso-8859-1"
1580 From: Chef <chef@bork.bork.bork>
1581 To: issue_tracker@your.tracker.email.domain.example
1582 Subject: [keyword1] Testing... [name=Bar]
1583 Cc: richard@test.test
1584 Reply-To: chef@bork.bork.bork
1585 Message-Id: <dummy_test_message_id>
1587 ''')
1588 assert not os.path.exists(SENDMAILDEBUG)
1589 self.assertEqual(self.db.keyword.get('1', 'name'), 'Bar')
1591 def testClassStrictInvalid(self):
1592 self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'strict'
1593 self.instance.config.MAILGW_DEFAULT_CLASS = ''
1595 message = '''Content-Type: text/plain;
1596 charset="iso-8859-1"
1597 From: Chef <chef@bork.bork.bork>
1598 To: issue_tracker@your.tracker.email.domain.example
1599 Subject: Testing...
1600 Cc: richard@test.test
1601 Reply-To: chef@bork.bork.bork
1602 Message-Id: <dummy_test_message_id>
1604 '''
1605 self.assertRaises(MailUsageError, self._handle_mail, message)
1607 def testClassStrictValid(self):
1608 self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'strict'
1609 self.instance.config.MAILGW_DEFAULT_CLASS = ''
1611 nodeid = self._handle_mail('''Content-Type: text/plain;
1612 charset="iso-8859-1"
1613 From: Chef <chef@bork.bork.bork>
1614 To: issue_tracker@your.tracker.email.domain.example
1615 Subject: [issue] Testing...
1616 Cc: richard@test.test
1617 Reply-To: chef@bork.bork.bork
1618 Message-Id: <dummy_test_message_id>
1620 ''')
1622 assert not os.path.exists(SENDMAILDEBUG)
1623 self.assertEqual(self.db.issue.get(nodeid, 'title'), 'Testing...')
1625 #
1626 # TEST FOR INVALID COMMANDS HANDLING
1627 #
1628 def testInvalidCommands(self):
1629 self.assertRaises(MailUsageError, self._handle_mail,
1630 '''Content-Type: text/plain;
1631 charset="iso-8859-1"
1632 From: Chef <chef@bork.bork.bork>
1633 To: issue_tracker@your.tracker.email.domain.example
1634 Subject: testing [frobulated]
1635 Cc: richard@test.test
1636 Reply-To: chef@bork.bork.bork
1637 Message-Id: <dummy_test_message_id>
1639 ''')
1641 def testInvalidCommandPassthrough(self):
1642 self.instance.config.MAILGW_SUBJECT_SUFFIX_PARSING = 'none'
1643 nodeid = self._handle_mail('''Content-Type: text/plain;
1644 charset="iso-8859-1"
1645 From: Chef <chef@bork.bork.bork>
1646 To: issue_tracker@your.tracker.email.domain.example
1647 Subject: testing [frobulated]
1648 Cc: richard@test.test
1649 Reply-To: chef@bork.bork.bork
1650 Message-Id: <dummy_test_message_id>
1652 ''')
1653 assert not os.path.exists(SENDMAILDEBUG)
1654 self.assertEqual(self.db.issue.get(nodeid, 'title'),
1655 'testing [frobulated]')
1657 def testInvalidCommandPassthroughLoose(self):
1658 self.instance.config.MAILGW_SUBJECT_SUFFIX_PARSING = 'loose'
1659 nodeid = self._handle_mail('''Content-Type: text/plain;
1660 charset="iso-8859-1"
1661 From: Chef <chef@bork.bork.bork>
1662 To: issue_tracker@your.tracker.email.domain.example
1663 Subject: testing [frobulated]
1664 Cc: richard@test.test
1665 Reply-To: chef@bork.bork.bork
1666 Message-Id: <dummy_test_message_id>
1668 ''')
1669 assert not os.path.exists(SENDMAILDEBUG)
1670 self.assertEqual(self.db.issue.get(nodeid, 'title'),
1671 'testing [frobulated]')
1673 def testInvalidCommandPassthroughLooseOK(self):
1674 self.instance.config.MAILGW_SUBJECT_SUFFIX_PARSING = 'loose'
1675 nodeid = self._handle_mail('''Content-Type: text/plain;
1676 charset="iso-8859-1"
1677 From: Chef <chef@bork.bork.bork>
1678 To: issue_tracker@your.tracker.email.domain.example
1679 Subject: testing [assignedto=mary]
1680 Cc: richard@test.test
1681 Reply-To: chef@bork.bork.bork
1682 Message-Id: <dummy_test_message_id>
1684 ''')
1685 assert not os.path.exists(SENDMAILDEBUG)
1686 self.assertEqual(self.db.issue.get(nodeid, 'title'), 'testing')
1687 self.assertEqual(self.db.issue.get(nodeid, 'assignedto'), self.mary_id)
1689 def testCommandDelimiters(self):
1690 self.instance.config.MAILGW_SUBJECT_SUFFIX_DELIMITERS = '{}'
1691 nodeid = self._handle_mail('''Content-Type: text/plain;
1692 charset="iso-8859-1"
1693 From: Chef <chef@bork.bork.bork>
1694 To: issue_tracker@your.tracker.email.domain.example
1695 Subject: testing {assignedto=mary}
1696 Cc: richard@test.test
1697 Reply-To: chef@bork.bork.bork
1698 Message-Id: <dummy_test_message_id>
1700 ''')
1701 assert not os.path.exists(SENDMAILDEBUG)
1702 self.assertEqual(self.db.issue.get(nodeid, 'title'), 'testing')
1703 self.assertEqual(self.db.issue.get(nodeid, 'assignedto'), self.mary_id)
1705 def testPrefixDelimiters(self):
1706 self.instance.config.MAILGW_SUBJECT_SUFFIX_DELIMITERS = '{}'
1707 self.db.keyword.create(name='Foo')
1708 self._handle_mail('''Content-Type: text/plain;
1709 charset="iso-8859-1"
1710 From: richard <richard@test.test>
1711 To: issue_tracker@your.tracker.email.domain.example
1712 Message-Id: <followup_dummy_id>
1713 In-Reply-To: <dummy_test_message_id>
1714 Subject: {keyword1} Testing... {name=Bar}
1716 ''')
1717 assert not os.path.exists(SENDMAILDEBUG)
1718 self.assertEqual(self.db.keyword.get('1', 'name'), 'Bar')
1720 def testCommandDelimitersIgnore(self):
1721 self.instance.config.MAILGW_SUBJECT_SUFFIX_DELIMITERS = '{}'
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: testing [assignedto=mary]
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.issue.get(nodeid, 'title'),
1734 'testing [assignedto=mary]')
1735 self.assertEqual(self.db.issue.get(nodeid, 'assignedto'), None)
1737 def testReplytoMatch(self):
1738 self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'loose'
1739 nodeid = self.doNewIssue()
1740 nodeid2 = self._handle_mail('''Content-Type: text/plain;
1741 charset="iso-8859-1"
1742 From: Chef <chef@bork.bork.bork>
1743 To: issue_tracker@your.tracker.email.domain.example
1744 Message-Id: <dummy_test_message_id2>
1745 In-Reply-To: <dummy_test_message_id>
1746 Subject: Testing...
1748 Followup message.
1749 ''')
1751 nodeid3 = self._handle_mail('''Content-Type: text/plain;
1752 charset="iso-8859-1"
1753 From: Chef <chef@bork.bork.bork>
1754 To: issue_tracker@your.tracker.email.domain.example
1755 Message-Id: <dummy_test_message_id3>
1756 In-Reply-To: <dummy_test_message_id2>
1757 Subject: Testing...
1759 Yet another message in the same thread/issue.
1760 ''')
1762 self.assertEqual(nodeid, nodeid2)
1763 self.assertEqual(nodeid, nodeid3)
1765 def testHelpSubject(self):
1766 message = '''Content-Type: text/plain;
1767 charset="iso-8859-1"
1768 From: Chef <chef@bork.bork.bork>
1769 To: issue_tracker@your.tracker.email.domain.example
1770 Message-Id: <dummy_test_message_id2>
1771 In-Reply-To: <dummy_test_message_id>
1772 Subject: hElp
1775 '''
1776 self.assertRaises(MailUsageHelp, self._handle_mail, message)
1778 def testMaillistSubject(self):
1779 self.instance.config.MAILGW_SUBJECT_SUFFIX_DELIMITERS = '[]'
1780 self.db.keyword.create(name='Foo')
1781 self._handle_mail('''Content-Type: text/plain;
1782 charset="iso-8859-1"
1783 From: Chef <chef@bork.bork.bork>
1784 To: issue_tracker@your.tracker.email.domain.example
1785 Subject: [mailinglist-name] [keyword1] Testing.. [name=Bar]
1786 Cc: richard@test.test
1787 Reply-To: chef@bork.bork.bork
1788 Message-Id: <dummy_test_message_id>
1790 ''')
1792 assert not os.path.exists(SENDMAILDEBUG)
1793 self.assertEqual(self.db.keyword.get('1', 'name'), 'Bar')
1795 def testUnknownPrefixSubject(self):
1796 self.db.keyword.create(name='Foo')
1797 self._handle_mail('''Content-Type: text/plain;
1798 charset="iso-8859-1"
1799 From: Chef <chef@bork.bork.bork>
1800 To: issue_tracker@your.tracker.email.domain.example
1801 Subject: VeryStrangeRe: [keyword1] Testing.. [name=Bar]
1802 Cc: richard@test.test
1803 Reply-To: chef@bork.bork.bork
1804 Message-Id: <dummy_test_message_id>
1806 ''')
1808 assert not os.path.exists(SENDMAILDEBUG)
1809 self.assertEqual(self.db.keyword.get('1', 'name'), 'Bar')
1811 def testIssueidLast(self):
1812 nodeid1 = self.doNewIssue()
1813 nodeid2 = self._handle_mail('''Content-Type: text/plain;
1814 charset="iso-8859-1"
1815 From: mary <mary@test.test>
1816 To: issue_tracker@your.tracker.email.domain.example
1817 Message-Id: <followup_dummy_id>
1818 In-Reply-To: <dummy_test_message_id>
1819 Subject: New title [issue1]
1821 This is a second followup
1822 ''')
1824 assert nodeid1 == nodeid2
1825 self.assertEqual(self.db.issue.get(nodeid2, 'title'), "Testing...")
1828 def test_suite():
1829 suite = unittest.TestSuite()
1830 suite.addTest(unittest.makeSuite(MailgwTestCase))
1831 return suite
1833 if __name__ == '__main__':
1834 runner = unittest.TextTestRunner()
1835 unittest.main(testRunner=runner)
1837 # vim: set filetype=python sts=4 sw=4 et si :