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', address='mary@test.test',
120 roles='User', realname='Contrary, Mary')
121 self.john_id = self.db.user.create(username='john', address='john@test.test',
122 alternate_addresses='jondoe@test.test\njohn.doe@test.test', roles='User',
123 realname='John Doe')
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 = self.instance.MailGW(self.instance, self.db)
136 handler.trapExceptions = 0
137 ret = handler.main(StringIO(message))
138 # handler can close the db on us and open a new one
139 self.db = handler.db
140 return ret
142 def _get_mail(self):
143 f = open(SENDMAILDEBUG)
144 try:
145 return f.read()
146 finally:
147 f.close()
149 def testEmptyMessage(self):
150 nodeid = self._handle_mail('''Content-Type: text/plain;
151 charset="iso-8859-1"
152 From: Chef <chef@bork.bork.bork>
153 To: issue_tracker@your.tracker.email.domain.example
154 Cc: richard@test.test
155 Reply-To: chef@bork.bork.bork
156 Message-Id: <dummy_test_message_id>
157 Subject: [issue] Testing...
159 ''')
160 assert not os.path.exists(SENDMAILDEBUG)
161 self.assertEqual(self.db.issue.get(nodeid, 'title'), 'Testing...')
163 def doNewIssue(self):
164 nodeid = self._handle_mail('''Content-Type: text/plain;
165 charset="iso-8859-1"
166 From: Chef <chef@bork.bork.bork>
167 To: issue_tracker@your.tracker.email.domain.example
168 Cc: richard@test.test
169 Message-Id: <dummy_test_message_id>
170 Subject: [issue] Testing...
172 This is a test submission of a new issue.
173 ''')
174 assert not os.path.exists(SENDMAILDEBUG)
175 l = self.db.issue.get(nodeid, 'nosy')
176 l.sort()
177 self.assertEqual(l, [self.chef_id, self.richard_id])
178 return nodeid
180 def testNewIssue(self):
181 self.doNewIssue()
183 def testNewIssueNosy(self):
184 self.instance.config.ADD_AUTHOR_TO_NOSY = 'yes'
185 nodeid = self._handle_mail('''Content-Type: text/plain;
186 charset="iso-8859-1"
187 From: Chef <chef@bork.bork.bork>
188 To: issue_tracker@your.tracker.email.domain.example
189 Cc: richard@test.test
190 Message-Id: <dummy_test_message_id>
191 Subject: [issue] Testing...
193 This is a test submission of a new issue.
194 ''')
195 assert not os.path.exists(SENDMAILDEBUG)
196 l = self.db.issue.get(nodeid, 'nosy')
197 l.sort()
198 self.assertEqual(l, [self.chef_id, self.richard_id])
200 def testAlternateAddress(self):
201 self._handle_mail('''Content-Type: text/plain;
202 charset="iso-8859-1"
203 From: John Doe <john.doe@test.test>
204 To: issue_tracker@your.tracker.email.domain.example
205 Message-Id: <dummy_test_message_id>
206 Subject: [issue] Testing...
208 This is a test submission of a new issue.
209 ''')
210 userlist = self.db.user.list()
211 assert not os.path.exists(SENDMAILDEBUG)
212 self.assertEqual(userlist, self.db.user.list(),
213 "user created when it shouldn't have been")
215 def testNewIssueNoClass(self):
216 self._handle_mail('''Content-Type: text/plain;
217 charset="iso-8859-1"
218 From: Chef <chef@bork.bork.bork>
219 To: issue_tracker@your.tracker.email.domain.example
220 Cc: richard@test.test
221 Message-Id: <dummy_test_message_id>
222 Subject: Testing...
224 This is a test submission of a new issue.
225 ''')
226 assert not os.path.exists(SENDMAILDEBUG)
228 def testNewIssueAuthMsg(self):
229 # TODO: fix the damn config - this is apalling
230 self.db.config.MESSAGES_TO_AUTHOR = 'yes'
231 self._handle_mail('''Content-Type: text/plain;
232 charset="iso-8859-1"
233 From: Chef <chef@bork.bork.bork>
234 To: issue_tracker@your.tracker.email.domain.example
235 Message-Id: <dummy_test_message_id>
236 Subject: [issue] Testing... [nosy=mary; assignedto=richard]
238 This is a test submission of a new issue.
239 ''')
240 self.compareMessages(self._get_mail(),
241 '''FROM: roundup-admin@your.tracker.email.domain.example
242 TO: chef@bork.bork.bork, mary@test.test, richard@test.test
243 Content-Type: text/plain; charset="utf-8"
244 Subject: [issue1] Testing...
245 To: chef@bork.bork.bork, mary@test.test, richard@test.test
246 From: "Bork, Chef" <issue_tracker@your.tracker.email.domain.example>
247 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
248 MIME-Version: 1.0
249 Message-Id: <dummy_test_message_id>
250 X-Roundup-Name: Roundup issue tracker
251 X-Roundup-Loop: hello
252 X-Roundup-Issue-Status: unread
253 Content-Transfer-Encoding: quoted-printable
256 New submission from Bork, Chef <chef@bork.bork.bork>:
258 This is a test submission of a new issue.
260 ----------
261 assignedto: richard
262 messages: 1
263 nosy: Chef, mary, richard
264 status: unread
265 title: Testing...
267 _______________________________________________________________________
268 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
269 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
270 _______________________________________________________________________
271 ''')
273 def testNewIssueNoAuthorInfo(self):
274 self.db.config.MAIL_ADD_AUTHORINFO = 'no'
275 self._handle_mail('''Content-Type: text/plain;
276 charset="iso-8859-1"
277 From: Chef <chef@bork.bork.bork>
278 To: issue_tracker@your.tracker.email.domain.example
279 Message-Id: <dummy_test_message_id>
280 Subject: [issue] Testing... [nosy=mary; assignedto=richard]
282 This is a test submission of a new issue.
283 ''')
284 self.compareMessages(self._get_mail(),
285 '''FROM: roundup-admin@your.tracker.email.domain.example
286 TO: chef@bork.bork.bork, mary@test.test, richard@test.test
287 Content-Type: text/plain; charset="utf-8"
288 Subject: [issue1] Testing...
289 To: mary@test.test, richard@test.test
290 From: "Bork, Chef" <issue_tracker@your.tracker.email.domain.example>
291 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
292 MIME-Version: 1.0
293 Message-Id: <dummy_test_message_id>
294 X-Roundup-Name: Roundup issue tracker
295 X-Roundup-Loop: hello
296 X-Roundup-Issue-Status: unread
297 Content-Transfer-Encoding: quoted-printable
299 This is a test submission of a new issue.
301 ----------
302 assignedto: richard
303 messages: 1
304 nosy: Chef, mary, richard
305 status: unread
306 title: Testing...
308 _______________________________________________________________________
309 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
310 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
311 _______________________________________________________________________
312 ''')
314 def testNewIssueNoAuthorEmail(self):
315 self.db.config.MAIL_ADD_AUTHOREMAIL = 'no'
316 self._handle_mail('''Content-Type: text/plain;
317 charset="iso-8859-1"
318 From: Chef <chef@bork.bork.bork>
319 To: issue_tracker@your.tracker.email.domain.example
320 Message-Id: <dummy_test_message_id>
321 Subject: [issue] Testing... [nosy=mary; assignedto=richard]
323 This is a test submission of a new issue.
324 ''')
325 self.compareMessages(self._get_mail(),
326 '''FROM: roundup-admin@your.tracker.email.domain.example
327 TO: chef@bork.bork.bork, mary@test.test, richard@test.test
328 Content-Type: text/plain; charset="utf-8"
329 Subject: [issue1] Testing...
330 To: mary@test.test, richard@test.test
331 From: "Bork, Chef" <issue_tracker@your.tracker.email.domain.example>
332 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
333 MIME-Version: 1.0
334 Message-Id: <dummy_test_message_id>
335 X-Roundup-Name: Roundup issue tracker
336 X-Roundup-Loop: hello
337 X-Roundup-Issue-Status: unread
338 Content-Transfer-Encoding: quoted-printable
340 New submission from Bork, Chef:
342 This is a test submission of a new issue.
344 ----------
345 assignedto: richard
346 messages: 1
347 nosy: Chef, mary, richard
348 status: unread
349 title: Testing...
351 _______________________________________________________________________
352 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
353 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
354 _______________________________________________________________________
355 ''')
357 multipart_msg = '''From: mary <mary@test.test>
358 To: issue_tracker@your.tracker.email.domain.example
359 Message-Id: <followup_dummy_id>
360 In-Reply-To: <dummy_test_message_id>
361 Subject: [issue1] Testing...
362 Content-Type: multipart/mixed; boundary="bxyzzy"
363 Content-Disposition: inline
366 --bxyzzy
367 Content-Type: multipart/alternative; boundary="bCsyhTFzCvuiizWE"
368 Content-Disposition: inline
370 --bCsyhTFzCvuiizWE
371 Content-Type: text/plain; charset=us-ascii
372 Content-Disposition: inline
374 test attachment first text/plain
376 --bCsyhTFzCvuiizWE
377 Content-Type: application/octet-stream
378 Content-Disposition: attachment; filename="first.dvi"
379 Content-Transfer-Encoding: base64
381 SnVzdCBhIHRlc3QgAQo=
383 --bCsyhTFzCvuiizWE
384 Content-Type: text/plain; charset=us-ascii
385 Content-Disposition: inline
387 test attachment second text/plain
389 --bCsyhTFzCvuiizWE
390 Content-Type: text/html
391 Content-Disposition: inline
393 <html>
394 to be ignored.
395 </html>
397 --bCsyhTFzCvuiizWE--
399 --bxyzzy
400 Content-Type: multipart/alternative; boundary="bCsyhTFzCvuiizWF"
401 Content-Disposition: inline
403 --bCsyhTFzCvuiizWF
404 Content-Type: text/plain; charset=us-ascii
405 Content-Disposition: inline
407 test attachment third text/plain
409 --bCsyhTFzCvuiizWF
410 Content-Type: application/octet-stream
411 Content-Disposition: attachment; filename="second.dvi"
412 Content-Transfer-Encoding: base64
414 SnVzdCBhIHRlc3QK
416 --bCsyhTFzCvuiizWF--
418 --bxyzzy--
419 '''
421 def testMultipartKeepAlternatives(self):
422 self.doNewIssue()
423 self._handle_mail(self.multipart_msg)
424 messages = self.db.issue.get('1', 'messages')
425 messages.sort()
426 msg = self.db.msg.getnode (messages[-1])
427 assert(len(msg.files) == 5)
428 names = {0 : 'first.dvi', 4 : 'second.dvi'}
429 content = {3 : 'test attachment third text/plain\n',
430 4 : 'Just a test\n'}
431 for n, id in enumerate (msg.files):
432 f = self.db.file.getnode (id)
433 self.assertEqual(f.name, names.get (n, 'unnamed'))
434 if n in content :
435 self.assertEqual(f.content, content [n])
436 self.assertEqual(msg.content, 'test attachment second text/plain')
438 def testMultipartDropAlternatives(self):
439 self.doNewIssue()
440 self.db.config.MAILGW_IGNORE_ALTERNATIVES = True
441 self._handle_mail(self.multipart_msg)
442 messages = self.db.issue.get('1', 'messages')
443 messages.sort()
444 msg = self.db.msg.getnode (messages[-1])
445 assert(len(msg.files) == 2)
446 names = {1 : 'second.dvi'}
447 content = {0 : 'test attachment third text/plain\n',
448 1 : 'Just a test\n'}
449 for n, id in enumerate (msg.files):
450 f = self.db.file.getnode (id)
451 self.assertEqual(f.name, names.get (n, 'unnamed'))
452 if n in content :
453 self.assertEqual(f.content, content [n])
454 self.assertEqual(msg.content, 'test attachment second text/plain')
456 def testSimpleFollowup(self):
457 self.doNewIssue()
458 self._handle_mail('''Content-Type: text/plain;
459 charset="iso-8859-1"
460 From: mary <mary@test.test>
461 To: issue_tracker@your.tracker.email.domain.example
462 Message-Id: <followup_dummy_id>
463 In-Reply-To: <dummy_test_message_id>
464 Subject: [issue1] Testing...
466 This is a second followup
467 ''')
468 self.compareMessages(self._get_mail(),
469 '''FROM: roundup-admin@your.tracker.email.domain.example
470 TO: chef@bork.bork.bork, richard@test.test
471 Content-Type: text/plain; charset="utf-8"
472 Subject: [issue1] Testing...
473 To: chef@bork.bork.bork, richard@test.test
474 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
475 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
476 MIME-Version: 1.0
477 Message-Id: <followup_dummy_id>
478 In-Reply-To: <dummy_test_message_id>
479 X-Roundup-Name: Roundup issue tracker
480 X-Roundup-Loop: hello
481 X-Roundup-Issue-Status: chatting
482 Content-Transfer-Encoding: quoted-printable
485 Contrary, Mary <mary@test.test> added the comment:
487 This is a second followup
489 ----------
490 status: unread -> chatting
492 _______________________________________________________________________
493 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
494 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
495 _______________________________________________________________________
496 ''')
498 def testFollowup(self):
499 self.doNewIssue()
501 self._handle_mail('''Content-Type: text/plain;
502 charset="iso-8859-1"
503 From: richard <richard@test.test>
504 To: issue_tracker@your.tracker.email.domain.example
505 Message-Id: <followup_dummy_id>
506 In-Reply-To: <dummy_test_message_id>
507 Subject: [issue1] Testing... [assignedto=mary; nosy=+john]
509 This is a followup
510 ''')
511 l = self.db.issue.get('1', 'nosy')
512 l.sort()
513 self.assertEqual(l, [self.chef_id, self.richard_id, self.mary_id,
514 self.john_id])
516 self.compareMessages(self._get_mail(),
517 '''FROM: roundup-admin@your.tracker.email.domain.example
518 TO: chef@bork.bork.bork, john@test.test, mary@test.test
519 Content-Type: text/plain; charset="utf-8"
520 Subject: [issue1] Testing...
521 To: chef@bork.bork.bork, john@test.test, mary@test.test
522 From: richard <issue_tracker@your.tracker.email.domain.example>
523 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
524 MIME-Version: 1.0
525 Message-Id: <followup_dummy_id>
526 In-Reply-To: <dummy_test_message_id>
527 X-Roundup-Name: Roundup issue tracker
528 X-Roundup-Loop: hello
529 X-Roundup-Issue-Status: chatting
530 Content-Transfer-Encoding: quoted-printable
533 richard <richard@test.test> added the comment:
535 This is a followup
537 ----------
538 assignedto: -> mary
539 nosy: +john, mary
540 status: unread -> chatting
542 _______________________________________________________________________
543 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
544 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
545 _______________________________________________________________________
546 ''')
548 def testPropertyChangeOnly(self):
549 self.doNewIssue()
550 oldvalues = self.db.getnode('issue', '1').copy()
551 oldvalues['assignedto'] = None
552 self.db.issue.set('1', assignedto=self.chef_id)
553 self.db.commit()
554 self.db.issue.nosymessage('1', None, oldvalues)
556 new_mail = ""
557 for line in self._get_mail().split("\n"):
558 if "Message-Id: " in line:
559 continue
560 if "Date: " in line:
561 continue
562 new_mail += line+"\n"
564 self.compareMessages(new_mail, """
565 FROM: roundup-admin@your.tracker.email.domain.example
566 TO: chef@bork.bork.bork, richard@test.test
567 Content-Type: text/plain; charset="utf-8"
568 Subject: [issue1] Testing...
569 To: chef@bork.bork.bork, richard@test.test
570 From: "Bork, Chef" <issue_tracker@your.tracker.email.domain.example>
571 X-Roundup-Name: Roundup issue tracker
572 X-Roundup-Loop: hello
573 X-Roundup-Issue-Status: unread
574 X-Roundup-Version: 1.3.3
575 MIME-Version: 1.0
576 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
577 Content-Transfer-Encoding: quoted-printable
580 Change by Bork, Chef <chef@bork.bork.bork>:
583 ----------
584 assignedto: -> Chef
586 _______________________________________________________________________
587 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
588 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
589 _______________________________________________________________________
590 """)
593 #
594 # FOLLOWUP TITLE MATCH
595 #
596 def testFollowupTitleMatch(self):
597 self.doNewIssue()
598 self._handle_mail('''Content-Type: text/plain;
599 charset="iso-8859-1"
600 From: richard <richard@test.test>
601 To: issue_tracker@your.tracker.email.domain.example
602 Message-Id: <followup_dummy_id>
603 Subject: Re: Testing... [assignedto=mary; nosy=+john]
605 This is a followup
606 ''')
607 self.compareMessages(self._get_mail(),
608 '''FROM: roundup-admin@your.tracker.email.domain.example
609 TO: chef@bork.bork.bork, john@test.test, mary@test.test
610 Content-Type: text/plain; charset="utf-8"
611 Subject: [issue1] Testing...
612 To: chef@bork.bork.bork, john@test.test, mary@test.test
613 From: richard <issue_tracker@your.tracker.email.domain.example>
614 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
615 MIME-Version: 1.0
616 Message-Id: <followup_dummy_id>
617 In-Reply-To: <dummy_test_message_id>
618 X-Roundup-Name: Roundup issue tracker
619 X-Roundup-Loop: hello
620 X-Roundup-Issue-Status: chatting
621 Content-Transfer-Encoding: quoted-printable
624 richard <richard@test.test> added the comment:
626 This is a followup
628 ----------
629 assignedto: -> mary
630 nosy: +john, mary
631 status: unread -> chatting
633 _______________________________________________________________________
634 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
635 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
636 _______________________________________________________________________
637 ''')
639 def testFollowupTitleMatchMultiRe(self):
640 nodeid1 = self.doNewIssue()
641 nodeid2 = self._handle_mail('''Content-Type: text/plain;
642 charset="iso-8859-1"
643 From: richard <richard@test.test>
644 To: issue_tracker@your.tracker.email.domain.example
645 Message-Id: <followup_dummy_id>
646 Subject: Re: Testing... [assignedto=mary; nosy=+john]
648 This is a followup
649 ''')
651 nodeid3 = self._handle_mail('''Content-Type: text/plain;
652 charset="iso-8859-1"
653 From: richard <richard@test.test>
654 To: issue_tracker@your.tracker.email.domain.example
655 Message-Id: <followup2_dummy_id>
656 Subject: Ang: Re: Testing...
658 This is a followup
659 ''')
660 self.assertEqual(nodeid1, nodeid2)
661 self.assertEqual(nodeid1, nodeid3)
663 def testFollowupTitleMatchNever(self):
664 nodeid = self.doNewIssue()
665 self.db.config.MAILGW_SUBJECT_CONTENT_MATCH = 'never'
666 self.assertNotEqual(self._handle_mail('''Content-Type: text/plain;
667 charset="iso-8859-1"
668 From: richard <richard@test.test>
669 To: issue_tracker@your.tracker.email.domain.example
670 Message-Id: <followup_dummy_id>
671 Subject: Re: Testing...
673 This is a followup
674 '''), nodeid)
676 def testFollowupTitleMatchNeverInterval(self):
677 nodeid = self.doNewIssue()
678 # force failure of the interval
679 time.sleep(2)
680 self.db.config.MAILGW_SUBJECT_CONTENT_MATCH = 'creation 00:00:01'
681 self.assertNotEqual(self._handle_mail('''Content-Type: text/plain;
682 charset="iso-8859-1"
683 From: richard <richard@test.test>
684 To: issue_tracker@your.tracker.email.domain.example
685 Message-Id: <followup_dummy_id>
686 Subject: Re: Testing...
688 This is a followup
689 '''), nodeid)
692 def testFollowupTitleMatchInterval(self):
693 nodeid = self.doNewIssue()
694 self.db.config.MAILGW_SUBJECT_CONTENT_MATCH = 'creation +1d'
695 self.assertEqual(self._handle_mail('''Content-Type: text/plain;
696 charset="iso-8859-1"
697 From: richard <richard@test.test>
698 To: issue_tracker@your.tracker.email.domain.example
699 Message-Id: <followup_dummy_id>
700 Subject: Re: Testing...
702 This is a followup
703 '''), nodeid)
706 def testFollowupNosyAuthor(self):
707 self.doNewIssue()
708 self.db.config.ADD_AUTHOR_TO_NOSY = 'yes'
709 self._handle_mail('''Content-Type: text/plain;
710 charset="iso-8859-1"
711 From: john@test.test
712 To: issue_tracker@your.tracker.email.domain.example
713 Message-Id: <followup_dummy_id>
714 In-Reply-To: <dummy_test_message_id>
715 Subject: [issue1] Testing...
717 This is a followup
718 ''')
720 self.compareMessages(self._get_mail(),
721 '''FROM: roundup-admin@your.tracker.email.domain.example
722 TO: chef@bork.bork.bork, richard@test.test
723 Content-Type: text/plain; charset="utf-8"
724 Subject: [issue1] Testing...
725 To: chef@bork.bork.bork, richard@test.test
726 From: John Doe <issue_tracker@your.tracker.email.domain.example>
727 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
728 MIME-Version: 1.0
729 Message-Id: <followup_dummy_id>
730 In-Reply-To: <dummy_test_message_id>
731 X-Roundup-Name: Roundup issue tracker
732 X-Roundup-Loop: hello
733 X-Roundup-Issue-Status: chatting
734 Content-Transfer-Encoding: quoted-printable
737 John Doe <john@test.test> added the comment:
739 This is a followup
741 ----------
742 nosy: +john
743 status: unread -> chatting
745 _______________________________________________________________________
746 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
747 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
748 _______________________________________________________________________
750 ''')
752 def testFollowupNosyRecipients(self):
753 self.doNewIssue()
754 self.db.config.ADD_RECIPIENTS_TO_NOSY = 'yes'
755 self._handle_mail('''Content-Type: text/plain;
756 charset="iso-8859-1"
757 From: richard@test.test
758 To: issue_tracker@your.tracker.email.domain.example
759 Cc: john@test.test
760 Message-Id: <followup_dummy_id>
761 In-Reply-To: <dummy_test_message_id>
762 Subject: [issue1] Testing...
764 This is a followup
765 ''')
766 self.compareMessages(self._get_mail(),
767 '''FROM: roundup-admin@your.tracker.email.domain.example
768 TO: chef@bork.bork.bork
769 Content-Type: text/plain; charset="utf-8"
770 Subject: [issue1] Testing...
771 To: chef@bork.bork.bork
772 From: richard <issue_tracker@your.tracker.email.domain.example>
773 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
774 MIME-Version: 1.0
775 Message-Id: <followup_dummy_id>
776 In-Reply-To: <dummy_test_message_id>
777 X-Roundup-Name: Roundup issue tracker
778 X-Roundup-Loop: hello
779 X-Roundup-Issue-Status: chatting
780 Content-Transfer-Encoding: quoted-printable
783 richard <richard@test.test> added the comment:
785 This is a followup
787 ----------
788 nosy: +john
789 status: unread -> chatting
791 _______________________________________________________________________
792 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
793 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
794 _______________________________________________________________________
796 ''')
798 def testFollowupNosyAuthorAndCopy(self):
799 self.doNewIssue()
800 self.db.config.ADD_AUTHOR_TO_NOSY = 'yes'
801 self.db.config.MESSAGES_TO_AUTHOR = 'yes'
802 self._handle_mail('''Content-Type: text/plain;
803 charset="iso-8859-1"
804 From: john@test.test
805 To: issue_tracker@your.tracker.email.domain.example
806 Message-Id: <followup_dummy_id>
807 In-Reply-To: <dummy_test_message_id>
808 Subject: [issue1] Testing...
810 This is a followup
811 ''')
812 self.compareMessages(self._get_mail(),
813 '''FROM: roundup-admin@your.tracker.email.domain.example
814 TO: chef@bork.bork.bork, john@test.test, richard@test.test
815 Content-Type: text/plain; charset="utf-8"
816 Subject: [issue1] Testing...
817 To: chef@bork.bork.bork, john@test.test, richard@test.test
818 From: John Doe <issue_tracker@your.tracker.email.domain.example>
819 Reply-To: Roundup issue tracker <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 testFollowupNoNosyAuthor(self):
845 self.doNewIssue()
846 self.instance.config.ADD_AUTHOR_TO_NOSY = 'no'
847 self._handle_mail('''Content-Type: text/plain;
848 charset="iso-8859-1"
849 From: john@test.test
850 To: issue_tracker@your.tracker.email.domain.example
851 Message-Id: <followup_dummy_id>
852 In-Reply-To: <dummy_test_message_id>
853 Subject: [issue1] Testing...
855 This is a followup
856 ''')
857 self.compareMessages(self._get_mail(),
858 '''FROM: roundup-admin@your.tracker.email.domain.example
859 TO: chef@bork.bork.bork, richard@test.test
860 Content-Type: text/plain; charset="utf-8"
861 Subject: [issue1] Testing...
862 To: chef@bork.bork.bork, richard@test.test
863 From: John Doe <issue_tracker@your.tracker.email.domain.example>
864 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
865 MIME-Version: 1.0
866 Message-Id: <followup_dummy_id>
867 In-Reply-To: <dummy_test_message_id>
868 X-Roundup-Name: Roundup issue tracker
869 X-Roundup-Loop: hello
870 X-Roundup-Issue-Status: chatting
871 Content-Transfer-Encoding: quoted-printable
874 John Doe <john@test.test> added the comment:
876 This is a followup
878 ----------
879 status: unread -> chatting
881 _______________________________________________________________________
882 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
883 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
884 _______________________________________________________________________
886 ''')
888 def testFollowupNoNosyRecipients(self):
889 self.doNewIssue()
890 self.instance.config.ADD_RECIPIENTS_TO_NOSY = 'no'
891 self._handle_mail('''Content-Type: text/plain;
892 charset="iso-8859-1"
893 From: richard@test.test
894 To: issue_tracker@your.tracker.email.domain.example
895 Cc: john@test.test
896 Message-Id: <followup_dummy_id>
897 In-Reply-To: <dummy_test_message_id>
898 Subject: [issue1] Testing...
900 This is a followup
901 ''')
902 self.compareMessages(self._get_mail(),
903 '''FROM: roundup-admin@your.tracker.email.domain.example
904 TO: chef@bork.bork.bork
905 Content-Type: text/plain; charset="utf-8"
906 Subject: [issue1] Testing...
907 To: chef@bork.bork.bork
908 From: richard <issue_tracker@your.tracker.email.domain.example>
909 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
910 MIME-Version: 1.0
911 Message-Id: <followup_dummy_id>
912 In-Reply-To: <dummy_test_message_id>
913 X-Roundup-Name: Roundup issue tracker
914 X-Roundup-Loop: hello
915 X-Roundup-Issue-Status: chatting
916 Content-Transfer-Encoding: quoted-printable
919 richard <richard@test.test> added the comment:
921 This is a followup
923 ----------
924 status: unread -> chatting
926 _______________________________________________________________________
927 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
928 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
929 _______________________________________________________________________
931 ''')
933 def testFollowupEmptyMessage(self):
934 self.doNewIssue()
936 self._handle_mail('''Content-Type: text/plain;
937 charset="iso-8859-1"
938 From: richard <richard@test.test>
939 To: issue_tracker@your.tracker.email.domain.example
940 Message-Id: <followup_dummy_id>
941 In-Reply-To: <dummy_test_message_id>
942 Subject: [issue1] Testing... [assignedto=mary; nosy=+john]
944 ''')
945 l = self.db.issue.get('1', 'nosy')
946 l.sort()
947 self.assertEqual(l, [self.chef_id, self.richard_id, self.mary_id,
948 self.john_id])
950 # should be no file created (ie. no message)
951 assert not os.path.exists(SENDMAILDEBUG)
953 def testFollowupEmptyMessageNoSubject(self):
954 self.doNewIssue()
956 self._handle_mail('''Content-Type: text/plain;
957 charset="iso-8859-1"
958 From: richard <richard@test.test>
959 To: issue_tracker@your.tracker.email.domain.example
960 Message-Id: <followup_dummy_id>
961 In-Reply-To: <dummy_test_message_id>
962 Subject: [issue1] [assignedto=mary; nosy=+john]
964 ''')
965 l = self.db.issue.get('1', 'nosy')
966 l.sort()
967 self.assertEqual(l, [self.chef_id, self.richard_id, self.mary_id,
968 self.john_id])
970 # should be no file created (ie. no message)
971 assert not os.path.exists(SENDMAILDEBUG)
973 def testNosyRemove(self):
974 self.doNewIssue()
976 self._handle_mail('''Content-Type: text/plain;
977 charset="iso-8859-1"
978 From: richard <richard@test.test>
979 To: issue_tracker@your.tracker.email.domain.example
980 Message-Id: <followup_dummy_id>
981 In-Reply-To: <dummy_test_message_id>
982 Subject: [issue1] Testing... [nosy=-richard]
984 ''')
985 l = self.db.issue.get('1', 'nosy')
986 l.sort()
987 self.assertEqual(l, [self.chef_id])
989 # NO NOSY MESSAGE SHOULD BE SENT!
990 assert not os.path.exists(SENDMAILDEBUG)
992 def testNewUserAuthor(self):
993 # first without the permission
994 # heh... just ignore the API for a second ;)
995 self.db.security.role['anonymous'].permissions=[]
996 anonid = self.db.user.lookup('anonymous')
997 self.db.user.set(anonid, roles='Anonymous')
999 l = self.db.user.list()
1000 l.sort()
1001 message = '''Content-Type: text/plain;
1002 charset="iso-8859-1"
1003 From: fubar <fubar@bork.bork.bork>
1004 To: issue_tracker@your.tracker.email.domain.example
1005 Message-Id: <dummy_test_message_id>
1006 Subject: [issue] Testing...
1008 This is a test submission of a new issue.
1009 '''
1010 try:
1011 self._handle_mail(message)
1012 except Unauthorized, value:
1013 body_diff = self.compareMessages(str(value), """
1014 You are not a registered user.
1016 Unknown address: fubar@bork.bork.bork
1017 """)
1019 assert not body_diff, body_diff
1021 else:
1022 raise AssertionError, "Unathorized not raised when handling mail"
1024 # Add Web Access role to anonymous, and try again to make sure
1025 # we get a "please register at:" message this time.
1026 p = [
1027 self.db.security.getPermission('Create', 'user'),
1028 self.db.security.getPermission('Web Access', None),
1029 ]
1031 self.db.security.role['anonymous'].permissions=p
1033 try:
1034 self._handle_mail(message)
1035 except Unauthorized, value:
1036 body_diff = self.compareMessages(str(value), """
1037 You are not a registered user. Please register at:
1039 http://tracker.example/cgi-bin/roundup.cgi/bugs/user?template=register
1041 ...before sending mail to the tracker.
1043 Unknown address: fubar@bork.bork.bork
1044 """)
1046 assert not body_diff, body_diff
1048 else:
1049 raise AssertionError, "Unathorized not raised when handling mail"
1051 # Make sure list of users is the same as before.
1052 m = self.db.user.list()
1053 m.sort()
1054 self.assertEqual(l, m)
1056 # now with the permission
1057 p = [
1058 self.db.security.getPermission('Create', 'user'),
1059 self.db.security.getPermission('Email Access', None),
1060 ]
1061 self.db.security.role['anonymous'].permissions=p
1062 self._handle_mail(message)
1063 m = self.db.user.list()
1064 m.sort()
1065 self.assertNotEqual(l, m)
1067 def testNewUserAuthorHighBit(self):
1068 l = set(self.db.user.list())
1069 # From: name has Euro symbol in it
1070 message = '''Content-Type: text/plain;
1071 charset="iso-8859-1"
1072 From: =?utf8?b?SOKCrGxsbw==?= <fubar@bork.bork.bork>
1073 To: issue_tracker@your.tracker.email.domain.example
1074 Message-Id: <dummy_test_message_id>
1075 Subject: [issue] Testing...
1077 This is a test submission of a new issue.
1078 '''
1079 p = [
1080 self.db.security.getPermission('Create', 'user'),
1081 self.db.security.getPermission('Email Access', None),
1082 ]
1083 self.db.security.role['anonymous'].permissions=p
1084 self._handle_mail(message)
1085 m = set(self.db.user.list())
1086 new = list(m - l)[0]
1087 name = self.db.user.get(new, 'realname')
1088 self.assertEquals(name, 'H€llo')
1090 def testEnc01(self):
1091 self.doNewIssue()
1092 self._handle_mail('''Content-Type: text/plain;
1093 charset="iso-8859-1"
1094 From: mary <mary@test.test>
1095 To: issue_tracker@your.tracker.email.domain.example
1096 Message-Id: <followup_dummy_id>
1097 In-Reply-To: <dummy_test_message_id>
1098 Subject: [issue1] Testing...
1099 Content-Type: text/plain;
1100 charset="iso-8859-1"
1101 Content-Transfer-Encoding: quoted-printable
1103 A message with encoding (encoded oe =F6)
1105 ''')
1106 self.compareMessages(self._get_mail(),
1107 '''FROM: roundup-admin@your.tracker.email.domain.example
1108 TO: chef@bork.bork.bork, richard@test.test
1109 Content-Type: text/plain; charset="utf-8"
1110 Subject: [issue1] Testing...
1111 To: chef@bork.bork.bork, richard@test.test
1112 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
1113 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1114 MIME-Version: 1.0
1115 Message-Id: <followup_dummy_id>
1116 In-Reply-To: <dummy_test_message_id>
1117 X-Roundup-Name: Roundup issue tracker
1118 X-Roundup-Loop: hello
1119 X-Roundup-Issue-Status: chatting
1120 Content-Transfer-Encoding: quoted-printable
1123 Contrary, Mary <mary@test.test> added the comment:
1125 A message with encoding (encoded oe =C3=B6)
1127 ----------
1128 status: unread -> chatting
1130 _______________________________________________________________________
1131 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1132 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1133 _______________________________________________________________________
1134 ''')
1136 def testEncNonUTF8(self):
1137 self.doNewIssue()
1138 self.instance.config.EMAIL_CHARSET = 'iso-8859-1'
1139 self._handle_mail('''Content-Type: text/plain;
1140 charset="iso-8859-1"
1141 From: mary <mary@test.test>
1142 To: issue_tracker@your.tracker.email.domain.example
1143 Message-Id: <followup_dummy_id>
1144 In-Reply-To: <dummy_test_message_id>
1145 Subject: [issue1] Testing...
1146 Content-Type: text/plain;
1147 charset="iso-8859-1"
1148 Content-Transfer-Encoding: quoted-printable
1150 A message with encoding (encoded oe =F6)
1152 ''')
1153 self.compareMessages(self._get_mail(),
1154 '''FROM: roundup-admin@your.tracker.email.domain.example
1155 TO: chef@bork.bork.bork, richard@test.test
1156 Content-Type: text/plain; charset="iso-8859-1"
1157 Subject: [issue1] Testing...
1158 To: chef@bork.bork.bork, richard@test.test
1159 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
1160 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1161 MIME-Version: 1.0
1162 Message-Id: <followup_dummy_id>
1163 In-Reply-To: <dummy_test_message_id>
1164 X-Roundup-Name: Roundup issue tracker
1165 X-Roundup-Loop: hello
1166 X-Roundup-Issue-Status: chatting
1167 Content-Transfer-Encoding: quoted-printable
1170 Contrary, Mary <mary@test.test> added the comment:
1172 A message with encoding (encoded oe =F6)
1174 ----------
1175 status: unread -> chatting
1177 _______________________________________________________________________
1178 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1179 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1180 _______________________________________________________________________
1181 ''')
1184 def testMultipartEnc01(self):
1185 self.doNewIssue()
1186 self._handle_mail('''Content-Type: text/plain;
1187 charset="iso-8859-1"
1188 From: mary <mary@test.test>
1189 To: issue_tracker@your.tracker.email.domain.example
1190 Message-Id: <followup_dummy_id>
1191 In-Reply-To: <dummy_test_message_id>
1192 Subject: [issue1] Testing...
1193 Content-Type: multipart/mixed;
1194 boundary="----_=_NextPart_000_01"
1196 This message is in MIME format. Since your mail reader does not understand
1197 this format, some or all of this message may not be legible.
1199 ------_=_NextPart_000_01
1200 Content-Type: text/plain;
1201 charset="iso-8859-1"
1202 Content-Transfer-Encoding: quoted-printable
1204 A message with first part encoded (encoded oe =F6)
1206 ''')
1207 self.compareMessages(self._get_mail(),
1208 '''FROM: roundup-admin@your.tracker.email.domain.example
1209 TO: chef@bork.bork.bork, richard@test.test
1210 Content-Type: text/plain; charset="utf-8"
1211 Subject: [issue1] Testing...
1212 To: chef@bork.bork.bork, richard@test.test
1213 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
1214 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1215 MIME-Version: 1.0
1216 Message-Id: <followup_dummy_id>
1217 In-Reply-To: <dummy_test_message_id>
1218 X-Roundup-Name: Roundup issue tracker
1219 X-Roundup-Loop: hello
1220 X-Roundup-Issue-Status: chatting
1221 Content-Transfer-Encoding: quoted-printable
1224 Contrary, Mary <mary@test.test> added the comment:
1226 A message with first part encoded (encoded oe =C3=B6)
1228 ----------
1229 status: unread -> chatting
1231 _______________________________________________________________________
1232 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1233 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1234 _______________________________________________________________________
1235 ''')
1237 def testContentDisposition(self):
1238 self.doNewIssue()
1239 self._handle_mail('''Content-Type: text/plain;
1240 charset="iso-8859-1"
1241 From: mary <mary@test.test>
1242 To: issue_tracker@your.tracker.email.domain.example
1243 Message-Id: <followup_dummy_id>
1244 In-Reply-To: <dummy_test_message_id>
1245 Subject: [issue1] Testing...
1246 Content-Type: multipart/mixed; boundary="bCsyhTFzCvuiizWE"
1247 Content-Disposition: inline
1250 --bCsyhTFzCvuiizWE
1251 Content-Type: text/plain; charset=us-ascii
1252 Content-Disposition: inline
1254 test attachment binary
1256 --bCsyhTFzCvuiizWE
1257 Content-Type: application/octet-stream
1258 Content-Disposition: attachment; filename="main.dvi"
1259 Content-Transfer-Encoding: base64
1261 SnVzdCBhIHRlc3QgAQo=
1263 --bCsyhTFzCvuiizWE--
1264 ''')
1265 messages = self.db.issue.get('1', 'messages')
1266 messages.sort()
1267 file = self.db.file.getnode (self.db.msg.get(messages[-1], 'files')[0])
1268 self.assertEqual(file.name, 'main.dvi')
1269 self.assertEqual(file.content, 'Just a test \001\n')
1271 def testFollowupStupidQuoting(self):
1272 self.doNewIssue()
1274 self._handle_mail('''Content-Type: text/plain;
1275 charset="iso-8859-1"
1276 From: richard <richard@test.test>
1277 To: issue_tracker@your.tracker.email.domain.example
1278 Message-Id: <followup_dummy_id>
1279 In-Reply-To: <dummy_test_message_id>
1280 Subject: Re: "[issue1] Testing... "
1282 This is a followup
1283 ''')
1284 self.compareMessages(self._get_mail(),
1285 '''FROM: roundup-admin@your.tracker.email.domain.example
1286 TO: chef@bork.bork.bork
1287 Content-Type: text/plain; charset="utf-8"
1288 Subject: [issue1] Testing...
1289 To: chef@bork.bork.bork
1290 From: richard <issue_tracker@your.tracker.email.domain.example>
1291 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1292 MIME-Version: 1.0
1293 Message-Id: <followup_dummy_id>
1294 In-Reply-To: <dummy_test_message_id>
1295 X-Roundup-Name: Roundup issue tracker
1296 X-Roundup-Loop: hello
1297 X-Roundup-Issue-Status: chatting
1298 Content-Transfer-Encoding: quoted-printable
1301 richard <richard@test.test> added the comment:
1303 This is a followup
1305 ----------
1306 status: unread -> chatting
1308 _______________________________________________________________________
1309 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1310 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1311 _______________________________________________________________________
1312 ''')
1314 def testEmailQuoting(self):
1315 self.instance.config.EMAIL_KEEP_QUOTED_TEXT = 'no'
1316 self.innerTestQuoting('''This is a followup
1317 ''')
1319 def testEmailQuotingRemove(self):
1320 self.instance.config.EMAIL_KEEP_QUOTED_TEXT = 'yes'
1321 self.innerTestQuoting('''Blah blah wrote:
1322 > Blah bklaskdfj sdf asdf jlaskdf skj sdkfjl asdf
1323 > skdjlkjsdfalsdkfjasdlfkj dlfksdfalksd fj
1324 >
1326 This is a followup
1327 ''')
1329 def innerTestQuoting(self, expect):
1330 nodeid = self.doNewIssue()
1332 messages = self.db.issue.get(nodeid, 'messages')
1334 self._handle_mail('''Content-Type: text/plain;
1335 charset="iso-8859-1"
1336 From: richard <richard@test.test>
1337 To: issue_tracker@your.tracker.email.domain.example
1338 Message-Id: <followup_dummy_id>
1339 In-Reply-To: <dummy_test_message_id>
1340 Subject: Re: [issue1] Testing...
1342 Blah blah wrote:
1343 > Blah bklaskdfj sdf asdf jlaskdf skj sdkfjl asdf
1344 > skdjlkjsdfalsdkfjasdlfkj dlfksdfalksd fj
1345 >
1347 This is a followup
1348 ''')
1349 # figure the new message id
1350 newmessages = self.db.issue.get(nodeid, 'messages')
1351 for msg in messages:
1352 newmessages.remove(msg)
1353 messageid = newmessages[0]
1355 self.compareMessages(self.db.msg.get(messageid, 'content'), expect)
1357 def testUserLookup(self):
1358 i = self.db.user.create(username='user1', address='user1@foo.com')
1359 self.assertEqual(uidFromAddress(self.db, ('', 'user1@foo.com'), 0), i)
1360 self.assertEqual(uidFromAddress(self.db, ('', 'USER1@foo.com'), 0), i)
1361 i = self.db.user.create(username='user2', address='USER2@foo.com')
1362 self.assertEqual(uidFromAddress(self.db, ('', 'USER2@foo.com'), 0), i)
1363 self.assertEqual(uidFromAddress(self.db, ('', 'user2@foo.com'), 0), i)
1365 def testUserAlternateLookup(self):
1366 i = self.db.user.create(username='user1', address='user1@foo.com',
1367 alternate_addresses='user1@bar.com')
1368 self.assertEqual(uidFromAddress(self.db, ('', 'user1@bar.com'), 0), i)
1369 self.assertEqual(uidFromAddress(self.db, ('', 'USER1@bar.com'), 0), i)
1371 def testUserCreate(self):
1372 i = uidFromAddress(self.db, ('', 'user@foo.com'), 1)
1373 self.assertNotEqual(uidFromAddress(self.db, ('', 'user@bar.com'), 1), i)
1375 def testRFC2822(self):
1376 ascii_header = "[issue243] This is a \"test\" - with 'quotation' marks"
1377 unicode_header = '[issue244] \xd0\xb0\xd0\xbd\xd0\xb4\xd1\x80\xd0\xb5\xd0\xb9'
1378 unicode_encoded = '=?utf-8?q?[issue244]_=D0=B0=D0=BD=D0=B4=D1=80=D0=B5=D0=B9?='
1379 self.assertEqual(rfc2822.encode_header(ascii_header), ascii_header)
1380 self.assertEqual(rfc2822.encode_header(unicode_header), unicode_encoded)
1382 def testRegistrationConfirmation(self):
1383 otk = "Aj4euk4LZSAdwePohj90SME5SpopLETL"
1384 self.db.getOTKManager().set(otk, username='johannes')
1385 self._handle_mail('''Content-Type: text/plain;
1386 charset="iso-8859-1"
1387 From: Chef <chef@bork.bork.bork>
1388 To: issue_tracker@your.tracker.email.domain.example
1389 Cc: richard@test.test
1390 Message-Id: <dummy_test_message_id>
1391 Subject: Re: Complete your registration to Roundup issue tracker
1392 -- key %s
1394 This is a test confirmation of registration.
1395 ''' % otk)
1396 self.db.user.lookup('johannes')
1398 def testFollowupOnNonIssue(self):
1399 self.db.keyword.create(name='Foo')
1400 self._handle_mail('''Content-Type: text/plain;
1401 charset="iso-8859-1"
1402 From: richard <richard@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: [keyword1] Testing... [name=Bar]
1408 ''')
1409 self.assertEqual(self.db.keyword.get('1', 'name'), 'Bar')
1411 def testResentFrom(self):
1412 nodeid = self._handle_mail('''Content-Type: text/plain;
1413 charset="iso-8859-1"
1414 From: Chef <chef@bork.bork.bork>
1415 Resent-From: mary <mary@test.test>
1416 To: issue_tracker@your.tracker.email.domain.example
1417 Cc: richard@test.test
1418 Message-Id: <dummy_test_message_id>
1419 Subject: [issue] Testing...
1421 This is a test submission of a new issue.
1422 ''')
1423 assert not os.path.exists(SENDMAILDEBUG)
1424 l = self.db.issue.get(nodeid, 'nosy')
1425 l.sort()
1426 self.assertEqual(l, [self.richard_id, self.mary_id])
1427 return nodeid
1429 def testDejaVu(self):
1430 self.assertRaises(IgnoreLoop, self._handle_mail,
1431 '''Content-Type: text/plain;
1432 charset="iso-8859-1"
1433 From: Chef <chef@bork.bork.bork>
1434 X-Roundup-Loop: hello
1435 To: issue_tracker@your.tracker.email.domain.example
1436 Cc: richard@test.test
1437 Message-Id: <dummy_test_message_id>
1438 Subject: Re: [issue] Testing...
1440 Hi, I've been mis-configured to loop messages back to myself.
1441 ''')
1443 def testItsBulkStupid(self):
1444 self.assertRaises(IgnoreBulk, self._handle_mail,
1445 '''Content-Type: text/plain;
1446 charset="iso-8859-1"
1447 From: Chef <chef@bork.bork.bork>
1448 Precedence: bulk
1449 To: issue_tracker@your.tracker.email.domain.example
1450 Cc: richard@test.test
1451 Message-Id: <dummy_test_message_id>
1452 Subject: Re: [issue] Testing...
1454 Hi, I'm on holidays, and this is a dumb auto-responder.
1455 ''')
1457 def testAutoReplyEmailsAreIgnored(self):
1458 self.assertRaises(IgnoreBulk, self._handle_mail,
1459 '''Content-Type: text/plain;
1460 charset="iso-8859-1"
1461 From: Chef <chef@bork.bork.bork>
1462 To: issue_tracker@your.tracker.email.domain.example
1463 Cc: richard@test.test
1464 Message-Id: <dummy_test_message_id>
1465 Subject: Re: [issue] Out of office AutoReply: Back next week
1467 Hi, I am back in the office next week
1468 ''')
1470 def testNoSubject(self):
1471 self.assertRaises(MailUsageError, self._handle_mail,
1472 '''Content-Type: text/plain;
1473 charset="iso-8859-1"
1474 From: Chef <chef@bork.bork.bork>
1475 To: issue_tracker@your.tracker.email.domain.example
1476 Cc: richard@test.test
1477 Reply-To: chef@bork.bork.bork
1478 Message-Id: <dummy_test_message_id>
1480 ''')
1482 #
1483 # TEST FOR INVALID DESIGNATOR HANDLING
1484 #
1485 def testInvalidDesignator(self):
1486 self.assertRaises(MailUsageError, self._handle_mail,
1487 '''Content-Type: text/plain;
1488 charset="iso-8859-1"
1489 From: Chef <chef@bork.bork.bork>
1490 To: issue_tracker@your.tracker.email.domain.example
1491 Subject: [frobulated] testing
1492 Cc: richard@test.test
1493 Reply-To: chef@bork.bork.bork
1494 Message-Id: <dummy_test_message_id>
1496 ''')
1497 self.assertRaises(MailUsageError, self._handle_mail,
1498 '''Content-Type: text/plain;
1499 charset="iso-8859-1"
1500 From: Chef <chef@bork.bork.bork>
1501 To: issue_tracker@your.tracker.email.domain.example
1502 Subject: [issue12345] testing
1503 Cc: richard@test.test
1504 Reply-To: chef@bork.bork.bork
1505 Message-Id: <dummy_test_message_id>
1507 ''')
1509 def testInvalidClassLoose(self):
1510 self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'loose'
1511 nodeid = self._handle_mail('''Content-Type: text/plain;
1512 charset="iso-8859-1"
1513 From: Chef <chef@bork.bork.bork>
1514 To: issue_tracker@your.tracker.email.domain.example
1515 Subject: [frobulated] testing
1516 Cc: richard@test.test
1517 Reply-To: chef@bork.bork.bork
1518 Message-Id: <dummy_test_message_id>
1520 ''')
1521 assert not os.path.exists(SENDMAILDEBUG)
1522 self.assertEqual(self.db.issue.get(nodeid, 'title'),
1523 '[frobulated] testing')
1525 def testInvalidClassLooseReply(self):
1526 self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'loose'
1527 nodeid = self._handle_mail('''Content-Type: text/plain;
1528 charset="iso-8859-1"
1529 From: Chef <chef@bork.bork.bork>
1530 To: issue_tracker@your.tracker.email.domain.example
1531 Subject: Re: [frobulated] testing
1532 Cc: richard@test.test
1533 Reply-To: chef@bork.bork.bork
1534 Message-Id: <dummy_test_message_id>
1536 ''')
1537 assert not os.path.exists(SENDMAILDEBUG)
1538 self.assertEqual(self.db.issue.get(nodeid, 'title'),
1539 '[frobulated] testing')
1541 def testInvalidClassLoose(self):
1542 self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'loose'
1543 nodeid = self._handle_mail('''Content-Type: text/plain;
1544 charset="iso-8859-1"
1545 From: Chef <chef@bork.bork.bork>
1546 To: issue_tracker@your.tracker.email.domain.example
1547 Subject: [issue1234] testing
1548 Cc: richard@test.test
1549 Reply-To: chef@bork.bork.bork
1550 Message-Id: <dummy_test_message_id>
1552 ''')
1553 assert not os.path.exists(SENDMAILDEBUG)
1554 self.assertEqual(self.db.issue.get(nodeid, 'title'),
1555 '[issue1234] testing')
1557 def testClassLooseOK(self):
1558 self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'loose'
1559 self.db.keyword.create(name='Foo')
1560 nodeid = self._handle_mail('''Content-Type: text/plain;
1561 charset="iso-8859-1"
1562 From: Chef <chef@bork.bork.bork>
1563 To: issue_tracker@your.tracker.email.domain.example
1564 Subject: [keyword1] Testing... [name=Bar]
1565 Cc: richard@test.test
1566 Reply-To: chef@bork.bork.bork
1567 Message-Id: <dummy_test_message_id>
1569 ''')
1570 assert not os.path.exists(SENDMAILDEBUG)
1571 self.assertEqual(self.db.keyword.get('1', 'name'), 'Bar')
1573 def testClassStrictInvalid(self):
1574 self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'strict'
1575 self.instance.config.MAILGW_DEFAULT_CLASS = ''
1577 message = '''Content-Type: text/plain;
1578 charset="iso-8859-1"
1579 From: Chef <chef@bork.bork.bork>
1580 To: issue_tracker@your.tracker.email.domain.example
1581 Subject: Testing...
1582 Cc: richard@test.test
1583 Reply-To: chef@bork.bork.bork
1584 Message-Id: <dummy_test_message_id>
1586 '''
1587 self.assertRaises(MailUsageError, self._handle_mail, message)
1589 def testClassStrictValid(self):
1590 self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'strict'
1591 self.instance.config.MAILGW_DEFAULT_CLASS = ''
1593 nodeid = self._handle_mail('''Content-Type: text/plain;
1594 charset="iso-8859-1"
1595 From: Chef <chef@bork.bork.bork>
1596 To: issue_tracker@your.tracker.email.domain.example
1597 Subject: [issue] Testing...
1598 Cc: richard@test.test
1599 Reply-To: chef@bork.bork.bork
1600 Message-Id: <dummy_test_message_id>
1602 ''')
1604 assert not os.path.exists(SENDMAILDEBUG)
1605 self.assertEqual(self.db.issue.get(nodeid, 'title'), 'Testing...')
1607 #
1608 # TEST FOR INVALID COMMANDS HANDLING
1609 #
1610 def testInvalidCommands(self):
1611 self.assertRaises(MailUsageError, self._handle_mail,
1612 '''Content-Type: text/plain;
1613 charset="iso-8859-1"
1614 From: Chef <chef@bork.bork.bork>
1615 To: issue_tracker@your.tracker.email.domain.example
1616 Subject: testing [frobulated]
1617 Cc: richard@test.test
1618 Reply-To: chef@bork.bork.bork
1619 Message-Id: <dummy_test_message_id>
1621 ''')
1623 def testInvalidCommandPassthrough(self):
1624 self.instance.config.MAILGW_SUBJECT_SUFFIX_PARSING = 'none'
1625 nodeid = self._handle_mail('''Content-Type: text/plain;
1626 charset="iso-8859-1"
1627 From: Chef <chef@bork.bork.bork>
1628 To: issue_tracker@your.tracker.email.domain.example
1629 Subject: testing [frobulated]
1630 Cc: richard@test.test
1631 Reply-To: chef@bork.bork.bork
1632 Message-Id: <dummy_test_message_id>
1634 ''')
1635 assert not os.path.exists(SENDMAILDEBUG)
1636 self.assertEqual(self.db.issue.get(nodeid, 'title'),
1637 'testing [frobulated]')
1639 def testInvalidCommandPassthroughLoose(self):
1640 self.instance.config.MAILGW_SUBJECT_SUFFIX_PARSING = 'loose'
1641 nodeid = self._handle_mail('''Content-Type: text/plain;
1642 charset="iso-8859-1"
1643 From: Chef <chef@bork.bork.bork>
1644 To: issue_tracker@your.tracker.email.domain.example
1645 Subject: testing [frobulated]
1646 Cc: richard@test.test
1647 Reply-To: chef@bork.bork.bork
1648 Message-Id: <dummy_test_message_id>
1650 ''')
1651 assert not os.path.exists(SENDMAILDEBUG)
1652 self.assertEqual(self.db.issue.get(nodeid, 'title'),
1653 'testing [frobulated]')
1655 def testInvalidCommandPassthroughLooseOK(self):
1656 self.instance.config.MAILGW_SUBJECT_SUFFIX_PARSING = 'loose'
1657 nodeid = self._handle_mail('''Content-Type: text/plain;
1658 charset="iso-8859-1"
1659 From: Chef <chef@bork.bork.bork>
1660 To: issue_tracker@your.tracker.email.domain.example
1661 Subject: testing [assignedto=mary]
1662 Cc: richard@test.test
1663 Reply-To: chef@bork.bork.bork
1664 Message-Id: <dummy_test_message_id>
1666 ''')
1667 assert not os.path.exists(SENDMAILDEBUG)
1668 self.assertEqual(self.db.issue.get(nodeid, 'title'), 'testing')
1669 self.assertEqual(self.db.issue.get(nodeid, 'assignedto'), self.mary_id)
1671 def testCommandDelimiters(self):
1672 self.instance.config.MAILGW_SUBJECT_SUFFIX_DELIMITERS = '{}'
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: testing {assignedto=mary}
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'), 'testing')
1685 self.assertEqual(self.db.issue.get(nodeid, 'assignedto'), self.mary_id)
1687 def testPrefixDelimiters(self):
1688 self.instance.config.MAILGW_SUBJECT_SUFFIX_DELIMITERS = '{}'
1689 self.db.keyword.create(name='Foo')
1690 self._handle_mail('''Content-Type: text/plain;
1691 charset="iso-8859-1"
1692 From: richard <richard@test.test>
1693 To: issue_tracker@your.tracker.email.domain.example
1694 Message-Id: <followup_dummy_id>
1695 In-Reply-To: <dummy_test_message_id>
1696 Subject: {keyword1} Testing... {name=Bar}
1698 ''')
1699 assert not os.path.exists(SENDMAILDEBUG)
1700 self.assertEqual(self.db.keyword.get('1', 'name'), 'Bar')
1702 def testCommandDelimitersIgnore(self):
1703 self.instance.config.MAILGW_SUBJECT_SUFFIX_DELIMITERS = '{}'
1704 nodeid = self._handle_mail('''Content-Type: text/plain;
1705 charset="iso-8859-1"
1706 From: Chef <chef@bork.bork.bork>
1707 To: issue_tracker@your.tracker.email.domain.example
1708 Subject: testing [assignedto=mary]
1709 Cc: richard@test.test
1710 Reply-To: chef@bork.bork.bork
1711 Message-Id: <dummy_test_message_id>
1713 ''')
1714 assert not os.path.exists(SENDMAILDEBUG)
1715 self.assertEqual(self.db.issue.get(nodeid, 'title'),
1716 'testing [assignedto=mary]')
1717 self.assertEqual(self.db.issue.get(nodeid, 'assignedto'), None)
1719 def testReplytoMatch(self):
1720 self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'loose'
1721 nodeid = self.doNewIssue()
1722 nodeid2 = 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 Message-Id: <dummy_test_message_id2>
1727 In-Reply-To: <dummy_test_message_id>
1728 Subject: Testing...
1730 Followup message.
1731 ''')
1733 nodeid3 = self._handle_mail('''Content-Type: text/plain;
1734 charset="iso-8859-1"
1735 From: Chef <chef@bork.bork.bork>
1736 To: issue_tracker@your.tracker.email.domain.example
1737 Message-Id: <dummy_test_message_id3>
1738 In-Reply-To: <dummy_test_message_id2>
1739 Subject: Testing...
1741 Yet another message in the same thread/issue.
1742 ''')
1744 self.assertEqual(nodeid, nodeid2)
1745 self.assertEqual(nodeid, nodeid3)
1747 def testHelpSubject(self):
1748 message = '''Content-Type: text/plain;
1749 charset="iso-8859-1"
1750 From: Chef <chef@bork.bork.bork>
1751 To: issue_tracker@your.tracker.email.domain.example
1752 Message-Id: <dummy_test_message_id2>
1753 In-Reply-To: <dummy_test_message_id>
1754 Subject: hElp
1757 '''
1758 self.assertRaises(MailUsageHelp, self._handle_mail, message)
1760 def testMaillistSubject(self):
1761 self.instance.config.MAILGW_SUBJECT_SUFFIX_DELIMITERS = '[]'
1762 self.db.keyword.create(name='Foo')
1763 self._handle_mail('''Content-Type: text/plain;
1764 charset="iso-8859-1"
1765 From: Chef <chef@bork.bork.bork>
1766 To: issue_tracker@your.tracker.email.domain.example
1767 Subject: [mailinglist-name] [keyword1] Testing.. [name=Bar]
1768 Cc: richard@test.test
1769 Reply-To: chef@bork.bork.bork
1770 Message-Id: <dummy_test_message_id>
1772 ''')
1774 assert not os.path.exists(SENDMAILDEBUG)
1775 self.assertEqual(self.db.keyword.get('1', 'name'), 'Bar')
1777 def testUnknownPrefixSubject(self):
1778 self.db.keyword.create(name='Foo')
1779 self._handle_mail('''Content-Type: text/plain;
1780 charset="iso-8859-1"
1781 From: Chef <chef@bork.bork.bork>
1782 To: issue_tracker@your.tracker.email.domain.example
1783 Subject: VeryStrangeRe: [keyword1] Testing.. [name=Bar]
1784 Cc: richard@test.test
1785 Reply-To: chef@bork.bork.bork
1786 Message-Id: <dummy_test_message_id>
1788 ''')
1790 assert not os.path.exists(SENDMAILDEBUG)
1791 self.assertEqual(self.db.keyword.get('1', 'name'), 'Bar')
1793 def testIssueidLast(self):
1794 nodeid1 = self.doNewIssue()
1795 nodeid2 = self._handle_mail('''Content-Type: text/plain;
1796 charset="iso-8859-1"
1797 From: mary <mary@test.test>
1798 To: issue_tracker@your.tracker.email.domain.example
1799 Message-Id: <followup_dummy_id>
1800 In-Reply-To: <dummy_test_message_id>
1801 Subject: New title [issue1]
1803 This is a second followup
1804 ''')
1806 assert nodeid1 == nodeid2
1807 self.assertEqual(self.db.issue.get(nodeid2, 'title'), "Testing...")
1810 def test_suite():
1811 suite = unittest.TestSuite()
1812 suite.addTest(unittest.makeSuite(MailgwTestCase))
1813 return suite
1815 if __name__ == '__main__':
1816 runner = unittest.TextTestRunner()
1817 unittest.main(testRunner=runner)
1819 # vim: set filetype=python sts=4 sw=4 et si :