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.64 2004-01-20 00:11:51 richard Exp $
13 import unittest, tempfile, os, shutil, errno, imp, sys, difflib, rfc822
15 from cStringIO import StringIO
17 if not os.environ.has_key('SENDMAILDEBUG'):
18 os.environ['SENDMAILDEBUG'] = 'mail-test.log'
19 SENDMAILDEBUG = os.environ['SENDMAILDEBUG']
21 from roundup.mailgw import MailGW, Unauthorized, uidFromAddress, \
22 parseContent, IgnoreLoop, IgnoreBulk
23 from roundup import init, instance, rfc2822, __version__
26 class Message(rfc822.Message):
27 """String-based Message class with equivalence test."""
28 def __init__(self, s):
29 rfc822.Message.__init__(self, StringIO(s.strip()))
31 def __eq__(self, other):
32 return (self.dict == other.dict and
33 self.fp.read() == other.fp.read())
35 class DiffHelper:
36 def compareMessages(self, new, old):
37 """Compare messages for semantic equivalence."""
38 new, old = Message(new), Message(old)
39 del new['date'], old['date']
41 if not new == old:
42 res = []
44 for key in new.keys():
45 if key.lower() == 'x-roundup-version':
46 # version changes constantly, so handle it specially
47 if new[key] != __version__:
48 res.append(' %s: %s != %s' % (key, __version__,
49 new[key]))
50 elif new[key] != old[key]:
51 res.append(' %s: %s != %s' % (key, old[key], new[key]))
53 body_diff = self.compareStrings(new.fp.read(), old.fp.read())
54 if body_diff:
55 res.append('')
56 res.extend(body_diff)
58 if res:
59 res.insert(0, 'Generated message not correct (diff follows):')
60 raise AssertionError, '\n'.join(res)
62 def compareStrings(self, s2, s1):
63 '''Note the reversal of s2 and s1 - difflib.SequenceMatcher wants
64 the first to be the "original" but in the calls in this file,
65 the second arg is the original. Ho hum.
66 '''
67 l1 = s1.strip().split('\n')
68 l2 = s2.strip().split('\n')
69 if l1 == l2:
70 return
71 s = difflib.SequenceMatcher(None, l1, l2)
72 res = []
73 for value, s1s, s1e, s2s, s2e in s.get_opcodes():
74 if value == 'equal':
75 for i in range(s1s, s1e):
76 res.append(' %s'%l1[i])
77 elif value == 'delete':
78 for i in range(s1s, s1e):
79 res.append('- %s'%l1[i])
80 elif value == 'insert':
81 for i in range(s2s, s2e):
82 res.append('+ %s'%l2[i])
83 elif value == 'replace':
84 for i, j in zip(range(s1s, s1e), range(s2s, s2e)):
85 res.append('- %s'%l1[i])
86 res.append('+ %s'%l2[j])
88 return res
90 class MailgwTestCase(unittest.TestCase, DiffHelper):
91 count = 0
92 schema = 'classic'
93 def setUp(self):
94 MailgwTestCase.count = MailgwTestCase.count + 1
95 self.dirname = '_test_mailgw_%s'%self.count
96 try:
97 shutil.rmtree(self.dirname)
98 except OSError, error:
99 if error.errno not in (errno.ENOENT, errno.ESRCH): raise
100 # create the instance
101 init.install(self.dirname, 'templates/classic')
102 init.write_select_db(self.dirname, 'anydbm')
103 init.initialise(self.dirname, 'sekrit')
105 # check we can load the package
106 self.instance = instance.open(self.dirname)
108 # and open the database
109 self.db = self.instance.open('admin')
110 self.chef_id = self.db.user.create(username='Chef',
111 address='chef@bork.bork.bork', realname='Bork, Chef', roles='User')
112 self.richard_id = self.db.user.create(username='richard',
113 address='richard@test', roles='User')
114 self.mary_id = self.db.user.create(username='mary', address='mary@test',
115 roles='User', realname='Contrary, Mary')
116 self.john_id = self.db.user.create(username='john', address='john@test',
117 alternate_addresses='jondoe@test\njohn.doe@test', roles='User',
118 realname='John Doe')
120 def tearDown(self):
121 if os.path.exists(SENDMAILDEBUG):
122 os.remove(SENDMAILDEBUG)
123 self.db.close()
124 try:
125 shutil.rmtree(self.dirname)
126 except OSError, error:
127 if error.errno not in (errno.ENOENT, errno.ESRCH): raise
129 def _handle_mail(self, message):
130 handler = self.instance.MailGW(self.instance, self.db)
131 handler.trapExceptions = 0
132 return handler.main(StringIO(message))
134 def _get_mail(self):
135 f = open(SENDMAILDEBUG)
136 try:
137 return f.read()
138 finally:
139 f.close()
141 def testEmptyMessage(self):
142 nodeid = self._handle_mail('''Content-Type: text/plain;
143 charset="iso-8859-1"
144 From: Chef <chef@bork.bork.bork>
145 To: issue_tracker@your.tracker.email.domain.example
146 Cc: richard@test
147 Reply-To: chef@bork.bork.bork
148 Message-Id: <dummy_test_message_id>
149 Subject: [issue] Testing...
151 ''')
152 assert not os.path.exists(SENDMAILDEBUG)
153 self.assertEqual(self.db.issue.get(nodeid, 'title'), 'Testing...')
155 def doNewIssue(self):
156 nodeid = self._handle_mail('''Content-Type: text/plain;
157 charset="iso-8859-1"
158 From: Chef <chef@bork.bork.bork>
159 To: issue_tracker@your.tracker.email.domain.example
160 Cc: richard@test
161 Message-Id: <dummy_test_message_id>
162 Subject: [issue] Testing...
164 This is a test submission of a new issue.
165 ''')
166 assert not os.path.exists(SENDMAILDEBUG)
167 l = self.db.issue.get(nodeid, 'nosy')
168 l.sort()
169 self.assertEqual(l, [self.chef_id, self.richard_id])
170 return nodeid
172 def testNewIssue(self):
173 self.doNewIssue()
175 def testNewIssueNosy(self):
176 self.instance.config.ADD_AUTHOR_TO_NOSY = 'yes'
177 nodeid = self._handle_mail('''Content-Type: text/plain;
178 charset="iso-8859-1"
179 From: Chef <chef@bork.bork.bork>
180 To: issue_tracker@your.tracker.email.domain.example
181 Cc: richard@test
182 Message-Id: <dummy_test_message_id>
183 Subject: [issue] Testing...
185 This is a test submission of a new issue.
186 ''')
187 assert not os.path.exists(SENDMAILDEBUG)
188 l = self.db.issue.get(nodeid, 'nosy')
189 l.sort()
190 self.assertEqual(l, [self.chef_id, self.richard_id])
192 def testAlternateAddress(self):
193 self._handle_mail('''Content-Type: text/plain;
194 charset="iso-8859-1"
195 From: John Doe <john.doe@test>
196 To: issue_tracker@your.tracker.email.domain.example
197 Message-Id: <dummy_test_message_id>
198 Subject: [issue] Testing...
200 This is a test submission of a new issue.
201 ''')
202 userlist = self.db.user.list()
203 assert not os.path.exists(SENDMAILDEBUG)
204 self.assertEqual(userlist, self.db.user.list(),
205 "user created when it shouldn't have been")
207 def testNewIssueNoClass(self):
208 self._handle_mail('''Content-Type: text/plain;
209 charset="iso-8859-1"
210 From: Chef <chef@bork.bork.bork>
211 To: issue_tracker@your.tracker.email.domain.example
212 Cc: richard@test
213 Message-Id: <dummy_test_message_id>
214 Subject: Testing...
216 This is a test submission of a new issue.
217 ''')
218 assert not os.path.exists(SENDMAILDEBUG)
220 def testNewIssueAuthMsg(self):
221 # TODO: fix the damn config - this is apalling
222 self.db.config.MESSAGES_TO_AUTHOR = 'yes'
223 self._handle_mail('''Content-Type: text/plain;
224 charset="iso-8859-1"
225 From: Chef <chef@bork.bork.bork>
226 To: issue_tracker@your.tracker.email.domain.example
227 Message-Id: <dummy_test_message_id>
228 Subject: [issue] Testing... [nosy=mary; assignedto=richard]
230 This is a test submission of a new issue.
231 ''')
232 self.compareMessages(self._get_mail(),
233 '''FROM: roundup-admin@your.tracker.email.domain.example
234 TO: chef@bork.bork.bork, mary@test, richard@test
235 Content-Type: text/plain; charset=utf-8
236 Subject: [issue1] Testing...
237 To: chef@bork.bork.bork, mary@test, richard@test
238 From: "Bork, Chef" <issue_tracker@your.tracker.email.domain.example>
239 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
240 MIME-Version: 1.0
241 Message-Id: <dummy_test_message_id>
242 X-Roundup-Name: Roundup issue tracker
243 X-Roundup-Loop: hello
244 Content-Transfer-Encoding: quoted-printable
247 New submission from Bork, Chef <chef@bork.bork.bork>:
249 This is a test submission of a new issue.
251 ----------
252 assignedto: richard
253 messages: 1
254 nosy: Chef, mary, richard
255 status: unread
256 title: Testing...
257 _______________________________________________________________________
258 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
259 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
260 _______________________________________________________________________
261 ''')
263 # BUG
264 # def testMultipart(self):
265 # '''With more than one part'''
266 # see MultipartEnc tests: but if there is more than one part
267 # we return a multipart/mixed and the boundary contains
268 # the ip address of the test machine.
270 # BUG should test some binary attamchent too.
272 def testSimpleFollowup(self):
273 self.doNewIssue()
274 self._handle_mail('''Content-Type: text/plain;
275 charset="iso-8859-1"
276 From: mary <mary@test>
277 To: issue_tracker@your.tracker.email.domain.example
278 Message-Id: <followup_dummy_id>
279 In-Reply-To: <dummy_test_message_id>
280 Subject: [issue1] Testing...
282 This is a second followup
283 ''')
284 self.compareMessages(self._get_mail(),
285 '''FROM: roundup-admin@your.tracker.email.domain.example
286 TO: chef@bork.bork.bork, richard@test
287 Content-Type: text/plain; charset=utf-8
288 Subject: [issue1] Testing...
289 To: chef@bork.bork.bork, richard@test
290 From: "Contrary, Mary" <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: <followup_dummy_id>
294 In-Reply-To: <dummy_test_message_id>
295 X-Roundup-Name: Roundup issue tracker
296 X-Roundup-Loop: hello
297 Content-Transfer-Encoding: quoted-printable
300 Contrary, Mary <mary@test> added the comment:
302 This is a second followup
304 ----------
305 status: unread -> chatting
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 testFollowup(self):
313 self.doNewIssue()
315 self._handle_mail('''Content-Type: text/plain;
316 charset="iso-8859-1"
317 From: richard <richard@test>
318 To: issue_tracker@your.tracker.email.domain.example
319 Message-Id: <followup_dummy_id>
320 In-Reply-To: <dummy_test_message_id>
321 Subject: [issue1] Testing... [assignedto=mary; nosy=+john]
323 This is a followup
324 ''')
325 l = self.db.issue.get('1', 'nosy')
326 l.sort()
327 self.assertEqual(l, [self.chef_id, self.richard_id, self.mary_id,
328 self.john_id])
330 self.compareMessages(self._get_mail(),
331 '''FROM: roundup-admin@your.tracker.email.domain.example
332 TO: chef@bork.bork.bork, john@test, mary@test
333 Content-Type: text/plain; charset=utf-8
334 Subject: [issue1] Testing...
335 To: chef@bork.bork.bork, john@test, mary@test
336 From: richard <issue_tracker@your.tracker.email.domain.example>
337 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
338 MIME-Version: 1.0
339 Message-Id: <followup_dummy_id>
340 In-Reply-To: <dummy_test_message_id>
341 X-Roundup-Name: Roundup issue tracker
342 X-Roundup-Loop: hello
343 Content-Transfer-Encoding: quoted-printable
346 richard <richard@test> added the comment:
348 This is a followup
350 ----------
351 assignedto: -> mary
352 nosy: +john, mary
353 status: unread -> chatting
354 _______________________________________________________________________
355 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
356 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
357 _______________________________________________________________________
358 ''')
360 def testFollowupTitleMatch(self):
361 self.doNewIssue()
362 self._handle_mail('''Content-Type: text/plain;
363 charset="iso-8859-1"
364 From: richard <richard@test>
365 To: issue_tracker@your.tracker.email.domain.example
366 Message-Id: <followup_dummy_id>
367 In-Reply-To: <dummy_test_message_id>
368 Subject: Re: Testing... [assignedto=mary; nosy=+john]
370 This is a followup
371 ''')
372 self.compareMessages(self._get_mail(),
373 '''FROM: roundup-admin@your.tracker.email.domain.example
374 TO: chef@bork.bork.bork, john@test, mary@test
375 Content-Type: text/plain; charset=utf-8
376 Subject: [issue1] Testing...
377 To: chef@bork.bork.bork, john@test, mary@test
378 From: richard <issue_tracker@your.tracker.email.domain.example>
379 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
380 MIME-Version: 1.0
381 Message-Id: <followup_dummy_id>
382 In-Reply-To: <dummy_test_message_id>
383 X-Roundup-Name: Roundup issue tracker
384 X-Roundup-Loop: hello
385 Content-Transfer-Encoding: quoted-printable
388 richard <richard@test> added the comment:
390 This is a followup
392 ----------
393 assignedto: -> mary
394 nosy: +john, mary
395 status: unread -> chatting
396 _______________________________________________________________________
397 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
398 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
399 _______________________________________________________________________
400 ''')
402 def testFollowupNosyAuthor(self):
403 self.doNewIssue()
404 self.db.config.ADD_AUTHOR_TO_NOSY = 'yes'
405 self._handle_mail('''Content-Type: text/plain;
406 charset="iso-8859-1"
407 From: john@test
408 To: issue_tracker@your.tracker.email.domain.example
409 Message-Id: <followup_dummy_id>
410 In-Reply-To: <dummy_test_message_id>
411 Subject: [issue1] Testing...
413 This is a followup
414 ''')
416 self.compareMessages(self._get_mail(),
417 '''FROM: roundup-admin@your.tracker.email.domain.example
418 TO: chef@bork.bork.bork, richard@test
419 Content-Type: text/plain; charset=utf-8
420 Subject: [issue1] Testing...
421 To: chef@bork.bork.bork, richard@test
422 From: John Doe <issue_tracker@your.tracker.email.domain.example>
423 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
424 MIME-Version: 1.0
425 Message-Id: <followup_dummy_id>
426 In-Reply-To: <dummy_test_message_id>
427 X-Roundup-Name: Roundup issue tracker
428 X-Roundup-Loop: hello
429 Content-Transfer-Encoding: quoted-printable
432 John Doe <john@test> added the comment:
434 This is a followup
436 ----------
437 nosy: +john
438 status: unread -> chatting
439 _______________________________________________________________________
440 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
441 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
442 _______________________________________________________________________
444 ''')
446 def testFollowupNosyRecipients(self):
447 self.doNewIssue()
448 self.db.config.ADD_RECIPIENTS_TO_NOSY = 'yes'
449 self._handle_mail('''Content-Type: text/plain;
450 charset="iso-8859-1"
451 From: richard@test
452 To: issue_tracker@your.tracker.email.domain.example
453 Cc: john@test
454 Message-Id: <followup_dummy_id>
455 In-Reply-To: <dummy_test_message_id>
456 Subject: [issue1] Testing...
458 This is a followup
459 ''')
460 self.compareMessages(self._get_mail(),
461 '''FROM: roundup-admin@your.tracker.email.domain.example
462 TO: chef@bork.bork.bork
463 Content-Type: text/plain; charset=utf-8
464 Subject: [issue1] Testing...
465 To: chef@bork.bork.bork
466 From: richard <issue_tracker@your.tracker.email.domain.example>
467 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
468 MIME-Version: 1.0
469 Message-Id: <followup_dummy_id>
470 In-Reply-To: <dummy_test_message_id>
471 X-Roundup-Name: Roundup issue tracker
472 X-Roundup-Loop: hello
473 Content-Transfer-Encoding: quoted-printable
476 richard <richard@test> added the comment:
478 This is a followup
480 ----------
481 nosy: +john
482 status: unread -> chatting
483 _______________________________________________________________________
484 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
485 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
486 _______________________________________________________________________
488 ''')
490 def testFollowupNosyAuthorAndCopy(self):
491 self.doNewIssue()
492 self.db.config.ADD_AUTHOR_TO_NOSY = 'yes'
493 self.db.config.MESSAGES_TO_AUTHOR = 'yes'
494 self._handle_mail('''Content-Type: text/plain;
495 charset="iso-8859-1"
496 From: john@test
497 To: issue_tracker@your.tracker.email.domain.example
498 Message-Id: <followup_dummy_id>
499 In-Reply-To: <dummy_test_message_id>
500 Subject: [issue1] Testing...
502 This is a followup
503 ''')
504 self.compareMessages(self._get_mail(),
505 '''FROM: roundup-admin@your.tracker.email.domain.example
506 TO: chef@bork.bork.bork, john@test, richard@test
507 Content-Type: text/plain; charset=utf-8
508 Subject: [issue1] Testing...
509 To: chef@bork.bork.bork, john@test, richard@test
510 From: John Doe <issue_tracker@your.tracker.email.domain.example>
511 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
512 MIME-Version: 1.0
513 Message-Id: <followup_dummy_id>
514 In-Reply-To: <dummy_test_message_id>
515 X-Roundup-Name: Roundup issue tracker
516 X-Roundup-Loop: hello
517 Content-Transfer-Encoding: quoted-printable
520 John Doe <john@test> added the comment:
522 This is a followup
524 ----------
525 nosy: +john
526 status: unread -> chatting
527 _______________________________________________________________________
528 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
529 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
530 _______________________________________________________________________
532 ''')
534 def testFollowupNoNosyAuthor(self):
535 self.doNewIssue()
536 self.instance.config.ADD_AUTHOR_TO_NOSY = 'no'
537 self._handle_mail('''Content-Type: text/plain;
538 charset="iso-8859-1"
539 From: john@test
540 To: issue_tracker@your.tracker.email.domain.example
541 Message-Id: <followup_dummy_id>
542 In-Reply-To: <dummy_test_message_id>
543 Subject: [issue1] Testing...
545 This is a followup
546 ''')
547 self.compareMessages(self._get_mail(),
548 '''FROM: roundup-admin@your.tracker.email.domain.example
549 TO: chef@bork.bork.bork, richard@test
550 Content-Type: text/plain; charset=utf-8
551 Subject: [issue1] Testing...
552 To: chef@bork.bork.bork, richard@test
553 From: John Doe <issue_tracker@your.tracker.email.domain.example>
554 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
555 MIME-Version: 1.0
556 Message-Id: <followup_dummy_id>
557 In-Reply-To: <dummy_test_message_id>
558 X-Roundup-Name: Roundup issue tracker
559 X-Roundup-Loop: hello
560 Content-Transfer-Encoding: quoted-printable
563 John Doe <john@test> added the comment:
565 This is a followup
567 ----------
568 status: unread -> chatting
569 _______________________________________________________________________
570 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
571 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
572 _______________________________________________________________________
574 ''')
576 def testFollowupNoNosyRecipients(self):
577 self.doNewIssue()
578 self.instance.config.ADD_RECIPIENTS_TO_NOSY = 'no'
579 self._handle_mail('''Content-Type: text/plain;
580 charset="iso-8859-1"
581 From: richard@test
582 To: issue_tracker@your.tracker.email.domain.example
583 Cc: john@test
584 Message-Id: <followup_dummy_id>
585 In-Reply-To: <dummy_test_message_id>
586 Subject: [issue1] Testing...
588 This is a followup
589 ''')
590 self.compareMessages(self._get_mail(),
591 '''FROM: roundup-admin@your.tracker.email.domain.example
592 TO: chef@bork.bork.bork
593 Content-Type: text/plain; charset=utf-8
594 Subject: [issue1] Testing...
595 To: chef@bork.bork.bork
596 From: richard <issue_tracker@your.tracker.email.domain.example>
597 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
598 MIME-Version: 1.0
599 Message-Id: <followup_dummy_id>
600 In-Reply-To: <dummy_test_message_id>
601 X-Roundup-Name: Roundup issue tracker
602 X-Roundup-Loop: hello
603 Content-Transfer-Encoding: quoted-printable
606 richard <richard@test> added the comment:
608 This is a followup
610 ----------
611 status: unread -> chatting
612 _______________________________________________________________________
613 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
614 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
615 _______________________________________________________________________
617 ''')
619 def testFollowupEmptyMessage(self):
620 self.doNewIssue()
622 self._handle_mail('''Content-Type: text/plain;
623 charset="iso-8859-1"
624 From: richard <richard@test>
625 To: issue_tracker@your.tracker.email.domain.example
626 Message-Id: <followup_dummy_id>
627 In-Reply-To: <dummy_test_message_id>
628 Subject: [issue1] Testing... [assignedto=mary; nosy=+john]
630 ''')
631 l = self.db.issue.get('1', 'nosy')
632 l.sort()
633 self.assertEqual(l, [self.chef_id, self.richard_id, self.mary_id,
634 self.john_id])
636 # should be no file created (ie. no message)
637 assert not os.path.exists(SENDMAILDEBUG)
639 def testNosyRemove(self):
640 self.doNewIssue()
642 self._handle_mail('''Content-Type: text/plain;
643 charset="iso-8859-1"
644 From: richard <richard@test>
645 To: issue_tracker@your.tracker.email.domain.example
646 Message-Id: <followup_dummy_id>
647 In-Reply-To: <dummy_test_message_id>
648 Subject: [issue1] Testing... [nosy=-richard]
650 ''')
651 l = self.db.issue.get('1', 'nosy')
652 l.sort()
653 self.assertEqual(l, [self.chef_id])
655 # NO NOSY MESSAGE SHOULD BE SENT!
656 assert not os.path.exists(SENDMAILDEBUG)
658 def testNewUserAuthor(self):
659 # first without the permission
660 # heh... just ignore the API for a second ;)
661 self.db.security.role['anonymous'].permissions=[]
662 anonid = self.db.user.lookup('anonymous')
663 self.db.user.set(anonid, roles='Anonymous')
665 self.db.security.hasPermission('Email Registration', anonid)
666 l = self.db.user.list()
667 l.sort()
668 message = '''Content-Type: text/plain;
669 charset="iso-8859-1"
670 From: fubar <fubar@bork.bork.bork>
671 To: issue_tracker@your.tracker.email.domain.example
672 Message-Id: <dummy_test_message_id>
673 Subject: [issue] Testing...
675 This is a test submission of a new issue.
676 '''
677 self.assertRaises(Unauthorized, self._handle_mail, message)
678 m = self.db.user.list()
679 m.sort()
680 self.assertEqual(l, m)
682 # now with the permission
683 p = self.db.security.getPermission('Email Registration')
684 self.db.security.role['anonymous'].permissions=[p]
685 self._handle_mail(message)
686 m = self.db.user.list()
687 m.sort()
688 self.assertNotEqual(l, m)
690 def testEnc01(self):
691 self.doNewIssue()
692 self._handle_mail('''Content-Type: text/plain;
693 charset="iso-8859-1"
694 From: mary <mary@test>
695 To: issue_tracker@your.tracker.email.domain.example
696 Message-Id: <followup_dummy_id>
697 In-Reply-To: <dummy_test_message_id>
698 Subject: [issue1] Testing...
699 Content-Type: text/plain;
700 charset="iso-8859-1"
701 Content-Transfer-Encoding: quoted-printable
703 A message with encoding (encoded oe =F6)
705 ''')
706 self.compareMessages(self._get_mail(),
707 '''FROM: roundup-admin@your.tracker.email.domain.example
708 TO: chef@bork.bork.bork, richard@test
709 Content-Type: text/plain; charset=utf-8
710 Subject: [issue1] Testing...
711 To: chef@bork.bork.bork, richard@test
712 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
713 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
714 MIME-Version: 1.0
715 Message-Id: <followup_dummy_id>
716 In-Reply-To: <dummy_test_message_id>
717 X-Roundup-Name: Roundup issue tracker
718 X-Roundup-Loop: hello
719 Content-Transfer-Encoding: quoted-printable
722 Contrary, Mary <mary@test> added the comment:
724 A message with encoding (encoded oe =C3=B6)
726 ----------
727 status: unread -> chatting
728 _______________________________________________________________________
729 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
730 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
731 _______________________________________________________________________
732 ''')
735 def testMultipartEnc01(self):
736 self.doNewIssue()
737 self._handle_mail('''Content-Type: text/plain;
738 charset="iso-8859-1"
739 From: mary <mary@test>
740 To: issue_tracker@your.tracker.email.domain.example
741 Message-Id: <followup_dummy_id>
742 In-Reply-To: <dummy_test_message_id>
743 Subject: [issue1] Testing...
744 Content-Type: multipart/mixed;
745 boundary="----_=_NextPart_000_01"
747 This message is in MIME format. Since your mail reader does not understand
748 this format, some or all of this message may not be legible.
750 ------_=_NextPart_000_01
751 Content-Type: text/plain;
752 charset="iso-8859-1"
753 Content-Transfer-Encoding: quoted-printable
755 A message with first part encoded (encoded oe =F6)
757 ''')
758 self.compareMessages(self._get_mail(),
759 '''FROM: roundup-admin@your.tracker.email.domain.example
760 TO: chef@bork.bork.bork, richard@test
761 Content-Type: text/plain; charset=utf-8
762 Subject: [issue1] Testing...
763 To: chef@bork.bork.bork, richard@test
764 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
765 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
766 MIME-Version: 1.0
767 Message-Id: <followup_dummy_id>
768 In-Reply-To: <dummy_test_message_id>
769 X-Roundup-Name: Roundup issue tracker
770 X-Roundup-Loop: hello
771 Content-Transfer-Encoding: quoted-printable
774 Contrary, Mary <mary@test> added the comment:
776 A message with first part encoded (encoded oe =C3=B6)
778 ----------
779 status: unread -> chatting
780 _______________________________________________________________________
781 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
782 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
783 _______________________________________________________________________
784 ''')
786 def testContentDisposition(self):
787 self.doNewIssue()
788 self._handle_mail('''Content-Type: text/plain;
789 charset="iso-8859-1"
790 From: mary <mary@test>
791 To: issue_tracker@your.tracker.email.domain.example
792 Message-Id: <followup_dummy_id>
793 In-Reply-To: <dummy_test_message_id>
794 Subject: [issue1] Testing...
795 Content-Type: multipart/mixed; boundary="bCsyhTFzCvuiizWE"
796 Content-Disposition: inline
799 --bCsyhTFzCvuiizWE
800 Content-Type: text/plain; charset=us-ascii
801 Content-Disposition: inline
803 test attachment binary
805 --bCsyhTFzCvuiizWE
806 Content-Type: application/octet-stream
807 Content-Disposition: attachment; filename="main.dvi"
809 xxxxxx
811 --bCsyhTFzCvuiizWE--
812 ''')
813 messages = self.db.issue.get('1', 'messages')
814 messages.sort()
815 file = self.db.msg.get(messages[-1], 'files')[0]
816 self.assertEqual(self.db.file.get(file, 'name'), 'main.dvi')
818 def testFollowupStupidQuoting(self):
819 self.doNewIssue()
821 self._handle_mail('''Content-Type: text/plain;
822 charset="iso-8859-1"
823 From: richard <richard@test>
824 To: issue_tracker@your.tracker.email.domain.example
825 Message-Id: <followup_dummy_id>
826 In-Reply-To: <dummy_test_message_id>
827 Subject: Re: "[issue1] Testing... "
829 This is a followup
830 ''')
831 self.compareMessages(self._get_mail(),
832 '''FROM: roundup-admin@your.tracker.email.domain.example
833 TO: chef@bork.bork.bork
834 Content-Type: text/plain; charset=utf-8
835 Subject: [issue1] Testing...
836 To: chef@bork.bork.bork
837 From: richard <issue_tracker@your.tracker.email.domain.example>
838 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
839 MIME-Version: 1.0
840 Message-Id: <followup_dummy_id>
841 In-Reply-To: <dummy_test_message_id>
842 X-Roundup-Name: Roundup issue tracker
843 X-Roundup-Loop: hello
844 Content-Transfer-Encoding: quoted-printable
847 richard <richard@test> added the comment:
849 This is a followup
851 ----------
852 status: unread -> chatting
853 _______________________________________________________________________
854 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
855 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
856 _______________________________________________________________________
857 ''')
859 def testEmailQuoting(self):
860 self.instance.config.EMAIL_KEEP_QUOTED_TEXT = 'no'
861 self.innerTestQuoting('''This is a followup
862 ''')
864 def testEmailQuotingRemove(self):
865 self.instance.config.EMAIL_KEEP_QUOTED_TEXT = 'yes'
866 self.innerTestQuoting('''Blah blah wrote:
867 > Blah bklaskdfj sdf asdf jlaskdf skj sdkfjl asdf
868 > skdjlkjsdfalsdkfjasdlfkj dlfksdfalksd fj
869 >
871 This is a followup
872 ''')
874 def innerTestQuoting(self, expect):
875 nodeid = self.doNewIssue()
877 messages = self.db.issue.get(nodeid, 'messages')
879 self._handle_mail('''Content-Type: text/plain;
880 charset="iso-8859-1"
881 From: richard <richard@test>
882 To: issue_tracker@your.tracker.email.domain.example
883 Message-Id: <followup_dummy_id>
884 In-Reply-To: <dummy_test_message_id>
885 Subject: Re: [issue1] Testing...
887 Blah blah wrote:
888 > Blah bklaskdfj sdf asdf jlaskdf skj sdkfjl asdf
889 > skdjlkjsdfalsdkfjasdlfkj dlfksdfalksd fj
890 >
892 This is a followup
893 ''')
894 # figure the new message id
895 newmessages = self.db.issue.get(nodeid, 'messages')
896 for msg in messages:
897 newmessages.remove(msg)
898 messageid = newmessages[0]
900 self.compareMessages(self.db.msg.get(messageid, 'content'), expect)
902 def testUserLookup(self):
903 i = self.db.user.create(username='user1', address='user1@foo.com')
904 self.assertEqual(uidFromAddress(self.db, ('', 'user1@foo.com'), 0), i)
905 self.assertEqual(uidFromAddress(self.db, ('', 'USER1@foo.com'), 0), i)
906 i = self.db.user.create(username='user2', address='USER2@foo.com')
907 self.assertEqual(uidFromAddress(self.db, ('', 'USER2@foo.com'), 0), i)
908 self.assertEqual(uidFromAddress(self.db, ('', 'user2@foo.com'), 0), i)
910 def testUserAlternateLookup(self):
911 i = self.db.user.create(username='user1', address='user1@foo.com',
912 alternate_addresses='user1@bar.com')
913 self.assertEqual(uidFromAddress(self.db, ('', 'user1@bar.com'), 0), i)
914 self.assertEqual(uidFromAddress(self.db, ('', 'USER1@bar.com'), 0), i)
916 def testUserCreate(self):
917 i = uidFromAddress(self.db, ('', 'user@foo.com'), 1)
918 self.assertNotEqual(uidFromAddress(self.db, ('', 'user@bar.com'), 1), i)
920 def testRFC2822(self):
921 ascii_header = "[issue243] This is a \"test\" - with 'quotation' marks"
922 unicode_header = '[issue244] \xd0\xb0\xd0\xbd\xd0\xb4\xd1\x80\xd0\xb5\xd0\xb9'
923 unicode_encoded = '=?utf-8?q?[issue244]_=D0=B0=D0=BD=D0=B4=D1=80=D0=B5=D0=B9?='
924 self.assertEqual(rfc2822.encode_header(ascii_header), ascii_header)
925 self.assertEqual(rfc2822.encode_header(unicode_header), unicode_encoded)
927 def testRegistrationConfirmation(self):
928 otk = "Aj4euk4LZSAdwePohj90SME5SpopLETL"
929 self.db.otks.set(otk, username='johannes', __time='')
930 self._handle_mail('''Content-Type: text/plain;
931 charset="iso-8859-1"
932 From: Chef <chef@bork.bork.bork>
933 To: issue_tracker@your.tracker.email.domain.example
934 Cc: richard@test
935 Message-Id: <dummy_test_message_id>
936 Subject: Re: Complete your registration to Roundup issue tracker\r
937 -- key %s
939 This is a test confirmation of registration.
940 ''' % otk)
941 self.db.user.lookup('johannes')
943 def testFollowupOnNonIssue(self):
944 self.db.keyword.create(name='Foo')
945 self._handle_mail('''Content-Type: text/plain;
946 charset="iso-8859-1"
947 From: richard <richard@test>
948 To: issue_tracker@your.tracker.email.domain.example
949 Message-Id: <followup_dummy_id>
950 In-Reply-To: <dummy_test_message_id>
951 Subject: [keyword1] Testing... [name=Bar]
953 ''')
954 self.assertEqual(self.db.keyword.get('1', 'name'), 'Bar')
956 def testResentFrom(self):
957 nodeid = self._handle_mail('''Content-Type: text/plain;
958 charset="iso-8859-1"
959 From: Chef <chef@bork.bork.bork>
960 Resent-From: mary <mary@test>
961 To: issue_tracker@your.tracker.email.domain.example
962 Cc: richard@test
963 Message-Id: <dummy_test_message_id>
964 Subject: [issue] Testing...
966 This is a test submission of a new issue.
967 ''')
968 assert not os.path.exists(SENDMAILDEBUG)
969 l = self.db.issue.get(nodeid, 'nosy')
970 l.sort()
971 self.assertEqual(l, [self.richard_id, self.mary_id])
972 return nodeid
975 def testDejaVu(self):
976 self.assertRaises(IgnoreLoop, self._handle_mail,
977 '''Content-Type: text/plain;
978 charset="iso-8859-1"
979 From: Chef <chef@bork.bork.bork>
980 X-Roundup-Loop: hello
981 To: issue_tracker@your.tracker.email.domain.example
982 Cc: richard@test
983 Message-Id: <dummy_test_message_id>
984 Subject: Re: [issue] Testing...
986 Hi, I've been mis-configured to loop messages back to myself.
987 ''')
989 def testItsBulkStupid(self):
990 self.assertRaises(IgnoreBulk, self._handle_mail,
991 '''Content-Type: text/plain;
992 charset="iso-8859-1"
993 From: Chef <chef@bork.bork.bork>
994 Precedence: bulk
995 To: issue_tracker@your.tracker.email.domain.example
996 Cc: richard@test
997 Message-Id: <dummy_test_message_id>
998 Subject: Re: [issue] Testing...
1000 Hi, I'm on holidays, and this is a dumb auto-responder.
1001 ''')
1003 def test_suite():
1004 suite = unittest.TestSuite()
1005 suite.addTest(unittest.makeSuite(MailgwTestCase))
1006 return suite
1008 if __name__ == '__main__':
1009 runner = unittest.TextTestRunner()
1010 unittest.main(testRunner=runner)
1012 # vim: set filetype=python ts=4 sw=4 et si