Code

migrate from MimeWriter to email
[roundup.git] / test / test_mailgw.py
1 #
2 # Copyright (c) 2001 Richard Jones, richard@bofh.asn.au.
3 # This module is free software, and you may redistribute it and/or modify
4 # under the same terms as Python, so long as this copyright message and
5 # disclaimer are retained in their original form.
6 #
7 # This module is distributed in the hope that it will be useful,
8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
10 #
11 # $Id: test_mailgw.py,v 1.96 2008-08-19 01:40:59 richard Exp $
13 # TODO: test bcc
15 import unittest, tempfile, os, shutil, errno, imp, sys, difflib, rfc822, time
17 from cStringIO import StringIO
19 if not os.environ.has_key('SENDMAILDEBUG'):
20     os.environ['SENDMAILDEBUG'] = 'mail-test.log'
21 SENDMAILDEBUG = os.environ['SENDMAILDEBUG']
23 from roundup.mailgw import MailGW, Unauthorized, uidFromAddress, \
24     parseContent, IgnoreLoop, IgnoreBulk, MailUsageError, MailUsageHelp
25 from roundup import init, instance, password, rfc2822, __version__
27 import db_test_base
29 class Message(rfc822.Message):
30     """String-based Message class with equivalence test."""
31     def __init__(self, s):
32         rfc822.Message.__init__(self, StringIO(s.strip()))
34     def __eq__(self, other):
35         return (self.dict == other.dict and
36                 self.fp.read() == other.fp.read())
38 class DiffHelper:
39     def compareMessages(self, new, old):
40         """Compare messages for semantic equivalence."""
41         new, old = Message(new), Message(old)
43         # all Roundup-generated messages have "Precedence: bulk"
44         old['Precedence'] = 'bulk'
46         # don't try to compare the date
47         del new['date'], old['date']
49         if not new == old:
50             res = []
52             for key in new.keys():
53                 if key.startswith('from '):
54                     # skip the unix from line
55                     continue
56                 if key.lower() == 'x-roundup-version':
57                     # version changes constantly, so handle it specially
58                     if new[key] != __version__:
59                         res.append('  %s: %r != %r' % (key, __version__,
60                             new[key]))
61                 elif new.get(key, '') != old.get(key, ''):
62                     res.append('  %s: %r != %r' % (key, old.get(key, ''),
63                         new.get(key, '')))
65             body_diff = self.compareStrings(new.fp.read(), old.fp.read())
66             if body_diff:
67                 res.append('')
68                 res.extend(body_diff)
70             if res:
71                 res.insert(0, 'Generated message not correct (diff follows):')
72                 raise AssertionError, '\n'.join(res)
74     def compareStrings(self, s2, s1):
75         '''Note the reversal of s2 and s1 - difflib.SequenceMatcher wants
76            the first to be the "original" but in the calls in this file,
77            the second arg is the original. Ho hum.
78         '''
79         l1 = s1.strip().split('\n')
80         l2 = s2.strip().split('\n')
81         if l1 == l2:
82             return
83         s = difflib.SequenceMatcher(None, l1, l2)
84         res = []
85         for value, s1s, s1e, s2s, s2e in s.get_opcodes():
86             if value == 'equal':
87                 for i in range(s1s, s1e):
88                     res.append('  %s'%l1[i])
89             elif value == 'delete':
90                 for i in range(s1s, s1e):
91                     res.append('- %s'%l1[i])
92             elif value == 'insert':
93                 for i in range(s2s, s2e):
94                     res.append('+ %s'%l2[i])
95             elif value == 'replace':
96                 for i, j in zip(range(s1s, s1e), range(s2s, s2e)):
97                     res.append('- %s'%l1[i])
98                     res.append('+ %s'%l2[j])
100         return res
102 class MailgwTestCase(unittest.TestCase, DiffHelper):
103     count = 0
104     schema = 'classic'
105     def setUp(self):
106         MailgwTestCase.count = MailgwTestCase.count + 1
107         self.dirname = '_test_mailgw_%s'%self.count
108         # set up and open a tracker
109         self.instance = db_test_base.setupTracker(self.dirname)
111         # and open the database
112         self.db = self.instance.open('admin')
113         self.chef_id = self.db.user.create(username='Chef',
114             address='chef@bork.bork.bork', realname='Bork, Chef', roles='User')
115         self.richard_id = self.db.user.create(username='richard',
116             address='richard@test.test', roles='User')
117         self.mary_id = self.db.user.create(username='mary', address='mary@test.test',
118             roles='User', realname='Contrary, Mary')
119         self.john_id = self.db.user.create(username='john', address='john@test.test',
120             alternate_addresses='jondoe@test.test\njohn.doe@test.test', roles='User',
121             realname='John Doe')
123     def tearDown(self):
124         if os.path.exists(SENDMAILDEBUG):
125             os.remove(SENDMAILDEBUG)
126         self.db.close()
127         try:
128             shutil.rmtree(self.dirname)
129         except OSError, error:
130             if error.errno not in (errno.ENOENT, errno.ESRCH): raise
132     def _handle_mail(self, message):
133         handler = self.instance.MailGW(self.instance, self.db)
134         handler.trapExceptions = 0
135         ret = handler.main(StringIO(message))
136         # handler can close the db on us and open a new one
137         self.db = handler.db
138         return ret
140     def _get_mail(self):
141         f = open(SENDMAILDEBUG)
142         try:
143             return f.read()
144         finally:
145             f.close()
147     def testEmptyMessage(self):
148         nodeid = self._handle_mail('''Content-Type: text/plain;
149   charset="iso-8859-1"
150 From: Chef <chef@bork.bork.bork>
151 To: issue_tracker@your.tracker.email.domain.example
152 Cc: richard@test.test
153 Reply-To: chef@bork.bork.bork
154 Message-Id: <dummy_test_message_id>
155 Subject: [issue] Testing...
157 ''')
158         assert not os.path.exists(SENDMAILDEBUG)
159         self.assertEqual(self.db.issue.get(nodeid, 'title'), 'Testing...')
161     def doNewIssue(self):
162         nodeid = self._handle_mail('''Content-Type: text/plain;
163   charset="iso-8859-1"
164 From: Chef <chef@bork.bork.bork>
165 To: issue_tracker@your.tracker.email.domain.example
166 Cc: richard@test.test
167 Message-Id: <dummy_test_message_id>
168 Subject: [issue] Testing...
170 This is a test submission of a new issue.
171 ''')
172         assert not os.path.exists(SENDMAILDEBUG)
173         l = self.db.issue.get(nodeid, 'nosy')
174         l.sort()
175         self.assertEqual(l, [self.chef_id, self.richard_id])
176         return nodeid
178     def testNewIssue(self):
179         self.doNewIssue()
181     def testNewIssueNosy(self):
182         self.instance.config.ADD_AUTHOR_TO_NOSY = 'yes'
183         nodeid = self._handle_mail('''Content-Type: text/plain;
184   charset="iso-8859-1"
185 From: Chef <chef@bork.bork.bork>
186 To: issue_tracker@your.tracker.email.domain.example
187 Cc: richard@test.test
188 Message-Id: <dummy_test_message_id>
189 Subject: [issue] Testing...
191 This is a test submission of a new issue.
192 ''')
193         assert not os.path.exists(SENDMAILDEBUG)
194         l = self.db.issue.get(nodeid, 'nosy')
195         l.sort()
196         self.assertEqual(l, [self.chef_id, self.richard_id])
198     def testAlternateAddress(self):
199         self._handle_mail('''Content-Type: text/plain;
200   charset="iso-8859-1"
201 From: John Doe <john.doe@test.test>
202 To: issue_tracker@your.tracker.email.domain.example
203 Message-Id: <dummy_test_message_id>
204 Subject: [issue] Testing...
206 This is a test submission of a new issue.
207 ''')
208         userlist = self.db.user.list()
209         assert not os.path.exists(SENDMAILDEBUG)
210         self.assertEqual(userlist, self.db.user.list(),
211             "user created when it shouldn't have been")
213     def testNewIssueNoClass(self):
214         self._handle_mail('''Content-Type: text/plain;
215   charset="iso-8859-1"
216 From: Chef <chef@bork.bork.bork>
217 To: issue_tracker@your.tracker.email.domain.example
218 Cc: richard@test.test
219 Message-Id: <dummy_test_message_id>
220 Subject: Testing...
222 This is a test submission of a new issue.
223 ''')
224         assert not os.path.exists(SENDMAILDEBUG)
226     def testNewIssueAuthMsg(self):
227         # TODO: fix the damn config - this is apalling
228         self.db.config.MESSAGES_TO_AUTHOR = 'yes'
229         self._handle_mail('''Content-Type: text/plain;
230   charset="iso-8859-1"
231 From: Chef <chef@bork.bork.bork>
232 To: issue_tracker@your.tracker.email.domain.example
233 Message-Id: <dummy_test_message_id>
234 Subject: [issue] Testing... [nosy=mary; assignedto=richard]
236 This is a test submission of a new issue.
237 ''')
238         self.compareMessages(self._get_mail(),
239 '''FROM: roundup-admin@your.tracker.email.domain.example
240 TO: chef@bork.bork.bork, mary@test.test, richard@test.test
241 Content-Type: text/plain; charset="utf-8"
242 Subject: [issue1] Testing...
243 To: chef@bork.bork.bork, mary@test.test, richard@test.test
244 From: "Bork, Chef" <issue_tracker@your.tracker.email.domain.example>
245 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
246 MIME-Version: 1.0
247 Message-Id: <dummy_test_message_id>
248 X-Roundup-Name: Roundup issue tracker
249 X-Roundup-Loop: hello
250 X-Roundup-Issue-Status: unread
251 Content-Transfer-Encoding: quoted-printable
254 New submission from Bork, Chef <chef@bork.bork.bork>:
256 This is a test submission of a new issue.
258 ----------
259 assignedto: richard
260 messages: 1
261 nosy: Chef, mary, richard
262 status: unread
263 title: Testing...
265 _______________________________________________________________________
266 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
267 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
268 _______________________________________________________________________
269 ''')
271     def testNewIssueNoAuthorInfo(self):
272         self.db.config.MAIL_ADD_AUTHORINFO = 'no'
273         self._handle_mail('''Content-Type: text/plain;
274   charset="iso-8859-1"
275 From: Chef <chef@bork.bork.bork>
276 To: issue_tracker@your.tracker.email.domain.example
277 Message-Id: <dummy_test_message_id>
278 Subject: [issue] Testing... [nosy=mary; assignedto=richard]
280 This is a test submission of a new issue.
281 ''')
282         self.compareMessages(self._get_mail(),
283 '''FROM: roundup-admin@your.tracker.email.domain.example
284 TO: chef@bork.bork.bork, mary@test.test, richard@test.test
285 Content-Type: text/plain; charset="utf-8"
286 Subject: [issue1] Testing...
287 To: mary@test.test, richard@test.test
288 From: "Bork, Chef" <issue_tracker@your.tracker.email.domain.example>
289 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
290 MIME-Version: 1.0
291 Message-Id: <dummy_test_message_id>
292 X-Roundup-Name: Roundup issue tracker
293 X-Roundup-Loop: hello
294 X-Roundup-Issue-Status: unread
295 Content-Transfer-Encoding: quoted-printable
297 This is a test submission of a new issue.
299 ----------
300 assignedto: richard
301 messages: 1
302 nosy: Chef, mary, richard
303 status: unread
304 title: Testing...
306 _______________________________________________________________________
307 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
308 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
309 _______________________________________________________________________
310 ''')
312     def testNewIssueNoAuthorEmail(self):
313         self.db.config.MAIL_ADD_AUTHOREMAIL = 'no'
314         self._handle_mail('''Content-Type: text/plain;
315   charset="iso-8859-1"
316 From: Chef <chef@bork.bork.bork>
317 To: issue_tracker@your.tracker.email.domain.example
318 Message-Id: <dummy_test_message_id>
319 Subject: [issue] Testing... [nosy=mary; assignedto=richard]
321 This is a test submission of a new issue.
322 ''')
323         self.compareMessages(self._get_mail(),
324 '''FROM: roundup-admin@your.tracker.email.domain.example
325 TO: chef@bork.bork.bork, mary@test.test, richard@test.test
326 Content-Type: text/plain; charset="utf-8"
327 Subject: [issue1] Testing...
328 To: mary@test.test, richard@test.test
329 From: "Bork, Chef" <issue_tracker@your.tracker.email.domain.example>
330 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
331 MIME-Version: 1.0
332 Message-Id: <dummy_test_message_id>
333 X-Roundup-Name: Roundup issue tracker
334 X-Roundup-Loop: hello
335 X-Roundup-Issue-Status: unread
336 Content-Transfer-Encoding: quoted-printable
338 New submission from Bork, Chef:
340 This is a test submission of a new issue.
342 ----------
343 assignedto: richard
344 messages: 1
345 nosy: Chef, mary, richard
346 status: unread
347 title: Testing...
349 _______________________________________________________________________
350 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
351 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
352 _______________________________________________________________________
353 ''')
355     multipart_msg = '''From: mary <mary@test.test>
356 To: issue_tracker@your.tracker.email.domain.example
357 Message-Id: <followup_dummy_id>
358 In-Reply-To: <dummy_test_message_id>
359 Subject: [issue1] Testing...
360 Content-Type: multipart/mixed; boundary="bxyzzy"
361 Content-Disposition: inline
364 --bxyzzy
365 Content-Type: multipart/alternative; boundary="bCsyhTFzCvuiizWE"
366 Content-Disposition: inline
368 --bCsyhTFzCvuiizWE
369 Content-Type: text/plain; charset=us-ascii
370 Content-Disposition: inline
372 test attachment first text/plain
374 --bCsyhTFzCvuiizWE
375 Content-Type: application/octet-stream
376 Content-Disposition: attachment; filename="first.dvi"
377 Content-Transfer-Encoding: base64
379 SnVzdCBhIHRlc3QgAQo=
381 --bCsyhTFzCvuiizWE
382 Content-Type: text/plain; charset=us-ascii
383 Content-Disposition: inline
385 test attachment second text/plain
387 --bCsyhTFzCvuiizWE
388 Content-Type: text/html
389 Content-Disposition: inline
391 <html>
392 to be ignored.
393 </html>
395 --bCsyhTFzCvuiizWE--
397 --bxyzzy
398 Content-Type: multipart/alternative; boundary="bCsyhTFzCvuiizWF"
399 Content-Disposition: inline
401 --bCsyhTFzCvuiizWF
402 Content-Type: text/plain; charset=us-ascii
403 Content-Disposition: inline
405 test attachment third text/plain
407 --bCsyhTFzCvuiizWF
408 Content-Type: application/octet-stream
409 Content-Disposition: attachment; filename="second.dvi"
410 Content-Transfer-Encoding: base64
412 SnVzdCBhIHRlc3QK
414 --bCsyhTFzCvuiizWF--
416 --bxyzzy--
417 '''
419     def testMultipartKeepAlternatives(self):
420         self.doNewIssue()
421         self._handle_mail(self.multipart_msg)
422         messages = self.db.issue.get('1', 'messages')
423         messages.sort()
424         msg = self.db.msg.getnode (messages[-1])
425         assert(len(msg.files) == 5)
426         names = {0 : 'first.dvi', 4 : 'second.dvi'}
427         content = {3 : 'test attachment third text/plain\n',
428                    4 : 'Just a test\n'}
429         for n, id in enumerate (msg.files):
430             f = self.db.file.getnode (id)
431             self.assertEqual(f.name, names.get (n, 'unnamed'))
432             if n in content :
433                 self.assertEqual(f.content, content [n])
434         self.assertEqual(msg.content, 'test attachment second text/plain')
436     def testMultipartDropAlternatives(self):
437         self.doNewIssue()
438         self.db.config.MAILGW_IGNORE_ALTERNATIVES = True
439         self._handle_mail(self.multipart_msg)
440         messages = self.db.issue.get('1', 'messages')
441         messages.sort()
442         msg = self.db.msg.getnode (messages[-1])
443         assert(len(msg.files) == 2)
444         names = {1 : 'second.dvi'}
445         content = {0 : 'test attachment third text/plain\n',
446                    1 : 'Just a test\n'}
447         for n, id in enumerate (msg.files):
448             f = self.db.file.getnode (id)
449             self.assertEqual(f.name, names.get (n, 'unnamed'))
450             if n in content :
451                 self.assertEqual(f.content, content [n])
452         self.assertEqual(msg.content, 'test attachment second text/plain')
454     def testSimpleFollowup(self):
455         self.doNewIssue()
456         self._handle_mail('''Content-Type: text/plain;
457   charset="iso-8859-1"
458 From: mary <mary@test.test>
459 To: issue_tracker@your.tracker.email.domain.example
460 Message-Id: <followup_dummy_id>
461 In-Reply-To: <dummy_test_message_id>
462 Subject: [issue1] Testing...
464 This is a second followup
465 ''')
466         self.compareMessages(self._get_mail(),
467 '''FROM: roundup-admin@your.tracker.email.domain.example
468 TO: chef@bork.bork.bork, richard@test.test
469 Content-Type: text/plain; charset="utf-8"
470 Subject: [issue1] Testing...
471 To: chef@bork.bork.bork, richard@test.test
472 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
473 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
474 MIME-Version: 1.0
475 Message-Id: <followup_dummy_id>
476 In-Reply-To: <dummy_test_message_id>
477 X-Roundup-Name: Roundup issue tracker
478 X-Roundup-Loop: hello
479 X-Roundup-Issue-Status: chatting
480 Content-Transfer-Encoding: quoted-printable
483 Contrary, Mary <mary@test.test> added the comment:
485 This is a second followup
487 ----------
488 status: unread -> chatting
490 _______________________________________________________________________
491 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
492 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
493 _______________________________________________________________________
494 ''')
496     def testFollowup(self):
497         self.doNewIssue()
499         self._handle_mail('''Content-Type: text/plain;
500   charset="iso-8859-1"
501 From: richard <richard@test.test>
502 To: issue_tracker@your.tracker.email.domain.example
503 Message-Id: <followup_dummy_id>
504 In-Reply-To: <dummy_test_message_id>
505 Subject: [issue1] Testing... [assignedto=mary; nosy=+john]
507 This is a followup
508 ''')
509         l = self.db.issue.get('1', 'nosy')
510         l.sort()
511         self.assertEqual(l, [self.chef_id, self.richard_id, self.mary_id,
512             self.john_id])
514         self.compareMessages(self._get_mail(),
515 '''FROM: roundup-admin@your.tracker.email.domain.example
516 TO: chef@bork.bork.bork, john@test.test, mary@test.test
517 Content-Type: text/plain; charset="utf-8"
518 Subject: [issue1] Testing...
519 To: chef@bork.bork.bork, john@test.test, mary@test.test
520 From: richard <issue_tracker@your.tracker.email.domain.example>
521 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
522 MIME-Version: 1.0
523 Message-Id: <followup_dummy_id>
524 In-Reply-To: <dummy_test_message_id>
525 X-Roundup-Name: Roundup issue tracker
526 X-Roundup-Loop: hello
527 X-Roundup-Issue-Status: chatting
528 Content-Transfer-Encoding: quoted-printable
531 richard <richard@test.test> added the comment:
533 This is a followup
535 ----------
536 assignedto:  -> mary
537 nosy: +john, mary
538 status: unread -> chatting
540 _______________________________________________________________________
541 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
542 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
543 _______________________________________________________________________
544 ''')
546     def testPropertyChangeOnly(self):
547         self.doNewIssue()
548         oldvalues = self.db.getnode('issue', '1').copy()
549         oldvalues['assignedto'] = None
550         self.db.issue.set('1', assignedto=self.chef_id)
551         self.db.commit()
552         self.db.issue.nosymessage('1', None, oldvalues)
554         new_mail = ""
555         for line in self._get_mail().split("\n"):
556             if "Message-Id: " in line:
557                 continue
558             if "Date: " in line:
559                 continue
560             new_mail += line+"\n"
562         self.compareMessages(new_mail, """
563 FROM: roundup-admin@your.tracker.email.domain.example
564 TO: chef@bork.bork.bork, richard@test.test
565 Content-Type: text/plain; charset="utf-8"
566 Subject: [issue1] Testing...
567 To: chef@bork.bork.bork, richard@test.test
568 From: "Bork, Chef" <issue_tracker@your.tracker.email.domain.example>
569 X-Roundup-Name: Roundup issue tracker
570 X-Roundup-Loop: hello
571 X-Roundup-Issue-Status: unread
572 X-Roundup-Version: 1.3.3
573 MIME-Version: 1.0
574 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
575 Content-Transfer-Encoding: quoted-printable
578 Change by Bork, Chef <chef@bork.bork.bork>:
581 ----------
582 assignedto:  -> Chef
584 _______________________________________________________________________
585 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
586 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
587 _______________________________________________________________________
588 """)
591     #
592     # FOLLOWUP TITLE MATCH
593     #
594     def testFollowupTitleMatch(self):
595         self.doNewIssue()
596         self._handle_mail('''Content-Type: text/plain;
597   charset="iso-8859-1"
598 From: richard <richard@test.test>
599 To: issue_tracker@your.tracker.email.domain.example
600 Message-Id: <followup_dummy_id>
601 Subject: Re: Testing... [assignedto=mary; nosy=+john]
603 This is a followup
604 ''')
605         self.compareMessages(self._get_mail(),
606 '''FROM: roundup-admin@your.tracker.email.domain.example
607 TO: chef@bork.bork.bork, john@test.test, mary@test.test
608 Content-Type: text/plain; charset="utf-8"
609 Subject: [issue1] Testing...
610 To: chef@bork.bork.bork, john@test.test, mary@test.test
611 From: richard <issue_tracker@your.tracker.email.domain.example>
612 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
613 MIME-Version: 1.0
614 Message-Id: <followup_dummy_id>
615 In-Reply-To: <dummy_test_message_id>
616 X-Roundup-Name: Roundup issue tracker
617 X-Roundup-Loop: hello
618 X-Roundup-Issue-Status: chatting
619 Content-Transfer-Encoding: quoted-printable
622 richard <richard@test.test> added the comment:
624 This is a followup
626 ----------
627 assignedto:  -> mary
628 nosy: +john, mary
629 status: unread -> chatting
631 _______________________________________________________________________
632 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
633 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
634 _______________________________________________________________________
635 ''')
637     def testFollowupTitleMatchMultiRe(self):
638         nodeid1 = self.doNewIssue()
639         nodeid2 = self._handle_mail('''Content-Type: text/plain;
640   charset="iso-8859-1"
641 From: richard <richard@test.test>
642 To: issue_tracker@your.tracker.email.domain.example
643 Message-Id: <followup_dummy_id>
644 Subject: Re: Testing... [assignedto=mary; nosy=+john]
646 This is a followup
647 ''')
649         nodeid3 = self._handle_mail('''Content-Type: text/plain;
650   charset="iso-8859-1"
651 From: richard <richard@test.test>
652 To: issue_tracker@your.tracker.email.domain.example
653 Message-Id: <followup2_dummy_id>
654 Subject: Ang: Re: Testing...
656 This is a followup
657 ''')
658         self.assertEqual(nodeid1, nodeid2)
659         self.assertEqual(nodeid1, nodeid3)
661     def testFollowupTitleMatchNever(self):
662         nodeid = self.doNewIssue()
663         self.db.config.MAILGW_SUBJECT_CONTENT_MATCH = 'never'
664         self.assertNotEqual(self._handle_mail('''Content-Type: text/plain;
665   charset="iso-8859-1"
666 From: richard <richard@test.test>
667 To: issue_tracker@your.tracker.email.domain.example
668 Message-Id: <followup_dummy_id>
669 Subject: Re: Testing...
671 This is a followup
672 '''), nodeid)
674     def testFollowupTitleMatchNeverInterval(self):
675         nodeid = self.doNewIssue()
676         # force failure of the interval
677         time.sleep(2)
678         self.db.config.MAILGW_SUBJECT_CONTENT_MATCH = 'creation 00:00:01'
679         self.assertNotEqual(self._handle_mail('''Content-Type: text/plain;
680   charset="iso-8859-1"
681 From: richard <richard@test.test>
682 To: issue_tracker@your.tracker.email.domain.example
683 Message-Id: <followup_dummy_id>
684 Subject: Re: Testing...
686 This is a followup
687 '''), nodeid)
690     def testFollowupTitleMatchInterval(self):
691         nodeid = self.doNewIssue()
692         self.db.config.MAILGW_SUBJECT_CONTENT_MATCH = 'creation +1d'
693         self.assertEqual(self._handle_mail('''Content-Type: text/plain;
694   charset="iso-8859-1"
695 From: richard <richard@test.test>
696 To: issue_tracker@your.tracker.email.domain.example
697 Message-Id: <followup_dummy_id>
698 Subject: Re: Testing...
700 This is a followup
701 '''), nodeid)
704     def testFollowupNosyAuthor(self):
705         self.doNewIssue()
706         self.db.config.ADD_AUTHOR_TO_NOSY = 'yes'
707         self._handle_mail('''Content-Type: text/plain;
708   charset="iso-8859-1"
709 From: john@test.test
710 To: issue_tracker@your.tracker.email.domain.example
711 Message-Id: <followup_dummy_id>
712 In-Reply-To: <dummy_test_message_id>
713 Subject: [issue1] Testing...
715 This is a followup
716 ''')
718         self.compareMessages(self._get_mail(),
719 '''FROM: roundup-admin@your.tracker.email.domain.example
720 TO: chef@bork.bork.bork, richard@test.test
721 Content-Type: text/plain; charset="utf-8"
722 Subject: [issue1] Testing...
723 To: chef@bork.bork.bork, richard@test.test
724 From: John Doe <issue_tracker@your.tracker.email.domain.example>
725 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
726 MIME-Version: 1.0
727 Message-Id: <followup_dummy_id>
728 In-Reply-To: <dummy_test_message_id>
729 X-Roundup-Name: Roundup issue tracker
730 X-Roundup-Loop: hello
731 X-Roundup-Issue-Status: chatting
732 Content-Transfer-Encoding: quoted-printable
735 John Doe <john@test.test> added the comment:
737 This is a followup
739 ----------
740 nosy: +john
741 status: unread -> chatting
743 _______________________________________________________________________
744 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
745 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
746 _______________________________________________________________________
748 ''')
750     def testFollowupNosyRecipients(self):
751         self.doNewIssue()
752         self.db.config.ADD_RECIPIENTS_TO_NOSY = 'yes'
753         self._handle_mail('''Content-Type: text/plain;
754   charset="iso-8859-1"
755 From: richard@test.test
756 To: issue_tracker@your.tracker.email.domain.example
757 Cc: john@test.test
758 Message-Id: <followup_dummy_id>
759 In-Reply-To: <dummy_test_message_id>
760 Subject: [issue1] Testing...
762 This is a followup
763 ''')
764         self.compareMessages(self._get_mail(),
765 '''FROM: roundup-admin@your.tracker.email.domain.example
766 TO: chef@bork.bork.bork
767 Content-Type: text/plain; charset="utf-8"
768 Subject: [issue1] Testing...
769 To: chef@bork.bork.bork
770 From: richard <issue_tracker@your.tracker.email.domain.example>
771 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
772 MIME-Version: 1.0
773 Message-Id: <followup_dummy_id>
774 In-Reply-To: <dummy_test_message_id>
775 X-Roundup-Name: Roundup issue tracker
776 X-Roundup-Loop: hello
777 X-Roundup-Issue-Status: chatting
778 Content-Transfer-Encoding: quoted-printable
781 richard <richard@test.test> added the comment:
783 This is a followup
785 ----------
786 nosy: +john
787 status: unread -> chatting
789 _______________________________________________________________________
790 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
791 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
792 _______________________________________________________________________
794 ''')
796     def testFollowupNosyAuthorAndCopy(self):
797         self.doNewIssue()
798         self.db.config.ADD_AUTHOR_TO_NOSY = 'yes'
799         self.db.config.MESSAGES_TO_AUTHOR = 'yes'
800         self._handle_mail('''Content-Type: text/plain;
801   charset="iso-8859-1"
802 From: john@test.test
803 To: issue_tracker@your.tracker.email.domain.example
804 Message-Id: <followup_dummy_id>
805 In-Reply-To: <dummy_test_message_id>
806 Subject: [issue1] Testing...
808 This is a followup
809 ''')
810         self.compareMessages(self._get_mail(),
811 '''FROM: roundup-admin@your.tracker.email.domain.example
812 TO: chef@bork.bork.bork, john@test.test, richard@test.test
813 Content-Type: text/plain; charset="utf-8"
814 Subject: [issue1] Testing...
815 To: chef@bork.bork.bork, john@test.test, richard@test.test
816 From: John Doe <issue_tracker@your.tracker.email.domain.example>
817 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
818 MIME-Version: 1.0
819 Message-Id: <followup_dummy_id>
820 In-Reply-To: <dummy_test_message_id>
821 X-Roundup-Name: Roundup issue tracker
822 X-Roundup-Loop: hello
823 X-Roundup-Issue-Status: chatting
824 Content-Transfer-Encoding: quoted-printable
827 John Doe <john@test.test> added the comment:
829 This is a followup
831 ----------
832 nosy: +john
833 status: unread -> chatting
835 _______________________________________________________________________
836 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
837 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
838 _______________________________________________________________________
840 ''')
842     def testFollowupNoNosyAuthor(self):
843         self.doNewIssue()
844         self.instance.config.ADD_AUTHOR_TO_NOSY = 'no'
845         self._handle_mail('''Content-Type: text/plain;
846   charset="iso-8859-1"
847 From: john@test.test
848 To: issue_tracker@your.tracker.email.domain.example
849 Message-Id: <followup_dummy_id>
850 In-Reply-To: <dummy_test_message_id>
851 Subject: [issue1] Testing...
853 This is a followup
854 ''')
855         self.compareMessages(self._get_mail(),
856 '''FROM: roundup-admin@your.tracker.email.domain.example
857 TO: chef@bork.bork.bork, richard@test.test
858 Content-Type: text/plain; charset="utf-8"
859 Subject: [issue1] Testing...
860 To: chef@bork.bork.bork, richard@test.test
861 From: John Doe <issue_tracker@your.tracker.email.domain.example>
862 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
863 MIME-Version: 1.0
864 Message-Id: <followup_dummy_id>
865 In-Reply-To: <dummy_test_message_id>
866 X-Roundup-Name: Roundup issue tracker
867 X-Roundup-Loop: hello
868 X-Roundup-Issue-Status: chatting
869 Content-Transfer-Encoding: quoted-printable
872 John Doe <john@test.test> added the comment:
874 This is a followup
876 ----------
877 status: unread -> chatting
879 _______________________________________________________________________
880 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
881 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
882 _______________________________________________________________________
884 ''')
886     def testFollowupNoNosyRecipients(self):
887         self.doNewIssue()
888         self.instance.config.ADD_RECIPIENTS_TO_NOSY = 'no'
889         self._handle_mail('''Content-Type: text/plain;
890   charset="iso-8859-1"
891 From: richard@test.test
892 To: issue_tracker@your.tracker.email.domain.example
893 Cc: john@test.test
894 Message-Id: <followup_dummy_id>
895 In-Reply-To: <dummy_test_message_id>
896 Subject: [issue1] Testing...
898 This is a followup
899 ''')
900         self.compareMessages(self._get_mail(),
901 '''FROM: roundup-admin@your.tracker.email.domain.example
902 TO: chef@bork.bork.bork
903 Content-Type: text/plain; charset="utf-8"
904 Subject: [issue1] Testing...
905 To: chef@bork.bork.bork
906 From: richard <issue_tracker@your.tracker.email.domain.example>
907 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
908 MIME-Version: 1.0
909 Message-Id: <followup_dummy_id>
910 In-Reply-To: <dummy_test_message_id>
911 X-Roundup-Name: Roundup issue tracker
912 X-Roundup-Loop: hello
913 X-Roundup-Issue-Status: chatting
914 Content-Transfer-Encoding: quoted-printable
917 richard <richard@test.test> added the comment:
919 This is a followup
921 ----------
922 status: unread -> chatting
924 _______________________________________________________________________
925 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
926 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
927 _______________________________________________________________________
929 ''')
931     def testFollowupEmptyMessage(self):
932         self.doNewIssue()
934         self._handle_mail('''Content-Type: text/plain;
935   charset="iso-8859-1"
936 From: richard <richard@test.test>
937 To: issue_tracker@your.tracker.email.domain.example
938 Message-Id: <followup_dummy_id>
939 In-Reply-To: <dummy_test_message_id>
940 Subject: [issue1] Testing... [assignedto=mary; nosy=+john]
942 ''')
943         l = self.db.issue.get('1', 'nosy')
944         l.sort()
945         self.assertEqual(l, [self.chef_id, self.richard_id, self.mary_id,
946             self.john_id])
948         # should be no file created (ie. no message)
949         assert not os.path.exists(SENDMAILDEBUG)
951     def testFollowupEmptyMessageNoSubject(self):
952         self.doNewIssue()
954         self._handle_mail('''Content-Type: text/plain;
955   charset="iso-8859-1"
956 From: richard <richard@test.test>
957 To: issue_tracker@your.tracker.email.domain.example
958 Message-Id: <followup_dummy_id>
959 In-Reply-To: <dummy_test_message_id>
960 Subject: [issue1] [assignedto=mary; nosy=+john]
962 ''')
963         l = self.db.issue.get('1', 'nosy')
964         l.sort()
965         self.assertEqual(l, [self.chef_id, self.richard_id, self.mary_id,
966             self.john_id])
968         # should be no file created (ie. no message)
969         assert not os.path.exists(SENDMAILDEBUG)
971     def testNosyRemove(self):
972         self.doNewIssue()
974         self._handle_mail('''Content-Type: text/plain;
975   charset="iso-8859-1"
976 From: richard <richard@test.test>
977 To: issue_tracker@your.tracker.email.domain.example
978 Message-Id: <followup_dummy_id>
979 In-Reply-To: <dummy_test_message_id>
980 Subject: [issue1] Testing... [nosy=-richard]
982 ''')
983         l = self.db.issue.get('1', 'nosy')
984         l.sort()
985         self.assertEqual(l, [self.chef_id])
987         # NO NOSY MESSAGE SHOULD BE SENT!
988         assert not os.path.exists(SENDMAILDEBUG)
990     def testNewUserAuthor(self):
991         # first without the permission
992         # heh... just ignore the API for a second ;)
993         self.db.security.role['anonymous'].permissions=[]
994         anonid = self.db.user.lookup('anonymous')
995         self.db.user.set(anonid, roles='Anonymous')
997         l = self.db.user.list()
998         l.sort()
999         message = '''Content-Type: text/plain;
1000   charset="iso-8859-1"
1001 From: fubar <fubar@bork.bork.bork>
1002 To: issue_tracker@your.tracker.email.domain.example
1003 Message-Id: <dummy_test_message_id>
1004 Subject: [issue] Testing...
1006 This is a test submission of a new issue.
1007 '''
1008         try:
1009             self._handle_mail(message)
1010         except Unauthorized, value:
1011             body_diff = self.compareMessages(str(value), """
1012 You are not a registered user.
1014 Unknown address: fubar@bork.bork.bork
1015 """)
1017             assert not body_diff, body_diff
1019         else:
1020             raise AssertionError, "Unathorized not raised when handling mail"
1022         # Add Web Access role to anonymous, and try again to make sure
1023         # we get a "please register at:" message this time.
1024         p = [
1025             self.db.security.getPermission('Create', 'user'),
1026             self.db.security.getPermission('Web Access', None),
1027         ]
1029         self.db.security.role['anonymous'].permissions=p
1031         try:
1032             self._handle_mail(message)
1033         except Unauthorized, value:
1034             body_diff = self.compareMessages(str(value), """
1035 You are not a registered user. Please register at:
1037 http://tracker.example/cgi-bin/roundup.cgi/bugs/user?template=register
1039 ...before sending mail to the tracker.
1041 Unknown address: fubar@bork.bork.bork
1042 """)
1044             assert not body_diff, body_diff
1046         else:
1047             raise AssertionError, "Unathorized not raised when handling mail"
1049         # Make sure list of users is the same as before.
1050         m = self.db.user.list()
1051         m.sort()
1052         self.assertEqual(l, m)
1054         # now with the permission
1055         p = [
1056             self.db.security.getPermission('Create', 'user'),
1057             self.db.security.getPermission('Email Access', None),
1058         ]
1059         self.db.security.role['anonymous'].permissions=p
1060         self._handle_mail(message)
1061         m = self.db.user.list()
1062         m.sort()
1063         self.assertNotEqual(l, m)
1065     def testEnc01(self):
1066         self.doNewIssue()
1067         self._handle_mail('''Content-Type: text/plain;
1068   charset="iso-8859-1"
1069 From: mary <mary@test.test>
1070 To: issue_tracker@your.tracker.email.domain.example
1071 Message-Id: <followup_dummy_id>
1072 In-Reply-To: <dummy_test_message_id>
1073 Subject: [issue1] Testing...
1074 Content-Type: text/plain;
1075         charset="iso-8859-1"
1076 Content-Transfer-Encoding: quoted-printable
1078 A message with encoding (encoded oe =F6)
1080 ''')
1081         self.compareMessages(self._get_mail(),
1082 '''FROM: roundup-admin@your.tracker.email.domain.example
1083 TO: chef@bork.bork.bork, richard@test.test
1084 Content-Type: text/plain; charset="utf-8"
1085 Subject: [issue1] Testing...
1086 To: chef@bork.bork.bork, richard@test.test
1087 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
1088 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1089 MIME-Version: 1.0
1090 Message-Id: <followup_dummy_id>
1091 In-Reply-To: <dummy_test_message_id>
1092 X-Roundup-Name: Roundup issue tracker
1093 X-Roundup-Loop: hello
1094 X-Roundup-Issue-Status: chatting
1095 Content-Transfer-Encoding: quoted-printable
1098 Contrary, Mary <mary@test.test> added the comment:
1100 A message with encoding (encoded oe =C3=B6)
1102 ----------
1103 status: unread -> chatting
1105 _______________________________________________________________________
1106 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1107 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1108 _______________________________________________________________________
1109 ''')
1112     def testMultipartEnc01(self):
1113         self.doNewIssue()
1114         self._handle_mail('''Content-Type: text/plain;
1115   charset="iso-8859-1"
1116 From: mary <mary@test.test>
1117 To: issue_tracker@your.tracker.email.domain.example
1118 Message-Id: <followup_dummy_id>
1119 In-Reply-To: <dummy_test_message_id>
1120 Subject: [issue1] Testing...
1121 Content-Type: multipart/mixed;
1122         boundary="----_=_NextPart_000_01"
1124 This message is in MIME format. Since your mail reader does not understand
1125 this format, some or all of this message may not be legible.
1127 ------_=_NextPart_000_01
1128 Content-Type: text/plain;
1129         charset="iso-8859-1"
1130 Content-Transfer-Encoding: quoted-printable
1132 A message with first part encoded (encoded oe =F6)
1134 ''')
1135         self.compareMessages(self._get_mail(),
1136 '''FROM: roundup-admin@your.tracker.email.domain.example
1137 TO: chef@bork.bork.bork, richard@test.test
1138 Content-Type: text/plain; charset="utf-8"
1139 Subject: [issue1] Testing...
1140 To: chef@bork.bork.bork, richard@test.test
1141 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
1142 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1143 MIME-Version: 1.0
1144 Message-Id: <followup_dummy_id>
1145 In-Reply-To: <dummy_test_message_id>
1146 X-Roundup-Name: Roundup issue tracker
1147 X-Roundup-Loop: hello
1148 X-Roundup-Issue-Status: chatting
1149 Content-Transfer-Encoding: quoted-printable
1152 Contrary, Mary <mary@test.test> added the comment:
1154 A message with first part encoded (encoded oe =C3=B6)
1156 ----------
1157 status: unread -> chatting
1159 _______________________________________________________________________
1160 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1161 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1162 _______________________________________________________________________
1163 ''')
1165     def testContentDisposition(self):
1166         self.doNewIssue()
1167         self._handle_mail('''Content-Type: text/plain;
1168   charset="iso-8859-1"
1169 From: mary <mary@test.test>
1170 To: issue_tracker@your.tracker.email.domain.example
1171 Message-Id: <followup_dummy_id>
1172 In-Reply-To: <dummy_test_message_id>
1173 Subject: [issue1] Testing...
1174 Content-Type: multipart/mixed; boundary="bCsyhTFzCvuiizWE"
1175 Content-Disposition: inline
1178 --bCsyhTFzCvuiizWE
1179 Content-Type: text/plain; charset=us-ascii
1180 Content-Disposition: inline
1182 test attachment binary
1184 --bCsyhTFzCvuiizWE
1185 Content-Type: application/octet-stream
1186 Content-Disposition: attachment; filename="main.dvi"
1187 Content-Transfer-Encoding: base64
1189 SnVzdCBhIHRlc3QgAQo=
1191 --bCsyhTFzCvuiizWE--
1192 ''')
1193         messages = self.db.issue.get('1', 'messages')
1194         messages.sort()
1195         file = self.db.file.getnode (self.db.msg.get(messages[-1], 'files')[0])
1196         self.assertEqual(file.name, 'main.dvi')
1197         self.assertEqual(file.content, 'Just a test \001\n')
1199     def testFollowupStupidQuoting(self):
1200         self.doNewIssue()
1202         self._handle_mail('''Content-Type: text/plain;
1203   charset="iso-8859-1"
1204 From: richard <richard@test.test>
1205 To: issue_tracker@your.tracker.email.domain.example
1206 Message-Id: <followup_dummy_id>
1207 In-Reply-To: <dummy_test_message_id>
1208 Subject: Re: "[issue1] Testing... "
1210 This is a followup
1211 ''')
1212         self.compareMessages(self._get_mail(),
1213 '''FROM: roundup-admin@your.tracker.email.domain.example
1214 TO: chef@bork.bork.bork
1215 Content-Type: text/plain; charset="utf-8"
1216 Subject: [issue1] Testing...
1217 To: chef@bork.bork.bork
1218 From: richard <issue_tracker@your.tracker.email.domain.example>
1219 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1220 MIME-Version: 1.0
1221 Message-Id: <followup_dummy_id>
1222 In-Reply-To: <dummy_test_message_id>
1223 X-Roundup-Name: Roundup issue tracker
1224 X-Roundup-Loop: hello
1225 X-Roundup-Issue-Status: chatting
1226 Content-Transfer-Encoding: quoted-printable
1229 richard <richard@test.test> added the comment:
1231 This is a followup
1233 ----------
1234 status: unread -> chatting
1236 _______________________________________________________________________
1237 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1238 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1239 _______________________________________________________________________
1240 ''')
1242     def testEmailQuoting(self):
1243         self.instance.config.EMAIL_KEEP_QUOTED_TEXT = 'no'
1244         self.innerTestQuoting('''This is a followup
1245 ''')
1247     def testEmailQuotingRemove(self):
1248         self.instance.config.EMAIL_KEEP_QUOTED_TEXT = 'yes'
1249         self.innerTestQuoting('''Blah blah wrote:
1250 > Blah bklaskdfj sdf asdf jlaskdf skj sdkfjl asdf
1251 >  skdjlkjsdfalsdkfjasdlfkj dlfksdfalksd fj
1254 This is a followup
1255 ''')
1257     def innerTestQuoting(self, expect):
1258         nodeid = self.doNewIssue()
1260         messages = self.db.issue.get(nodeid, 'messages')
1262         self._handle_mail('''Content-Type: text/plain;
1263   charset="iso-8859-1"
1264 From: richard <richard@test.test>
1265 To: issue_tracker@your.tracker.email.domain.example
1266 Message-Id: <followup_dummy_id>
1267 In-Reply-To: <dummy_test_message_id>
1268 Subject: Re: [issue1] Testing...
1270 Blah blah wrote:
1271 > Blah bklaskdfj sdf asdf jlaskdf skj sdkfjl asdf
1272 >  skdjlkjsdfalsdkfjasdlfkj dlfksdfalksd fj
1275 This is a followup
1276 ''')
1277         # figure the new message id
1278         newmessages = self.db.issue.get(nodeid, 'messages')
1279         for msg in messages:
1280             newmessages.remove(msg)
1281         messageid = newmessages[0]
1283         self.compareMessages(self.db.msg.get(messageid, 'content'), expect)
1285     def testUserLookup(self):
1286         i = self.db.user.create(username='user1', address='user1@foo.com')
1287         self.assertEqual(uidFromAddress(self.db, ('', 'user1@foo.com'), 0), i)
1288         self.assertEqual(uidFromAddress(self.db, ('', 'USER1@foo.com'), 0), i)
1289         i = self.db.user.create(username='user2', address='USER2@foo.com')
1290         self.assertEqual(uidFromAddress(self.db, ('', 'USER2@foo.com'), 0), i)
1291         self.assertEqual(uidFromAddress(self.db, ('', 'user2@foo.com'), 0), i)
1293     def testUserAlternateLookup(self):
1294         i = self.db.user.create(username='user1', address='user1@foo.com',
1295                                 alternate_addresses='user1@bar.com')
1296         self.assertEqual(uidFromAddress(self.db, ('', 'user1@bar.com'), 0), i)
1297         self.assertEqual(uidFromAddress(self.db, ('', 'USER1@bar.com'), 0), i)
1299     def testUserCreate(self):
1300         i = uidFromAddress(self.db, ('', 'user@foo.com'), 1)
1301         self.assertNotEqual(uidFromAddress(self.db, ('', 'user@bar.com'), 1), i)
1303     def testRFC2822(self):
1304         ascii_header = "[issue243] This is a \"test\" - with 'quotation' marks"
1305         unicode_header = '[issue244] \xd0\xb0\xd0\xbd\xd0\xb4\xd1\x80\xd0\xb5\xd0\xb9'
1306         unicode_encoded = '=?utf-8?q?[issue244]_=D0=B0=D0=BD=D0=B4=D1=80=D0=B5=D0=B9?='
1307         self.assertEqual(rfc2822.encode_header(ascii_header), ascii_header)
1308         self.assertEqual(rfc2822.encode_header(unicode_header), unicode_encoded)
1310     def testRegistrationConfirmation(self):
1311         otk = "Aj4euk4LZSAdwePohj90SME5SpopLETL"
1312         self.db.getOTKManager().set(otk, username='johannes')
1313         self._handle_mail('''Content-Type: text/plain;
1314   charset="iso-8859-1"
1315 From: Chef <chef@bork.bork.bork>
1316 To: issue_tracker@your.tracker.email.domain.example
1317 Cc: richard@test.test
1318 Message-Id: <dummy_test_message_id>
1319 Subject: Re: Complete your registration to Roundup issue tracker
1320  -- key %s
1322 This is a test confirmation of registration.
1323 ''' % otk)
1324         self.db.user.lookup('johannes')
1326     def testFollowupOnNonIssue(self):
1327         self.db.keyword.create(name='Foo')
1328         self._handle_mail('''Content-Type: text/plain;
1329   charset="iso-8859-1"
1330 From: richard <richard@test.test>
1331 To: issue_tracker@your.tracker.email.domain.example
1332 Message-Id: <followup_dummy_id>
1333 In-Reply-To: <dummy_test_message_id>
1334 Subject: [keyword1] Testing... [name=Bar]
1336 ''')
1337         self.assertEqual(self.db.keyword.get('1', 'name'), 'Bar')
1339     def testResentFrom(self):
1340         nodeid = self._handle_mail('''Content-Type: text/plain;
1341   charset="iso-8859-1"
1342 From: Chef <chef@bork.bork.bork>
1343 Resent-From: mary <mary@test.test>
1344 To: issue_tracker@your.tracker.email.domain.example
1345 Cc: richard@test.test
1346 Message-Id: <dummy_test_message_id>
1347 Subject: [issue] Testing...
1349 This is a test submission of a new issue.
1350 ''')
1351         assert not os.path.exists(SENDMAILDEBUG)
1352         l = self.db.issue.get(nodeid, 'nosy')
1353         l.sort()
1354         self.assertEqual(l, [self.richard_id, self.mary_id])
1355         return nodeid
1357     def testDejaVu(self):
1358         self.assertRaises(IgnoreLoop, self._handle_mail,
1359             '''Content-Type: text/plain;
1360   charset="iso-8859-1"
1361 From: Chef <chef@bork.bork.bork>
1362 X-Roundup-Loop: hello
1363 To: issue_tracker@your.tracker.email.domain.example
1364 Cc: richard@test.test
1365 Message-Id: <dummy_test_message_id>
1366 Subject: Re: [issue] Testing...
1368 Hi, I've been mis-configured to loop messages back to myself.
1369 ''')
1371     def testItsBulkStupid(self):
1372         self.assertRaises(IgnoreBulk, self._handle_mail,
1373             '''Content-Type: text/plain;
1374   charset="iso-8859-1"
1375 From: Chef <chef@bork.bork.bork>
1376 Precedence: bulk
1377 To: issue_tracker@your.tracker.email.domain.example
1378 Cc: richard@test.test
1379 Message-Id: <dummy_test_message_id>
1380 Subject: Re: [issue] Testing...
1382 Hi, I'm on holidays, and this is a dumb auto-responder.
1383 ''')
1385     def testAutoReplyEmailsAreIgnored(self):
1386         self.assertRaises(IgnoreBulk, self._handle_mail,
1387             '''Content-Type: text/plain;
1388   charset="iso-8859-1"
1389 From: Chef <chef@bork.bork.bork>
1390 To: issue_tracker@your.tracker.email.domain.example
1391 Cc: richard@test.test
1392 Message-Id: <dummy_test_message_id>
1393 Subject: Re: [issue] Out of office AutoReply: Back next week
1395 Hi, I am back in the office next week
1396 ''')
1398     def testNoSubject(self):
1399         self.assertRaises(MailUsageError, self._handle_mail,
1400             '''Content-Type: text/plain;
1401   charset="iso-8859-1"
1402 From: Chef <chef@bork.bork.bork>
1403 To: issue_tracker@your.tracker.email.domain.example
1404 Cc: richard@test.test
1405 Reply-To: chef@bork.bork.bork
1406 Message-Id: <dummy_test_message_id>
1408 ''')
1410     #
1411     # TEST FOR INVALID DESIGNATOR HANDLING
1412     #
1413     def testInvalidDesignator(self):
1414         self.assertRaises(MailUsageError, self._handle_mail,
1415             '''Content-Type: text/plain;
1416   charset="iso-8859-1"
1417 From: Chef <chef@bork.bork.bork>
1418 To: issue_tracker@your.tracker.email.domain.example
1419 Subject: [frobulated] testing
1420 Cc: richard@test.test
1421 Reply-To: chef@bork.bork.bork
1422 Message-Id: <dummy_test_message_id>
1424 ''')
1425         self.assertRaises(MailUsageError, self._handle_mail,
1426             '''Content-Type: text/plain;
1427   charset="iso-8859-1"
1428 From: Chef <chef@bork.bork.bork>
1429 To: issue_tracker@your.tracker.email.domain.example
1430 Subject: [issue12345] testing
1431 Cc: richard@test.test
1432 Reply-To: chef@bork.bork.bork
1433 Message-Id: <dummy_test_message_id>
1435 ''')
1437     def testInvalidClassLoose(self):
1438         self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'loose'
1439         nodeid = self._handle_mail('''Content-Type: text/plain;
1440   charset="iso-8859-1"
1441 From: Chef <chef@bork.bork.bork>
1442 To: issue_tracker@your.tracker.email.domain.example
1443 Subject: [frobulated] testing
1444 Cc: richard@test.test
1445 Reply-To: chef@bork.bork.bork
1446 Message-Id: <dummy_test_message_id>
1448 ''')
1449         assert not os.path.exists(SENDMAILDEBUG)
1450         self.assertEqual(self.db.issue.get(nodeid, 'title'),
1451             '[frobulated] testing')
1453     def testInvalidClassLooseReply(self):
1454         self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'loose'
1455         nodeid = self._handle_mail('''Content-Type: text/plain;
1456   charset="iso-8859-1"
1457 From: Chef <chef@bork.bork.bork>
1458 To: issue_tracker@your.tracker.email.domain.example
1459 Subject: Re: [frobulated] testing
1460 Cc: richard@test.test
1461 Reply-To: chef@bork.bork.bork
1462 Message-Id: <dummy_test_message_id>
1464 ''')
1465         assert not os.path.exists(SENDMAILDEBUG)
1466         self.assertEqual(self.db.issue.get(nodeid, 'title'),
1467             '[frobulated] testing')
1469     def testInvalidClassLoose(self):
1470         self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'loose'
1471         nodeid = self._handle_mail('''Content-Type: text/plain;
1472   charset="iso-8859-1"
1473 From: Chef <chef@bork.bork.bork>
1474 To: issue_tracker@your.tracker.email.domain.example
1475 Subject: [issue1234] testing
1476 Cc: richard@test.test
1477 Reply-To: chef@bork.bork.bork
1478 Message-Id: <dummy_test_message_id>
1480 ''')
1481         assert not os.path.exists(SENDMAILDEBUG)
1482         self.assertEqual(self.db.issue.get(nodeid, 'title'),
1483             '[issue1234] testing')
1485     def testClassLooseOK(self):
1486         self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'loose'
1487         self.db.keyword.create(name='Foo')
1488         nodeid = self._handle_mail('''Content-Type: text/plain;
1489   charset="iso-8859-1"
1490 From: Chef <chef@bork.bork.bork>
1491 To: issue_tracker@your.tracker.email.domain.example
1492 Subject: [keyword1] Testing... [name=Bar]
1493 Cc: richard@test.test
1494 Reply-To: chef@bork.bork.bork
1495 Message-Id: <dummy_test_message_id>
1497 ''')
1498         assert not os.path.exists(SENDMAILDEBUG)
1499         self.assertEqual(self.db.keyword.get('1', 'name'), 'Bar')
1501     def testClassStrictInvalid(self):
1502         self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'strict'
1503         self.instance.config.MAILGW_DEFAULT_CLASS = ''
1505         message = '''Content-Type: text/plain;
1506   charset="iso-8859-1"
1507 From: Chef <chef@bork.bork.bork>
1508 To: issue_tracker@your.tracker.email.domain.example
1509 Subject: Testing...
1510 Cc: richard@test.test
1511 Reply-To: chef@bork.bork.bork
1512 Message-Id: <dummy_test_message_id>
1514 '''
1515         self.assertRaises(MailUsageError, self._handle_mail, message)
1517     def testClassStrictValid(self):
1518         self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'strict'
1519         self.instance.config.MAILGW_DEFAULT_CLASS = ''
1521         nodeid = self._handle_mail('''Content-Type: text/plain;
1522   charset="iso-8859-1"
1523 From: Chef <chef@bork.bork.bork>
1524 To: issue_tracker@your.tracker.email.domain.example
1525 Subject: [issue] Testing...
1526 Cc: richard@test.test
1527 Reply-To: chef@bork.bork.bork
1528 Message-Id: <dummy_test_message_id>
1530 ''')
1532         assert not os.path.exists(SENDMAILDEBUG)
1533         self.assertEqual(self.db.issue.get(nodeid, 'title'), 'Testing...')
1535     #
1536     # TEST FOR INVALID COMMANDS HANDLING
1537     #
1538     def testInvalidCommands(self):
1539         self.assertRaises(MailUsageError, self._handle_mail,
1540             '''Content-Type: text/plain;
1541   charset="iso-8859-1"
1542 From: Chef <chef@bork.bork.bork>
1543 To: issue_tracker@your.tracker.email.domain.example
1544 Subject: testing [frobulated]
1545 Cc: richard@test.test
1546 Reply-To: chef@bork.bork.bork
1547 Message-Id: <dummy_test_message_id>
1549 ''')
1551     def testInvalidCommandPassthrough(self):
1552         self.instance.config.MAILGW_SUBJECT_SUFFIX_PARSING = 'none'
1553         nodeid = self._handle_mail('''Content-Type: text/plain;
1554   charset="iso-8859-1"
1555 From: Chef <chef@bork.bork.bork>
1556 To: issue_tracker@your.tracker.email.domain.example
1557 Subject: testing [frobulated]
1558 Cc: richard@test.test
1559 Reply-To: chef@bork.bork.bork
1560 Message-Id: <dummy_test_message_id>
1562 ''')
1563         assert not os.path.exists(SENDMAILDEBUG)
1564         self.assertEqual(self.db.issue.get(nodeid, 'title'),
1565             'testing [frobulated]')
1567     def testInvalidCommandPassthroughLoose(self):
1568         self.instance.config.MAILGW_SUBJECT_SUFFIX_PARSING = 'loose'
1569         nodeid = self._handle_mail('''Content-Type: text/plain;
1570   charset="iso-8859-1"
1571 From: Chef <chef@bork.bork.bork>
1572 To: issue_tracker@your.tracker.email.domain.example
1573 Subject: testing [frobulated]
1574 Cc: richard@test.test
1575 Reply-To: chef@bork.bork.bork
1576 Message-Id: <dummy_test_message_id>
1578 ''')
1579         assert not os.path.exists(SENDMAILDEBUG)
1580         self.assertEqual(self.db.issue.get(nodeid, 'title'),
1581             'testing [frobulated]')
1583     def testInvalidCommandPassthroughLooseOK(self):
1584         self.instance.config.MAILGW_SUBJECT_SUFFIX_PARSING = 'loose'
1585         nodeid = self._handle_mail('''Content-Type: text/plain;
1586   charset="iso-8859-1"
1587 From: Chef <chef@bork.bork.bork>
1588 To: issue_tracker@your.tracker.email.domain.example
1589 Subject: testing [assignedto=mary]
1590 Cc: richard@test.test
1591 Reply-To: chef@bork.bork.bork
1592 Message-Id: <dummy_test_message_id>
1594 ''')
1595         assert not os.path.exists(SENDMAILDEBUG)
1596         self.assertEqual(self.db.issue.get(nodeid, 'title'), 'testing')
1597         self.assertEqual(self.db.issue.get(nodeid, 'assignedto'), self.mary_id)
1599     def testCommandDelimiters(self):
1600         self.instance.config.MAILGW_SUBJECT_SUFFIX_DELIMITERS = '{}'
1601         nodeid = self._handle_mail('''Content-Type: text/plain;
1602   charset="iso-8859-1"
1603 From: Chef <chef@bork.bork.bork>
1604 To: issue_tracker@your.tracker.email.domain.example
1605 Subject: testing {assignedto=mary}
1606 Cc: richard@test.test
1607 Reply-To: chef@bork.bork.bork
1608 Message-Id: <dummy_test_message_id>
1610 ''')
1611         assert not os.path.exists(SENDMAILDEBUG)
1612         self.assertEqual(self.db.issue.get(nodeid, 'title'), 'testing')
1613         self.assertEqual(self.db.issue.get(nodeid, 'assignedto'), self.mary_id)
1615     def testPrefixDelimiters(self):
1616         self.instance.config.MAILGW_SUBJECT_SUFFIX_DELIMITERS = '{}'
1617         self.db.keyword.create(name='Foo')
1618         self._handle_mail('''Content-Type: text/plain;
1619   charset="iso-8859-1"
1620 From: richard <richard@test.test>
1621 To: issue_tracker@your.tracker.email.domain.example
1622 Message-Id: <followup_dummy_id>
1623 In-Reply-To: <dummy_test_message_id>
1624 Subject: {keyword1} Testing... {name=Bar}
1626 ''')
1627         assert not os.path.exists(SENDMAILDEBUG)
1628         self.assertEqual(self.db.keyword.get('1', 'name'), 'Bar')
1630     def testCommandDelimitersIgnore(self):
1631         self.instance.config.MAILGW_SUBJECT_SUFFIX_DELIMITERS = '{}'
1632         nodeid = self._handle_mail('''Content-Type: text/plain;
1633   charset="iso-8859-1"
1634 From: Chef <chef@bork.bork.bork>
1635 To: issue_tracker@your.tracker.email.domain.example
1636 Subject: testing [assignedto=mary]
1637 Cc: richard@test.test
1638 Reply-To: chef@bork.bork.bork
1639 Message-Id: <dummy_test_message_id>
1641 ''')
1642         assert not os.path.exists(SENDMAILDEBUG)
1643         self.assertEqual(self.db.issue.get(nodeid, 'title'),
1644             'testing [assignedto=mary]')
1645         self.assertEqual(self.db.issue.get(nodeid, 'assignedto'), None)
1647     def testReplytoMatch(self):
1648         self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'loose'
1649         nodeid = self.doNewIssue()
1650         nodeid2 = self._handle_mail('''Content-Type: text/plain;
1651   charset="iso-8859-1"
1652 From: Chef <chef@bork.bork.bork>
1653 To: issue_tracker@your.tracker.email.domain.example
1654 Message-Id: <dummy_test_message_id2>
1655 In-Reply-To: <dummy_test_message_id>
1656 Subject: Testing...
1658 Followup message.
1659 ''')
1661         nodeid3 = self._handle_mail('''Content-Type: text/plain;
1662   charset="iso-8859-1"
1663 From: Chef <chef@bork.bork.bork>
1664 To: issue_tracker@your.tracker.email.domain.example
1665 Message-Id: <dummy_test_message_id3>
1666 In-Reply-To: <dummy_test_message_id2>
1667 Subject: Testing...
1669 Yet another message in the same thread/issue.
1670 ''')
1672         self.assertEqual(nodeid, nodeid2)
1673         self.assertEqual(nodeid, nodeid3)
1675     def testHelpSubject(self):
1676         message = '''Content-Type: text/plain;
1677   charset="iso-8859-1"
1678 From: Chef <chef@bork.bork.bork>
1679 To: issue_tracker@your.tracker.email.domain.example
1680 Message-Id: <dummy_test_message_id2>
1681 In-Reply-To: <dummy_test_message_id>
1682 Subject: hElp
1685 '''
1686         self.assertRaises(MailUsageHelp, self._handle_mail, message)
1688     def testMaillistSubject(self):
1689         self.instance.config.MAILGW_SUBJECT_SUFFIX_DELIMITERS = '[]'
1690         self.db.keyword.create(name='Foo')
1691         self._handle_mail('''Content-Type: text/plain;
1692   charset="iso-8859-1"
1693 From: Chef <chef@bork.bork.bork>
1694 To: issue_tracker@your.tracker.email.domain.example
1695 Subject: [mailinglist-name] [keyword1] Testing.. [name=Bar]
1696 Cc: richard@test.test
1697 Reply-To: chef@bork.bork.bork
1698 Message-Id: <dummy_test_message_id>
1700 ''')
1702         assert not os.path.exists(SENDMAILDEBUG)
1703         self.assertEqual(self.db.keyword.get('1', 'name'), 'Bar')
1705     def testUnknownPrefixSubject(self):
1706         self.db.keyword.create(name='Foo')
1707         self._handle_mail('''Content-Type: text/plain;
1708   charset="iso-8859-1"
1709 From: Chef <chef@bork.bork.bork>
1710 To: issue_tracker@your.tracker.email.domain.example
1711 Subject: VeryStrangeRe: [keyword1] Testing.. [name=Bar]
1712 Cc: richard@test.test
1713 Reply-To: chef@bork.bork.bork
1714 Message-Id: <dummy_test_message_id>
1716 ''')
1718         assert not os.path.exists(SENDMAILDEBUG)
1719         self.assertEqual(self.db.keyword.get('1', 'name'), 'Bar')
1721     def testIssueidLast(self):
1722         nodeid1 = self.doNewIssue()
1723         nodeid2 = self._handle_mail('''Content-Type: text/plain;
1724   charset="iso-8859-1"
1725 From: mary <mary@test.test>
1726 To: issue_tracker@your.tracker.email.domain.example
1727 Message-Id: <followup_dummy_id>
1728 In-Reply-To: <dummy_test_message_id>
1729 Subject: New title [issue1]
1731 This is a second followup
1732 ''')
1734         assert nodeid1 == nodeid2
1735         self.assertEqual(self.db.issue.get(nodeid2, 'title'), "Testing...")
1738 def test_suite():
1739     suite = unittest.TestSuite()
1740     suite.addTest(unittest.makeSuite(MailgwTestCase))
1741     return suite
1743 if __name__ == '__main__':
1744     runner = unittest.TextTestRunner()
1745     unittest.main(testRunner=runner)
1747 # vim: set filetype=python sts=4 sw=4 et si :