Code

Add some new encoding tests to mailgw:
[roundup.git] / test / test_mailgw.py
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
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
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 :