Code

47b8eeb77607bb1f67ed1db103c203c9e0b3f651
[roundup.git] / test / test_mailgw.py
1 # -*- encoding: utf-8 -*-
2 #
3 # Copyright (c) 2001 Richard Jones, richard@bofh.asn.au.
4 # This module is free software, and you may redistribute it and/or modify
5 # under the same terms as Python, so long as this copyright message and
6 # disclaimer are retained in their original form.
7 #
8 # This module is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11 #
12 # $Id: test_mailgw.py,v 1.96 2008-08-19 01:40:59 richard Exp $
14 # TODO: test bcc
16 import unittest, tempfile, os, shutil, errno, imp, sys, difflib, rfc822, time
18 from cStringIO import StringIO
20 if not os.environ.has_key('SENDMAILDEBUG'):
21     os.environ['SENDMAILDEBUG'] = 'mail-test.log'
22 SENDMAILDEBUG = os.environ['SENDMAILDEBUG']
24 from roundup import mailgw, i18n, roundupdb
25 from roundup.mailgw import MailGW, Unauthorized, uidFromAddress, \
26     parseContent, IgnoreLoop, IgnoreBulk, MailUsageError, MailUsageHelp
27 from roundup import init, instance, password, rfc2822, __version__
28 from roundup.anypy.sets_ import set
30 #import db_test_base
31 import memorydb
33 class Message(rfc822.Message):
34     """String-based Message class with equivalence test."""
35     def __init__(self, s):
36         rfc822.Message.__init__(self, StringIO(s.strip()))
38     def __eq__(self, other):
39         return (self.dict == other.dict and
40                 self.fp.read() == other.fp.read())
42 class Tracker(object):
43     def open(self, journaltag):
44         return self.db
46 class DiffHelper:
47     def compareMessages(self, new, old):
48         """Compare messages for semantic equivalence."""
49         new, old = Message(new), Message(old)
51         # all Roundup-generated messages have "Precedence: bulk"
52         old['Precedence'] = 'bulk'
54         # don't try to compare the date
55         del new['date'], old['date']
57         if not new == old:
58             res = []
60             replace = {}
61             for key in new.keys():
62                 if key.startswith('from '):
63                     # skip the unix from line
64                     continue
65                 if key.lower() == 'x-roundup-version':
66                     # version changes constantly, so handle it specially
67                     if new[key] != __version__:
68                         res.append('  %s: %r != %r' % (key, __version__,
69                             new[key]))
70                 elif key.lower() == 'content-type' and 'boundary=' in new[key]:
71                     # handle mime messages
72                     newmime = new[key].split('=',1)[-1].strip('"')
73                     oldmime = old.get(key, '').split('=',1)[-1].strip('"')
74                     replace ['--' + newmime] = '--' + oldmime
75                     replace ['--' + newmime + '--'] = '--' + oldmime + '--'
76                 elif new.get(key, '') != old.get(key, ''):
77                     res.append('  %s: %r != %r' % (key, old.get(key, ''),
78                         new.get(key, '')))
80             body_diff = self.compareStrings(new.fp.read(), old.fp.read(),
81                 replace=replace)
82             if body_diff:
83                 res.append('')
84                 res.extend(body_diff)
86             if res:
87                 res.insert(0, 'Generated message not correct (diff follows, expected vs. actual):')
88                 raise AssertionError, '\n'.join(res)
90     def compareStrings(self, s2, s1, replace={}):
91         '''Note the reversal of s2 and s1 - difflib.SequenceMatcher wants
92            the first to be the "original" but in the calls in this file,
93            the second arg is the original. Ho hum.
94            Do replacements over the replace dict -- used for mime boundary
95         '''
96         l1 = s1.strip().split('\n')
97         l2 = [replace.get(i,i) for i in s2.strip().split('\n')]
98         if l1 == l2:
99             return
100         s = difflib.SequenceMatcher(None, l1, l2)
101         res = []
102         for value, s1s, s1e, s2s, s2e in s.get_opcodes():
103             if value == 'equal':
104                 for i in range(s1s, s1e):
105                     res.append('  %s'%l1[i])
106             elif value == 'delete':
107                 for i in range(s1s, s1e):
108                     res.append('- %s'%l1[i])
109             elif value == 'insert':
110                 for i in range(s2s, s2e):
111                     res.append('+ %s'%l2[i])
112             elif value == 'replace':
113                 for i, j in zip(range(s1s, s1e), range(s2s, s2e)):
114                     res.append('- %s'%l1[i])
115                     res.append('+ %s'%l2[j])
117         return res
119 class MailgwTestCase(unittest.TestCase, DiffHelper):
120     count = 0
121     schema = 'classic'
122     def setUp(self):
123         self.old_translate_ = mailgw._
124         roundupdb._ = mailgw._ = i18n.get_translation(language='C').gettext
125         MailgwTestCase.count = MailgwTestCase.count + 1
127         # and open the database / "instance"
128         self.db = memorydb.create('admin')
129         self.instance = Tracker()
130         self.instance.db = self.db
131         self.instance.config = self.db.config
132         self.instance.MailGW = MailGW
134         self.chef_id = self.db.user.create(username='Chef',
135             address='chef@bork.bork.bork', realname='Bork, Chef', roles='User')
136         self.richard_id = self.db.user.create(username='richard',
137             address='richard@test.test', roles='User')
138         self.mary_id = self.db.user.create(username='mary',
139             address='mary@test.test', roles='User', realname='Contrary, Mary')
140         self.john_id = self.db.user.create(username='john',
141             address='john@test.test', roles='User', realname='John Doe',
142             alternate_addresses='jondoe@test.test\njohn.doe@test.test')
143         self.rgg_id = self.db.user.create(username='rgg',
144             address='rgg@test.test', roles='User')
146     def tearDown(self):
147         roundupdb._ = mailgw._ = self.old_translate_
148         if os.path.exists(SENDMAILDEBUG):
149             os.remove(SENDMAILDEBUG)
150         self.db.close()
152     def _create_mailgw(self, message):
153         class MailGW(self.instance.MailGW):
154             def handle_message(self, message):
155                 return self._handle_message(message)
156         handler = MailGW(self.instance)
157         handler.db = self.db
158         return handler
160     def _handle_mail(self, message):
161         handler = self._create_mailgw(message)
162         handler.trapExceptions = 0
163         return handler.main(StringIO(message))
165     def _get_mail(self):
166         f = open(SENDMAILDEBUG)
167         try:
168             return f.read()
169         finally:
170             f.close()
172     def testEmptyMessage(self):
173         nodeid = self._handle_mail('''Content-Type: text/plain;
174   charset="iso-8859-1"
175 From: Chef <chef@bork.bork.bork>
176 To: issue_tracker@your.tracker.email.domain.example
177 Cc: richard@test.test
178 Reply-To: chef@bork.bork.bork
179 Message-Id: <dummy_test_message_id>
180 Subject: [issue] Testing...
182 ''')
183         assert not os.path.exists(SENDMAILDEBUG)
184         self.assertEqual(self.db.issue.get(nodeid, 'title'), 'Testing...')
186     def testMessageWithFromInIt(self):
187         nodeid = self._handle_mail('''Content-Type: text/plain;
188   charset="iso-8859-1"
189 From: Chef <chef@bork.bork.bork>
190 To: issue_tracker@your.tracker.email.domain.example
191 Cc: richard@test.test
192 Reply-To: chef@bork.bork.bork
193 Message-Id: <dummy_test_message_id>
194 Subject: [issue] Testing...
196 From here to there!
197 ''')
198         assert not os.path.exists(SENDMAILDEBUG)
199         msgid = self.db.issue.get(nodeid, 'messages')[0]
200         self.assertEqual(self.db.msg.get(msgid, 'content'), 'From here to there!')
202     def doNewIssue(self):
203         nodeid = self._handle_mail('''Content-Type: text/plain;
204   charset="iso-8859-1"
205 From: Chef <chef@bork.bork.bork>
206 To: issue_tracker@your.tracker.email.domain.example
207 Cc: richard@test.test
208 Message-Id: <dummy_test_message_id>
209 Subject: [issue] Testing...
211 This is a test submission of a new issue.
212 ''')
213         assert not os.path.exists(SENDMAILDEBUG)
214         l = self.db.issue.get(nodeid, 'nosy')
215         l.sort()
216         self.assertEqual(l, [self.chef_id, self.richard_id])
217         return nodeid
219     def testNewIssue(self):
220         self.doNewIssue()
222     def testNewIssueNosy(self):
223         self.instance.config.ADD_AUTHOR_TO_NOSY = 'yes'
224         nodeid = self._handle_mail('''Content-Type: text/plain;
225   charset="iso-8859-1"
226 From: Chef <chef@bork.bork.bork>
227 To: issue_tracker@your.tracker.email.domain.example
228 Cc: richard@test.test
229 Message-Id: <dummy_test_message_id>
230 Subject: [issue] Testing...
232 This is a test submission of a new issue.
233 ''')
234         assert not os.path.exists(SENDMAILDEBUG)
235         l = self.db.issue.get(nodeid, 'nosy')
236         l.sort()
237         self.assertEqual(l, [self.chef_id, self.richard_id])
239     def testAlternateAddress(self):
240         self._handle_mail('''Content-Type: text/plain;
241   charset="iso-8859-1"
242 From: John Doe <john.doe@test.test>
243 To: issue_tracker@your.tracker.email.domain.example
244 Message-Id: <dummy_test_message_id>
245 Subject: [issue] Testing...
247 This is a test submission of a new issue.
248 ''')
249         userlist = self.db.user.list()
250         assert not os.path.exists(SENDMAILDEBUG)
251         self.assertEqual(userlist, self.db.user.list(),
252             "user created when it shouldn't have been")
254     def testNewIssueNoClass(self):
255         self._handle_mail('''Content-Type: text/plain;
256   charset="iso-8859-1"
257 From: Chef <chef@bork.bork.bork>
258 To: issue_tracker@your.tracker.email.domain.example
259 Cc: richard@test.test
260 Message-Id: <dummy_test_message_id>
261 Subject: Testing...
263 This is a test submission of a new issue.
264 ''')
265         assert not os.path.exists(SENDMAILDEBUG)
267     def testNewIssueAuthMsg(self):
268         # TODO: fix the damn config - this is apalling
269         self.db.config.MESSAGES_TO_AUTHOR = 'yes'
270         self._handle_mail('''Content-Type: text/plain;
271   charset="iso-8859-1"
272 From: Chef <chef@bork.bork.bork>
273 To: issue_tracker@your.tracker.email.domain.example
274 Message-Id: <dummy_test_message_id>
275 Subject: [issue] Testing... [nosy=mary; assignedto=richard]
277 This is a test submission of a new issue.
278 ''')
279         self.compareMessages(self._get_mail(),
280 '''FROM: roundup-admin@your.tracker.email.domain.example
281 TO: chef@bork.bork.bork, mary@test.test, richard@test.test
282 Content-Type: text/plain; charset="utf-8"
283 Subject: [issue1] Testing...
284 To: chef@bork.bork.bork, mary@test.test, richard@test.test
285 From: "Bork, Chef" <issue_tracker@your.tracker.email.domain.example>
286 Reply-To: Roundup issue tracker
287  <issue_tracker@your.tracker.email.domain.example>
288 MIME-Version: 1.0
289 Message-Id: <dummy_test_message_id>
290 X-Roundup-Name: Roundup issue tracker
291 X-Roundup-Loop: hello
292 X-Roundup-Issue-Status: unread
293 Content-Transfer-Encoding: quoted-printable
296 New submission from Bork, Chef <chef@bork.bork.bork>:
298 This is a test submission of a new issue.
300 ----------
301 assignedto: richard
302 messages: 1
303 nosy: Chef, mary, richard
304 status: unread
305 title: Testing...
307 _______________________________________________________________________
308 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
309 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
310 _______________________________________________________________________
311 ''')
313     def testNewIssueNoAuthorInfo(self):
314         self.db.config.MAIL_ADD_AUTHORINFO = 'no'
315         self._handle_mail('''Content-Type: text/plain;
316   charset="iso-8859-1"
317 From: Chef <chef@bork.bork.bork>
318 To: issue_tracker@your.tracker.email.domain.example
319 Message-Id: <dummy_test_message_id>
320 Subject: [issue] Testing... [nosy=mary; assignedto=richard]
322 This is a test submission of a new issue.
323 ''')
324         self.compareMessages(self._get_mail(),
325 '''FROM: roundup-admin@your.tracker.email.domain.example
326 TO: chef@bork.bork.bork, mary@test.test, richard@test.test
327 Content-Type: text/plain; charset="utf-8"
328 Subject: [issue1] Testing...
329 To: mary@test.test, richard@test.test
330 From: "Bork, Chef" <issue_tracker@your.tracker.email.domain.example>
331 Reply-To: Roundup issue tracker
332  <issue_tracker@your.tracker.email.domain.example>
333 MIME-Version: 1.0
334 Message-Id: <dummy_test_message_id>
335 X-Roundup-Name: Roundup issue tracker
336 X-Roundup-Loop: hello
337 X-Roundup-Issue-Status: unread
338 Content-Transfer-Encoding: quoted-printable
340 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     def testNewIssueNoAuthorEmail(self):
356         self.db.config.MAIL_ADD_AUTHOREMAIL = 'no'
357         self._handle_mail('''Content-Type: text/plain;
358   charset="iso-8859-1"
359 From: Chef <chef@bork.bork.bork>
360 To: issue_tracker@your.tracker.email.domain.example
361 Message-Id: <dummy_test_message_id>
362 Subject: [issue] Testing... [nosy=mary; assignedto=richard]
364 This is a test submission of a new issue.
365 ''')
366         self.compareMessages(self._get_mail(),
367 '''FROM: roundup-admin@your.tracker.email.domain.example
368 TO: chef@bork.bork.bork, mary@test.test, richard@test.test
369 Content-Type: text/plain; charset="utf-8"
370 Subject: [issue1] Testing...
371 To: mary@test.test, richard@test.test
372 From: "Bork, Chef" <issue_tracker@your.tracker.email.domain.example>
373 Reply-To: Roundup issue tracker
374  <issue_tracker@your.tracker.email.domain.example>
375 MIME-Version: 1.0
376 Message-Id: <dummy_test_message_id>
377 X-Roundup-Name: Roundup issue tracker
378 X-Roundup-Loop: hello
379 X-Roundup-Issue-Status: unread
380 Content-Transfer-Encoding: quoted-printable
382 New submission from Bork, Chef:
384 This is a test submission of a new issue.
386 ----------
387 assignedto: richard
388 messages: 1
389 nosy: Chef, mary, richard
390 status: unread
391 title: Testing...
393 _______________________________________________________________________
394 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
395 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
396 _______________________________________________________________________
397 ''')
399     multipart_msg = '''From: mary <mary@test.test>
400 To: issue_tracker@your.tracker.email.domain.example
401 Message-Id: <followup_dummy_id>
402 In-Reply-To: <dummy_test_message_id>
403 Subject: [issue1] Testing...
404 Content-Type: multipart/mixed; boundary="bxyzzy"
405 Content-Disposition: inline
408 --bxyzzy
409 Content-Type: multipart/alternative; boundary="bCsyhTFzCvuiizWE"
410 Content-Disposition: inline
412 --bCsyhTFzCvuiizWE
413 Content-Type: text/plain; charset=us-ascii
414 Content-Disposition: inline
416 test attachment first text/plain
418 --bCsyhTFzCvuiizWE
419 Content-Type: application/octet-stream
420 Content-Disposition: attachment; filename="first.dvi"
421 Content-Transfer-Encoding: base64
423 SnVzdCBhIHRlc3QgAQo=
425 --bCsyhTFzCvuiizWE
426 Content-Type: text/plain; charset=us-ascii
427 Content-Disposition: inline
429 test attachment second text/plain
431 --bCsyhTFzCvuiizWE
432 Content-Type: text/html
433 Content-Disposition: inline
435 <html>
436 to be ignored.
437 </html>
439 --bCsyhTFzCvuiizWE--
441 --bxyzzy
442 Content-Type: multipart/alternative; boundary="bCsyhTFzCvuiizWF"
443 Content-Disposition: inline
445 --bCsyhTFzCvuiizWF
446 Content-Type: text/plain; charset=us-ascii
447 Content-Disposition: inline
449 test attachment third text/plain
451 --bCsyhTFzCvuiizWF
452 Content-Type: application/octet-stream
453 Content-Disposition: attachment; filename="second.dvi"
454 Content-Transfer-Encoding: base64
456 SnVzdCBhIHRlc3QK
458 --bCsyhTFzCvuiizWF--
460 --bxyzzy--
461 '''
463     multipart_msg_latin1 = '''From: mary <mary@test.test>
464 To: issue_tracker@your.tracker.email.domain.example
465 Message-Id: <followup_dummy_id>
466 In-Reply-To: <dummy_test_message_id>
467 Subject: [issue1] Testing...
468 Content-Type: multipart/alternative; boundary=001485f339f8f361fb049188dbba
471 --001485f339f8f361fb049188dbba
472 Content-Type: text/plain; charset=ISO-8859-1
473 Content-Transfer-Encoding: quoted-printable
475 umlaut =E4=F6=FC=C4=D6=DC=DF
477 --001485f339f8f361fb049188dbba
478 Content-Type: text/html; charset=ISO-8859-1
479 Content-Transfer-Encoding: quoted-printable
481 <html>umlaut =E4=F6=FC=C4=D6=DC=DF</html>
483 --001485f339f8f361fb049188dbba--
484 '''
486     def testMultipartKeepAlternatives(self):
487         self.doNewIssue()
488         self._handle_mail(self.multipart_msg)
489         messages = self.db.issue.get('1', 'messages')
490         messages.sort()
491         msg = self.db.msg.getnode (messages[-1])
492         assert(len(msg.files) == 5)
493         names = {0 : 'first.dvi', 4 : 'second.dvi'}
494         content = {3 : 'test attachment third text/plain\n',
495                    4 : 'Just a test\n'}
496         for n, id in enumerate (msg.files):
497             f = self.db.file.getnode (id)
498             self.assertEqual(f.name, names.get (n, 'unnamed'))
499             if n in content :
500                 self.assertEqual(f.content, content [n])
501         self.assertEqual(msg.content, 'test attachment second text/plain')
503     def testMultipartDropAlternatives(self):
504         self.doNewIssue()
505         self.db.config.MAILGW_IGNORE_ALTERNATIVES = True
506         self._handle_mail(self.multipart_msg)
507         messages = self.db.issue.get('1', 'messages')
508         messages.sort()
509         msg = self.db.msg.getnode (messages[-1])
510         assert(len(msg.files) == 2)
511         names = {1 : 'second.dvi'}
512         content = {0 : 'test attachment third text/plain\n',
513                    1 : 'Just a test\n'}
514         for n, id in enumerate (msg.files):
515             f = self.db.file.getnode (id)
516             self.assertEqual(f.name, names.get (n, 'unnamed'))
517             if n in content :
518                 self.assertEqual(f.content, content [n])
519         self.assertEqual(msg.content, 'test attachment second text/plain')
521     def testMultipartCharsetUTF8NoAttach(self):
522         c = 'umlaut \xc3\xa4\xc3\xb6\xc3\xbc\xc3\x84\xc3\x96\xc3\x9c\xc3\x9f'
523         self.doNewIssue()
524         self.db.config.NOSY_MAX_ATTACHMENT_SIZE = 0
525         self._handle_mail(self.multipart_msg_latin1)
526         messages = self.db.issue.get('1', 'messages')
527         messages.sort()
528         msg = self.db.msg.getnode (messages[-1])
529         assert(len(msg.files) == 1)
530         name = 'unnamed'
531         content = '<html>' + c + '</html>\n'
532         for n, id in enumerate (msg.files):
533             f = self.db.file.getnode (id)
534             self.assertEqual(f.name, name)
535             self.assertEqual(f.content, content)
536         self.assertEqual(msg.content, c)
537         self.compareMessages(self._get_mail(),
538 '''FROM: roundup-admin@your.tracker.email.domain.example
539 TO: chef@bork.bork.bork, richard@test.test
540 Content-Type: text/plain; charset="utf-8"
541 Subject: [issue1] Testing...
542 To: chef@bork.bork.bork, richard@test.test
543 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
544 Reply-To: Roundup issue tracker
545  <issue_tracker@your.tracker.email.domain.example>
546 MIME-Version: 1.0
547 Message-Id: <followup_dummy_id>
548 In-Reply-To: <dummy_test_message_id>
549 X-Roundup-Name: Roundup issue tracker
550 X-Roundup-Loop: hello
551 X-Roundup-Issue-Status: chatting
552 X-Roundup-Issue-Files: unnamed
553 Content-Transfer-Encoding: quoted-printable
556 Contrary, Mary <mary@test.test> added the comment:
558 umlaut =C3=A4=C3=B6=C3=BC=C3=84=C3=96=C3=9C=C3=9F
559 File 'unnamed' not attached - you can download it from http://tracker.examp=
560 le/cgi-bin/roundup.cgi/bugs/file1.
562 ----------
563 status: unread -> chatting
565 _______________________________________________________________________
566 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
567 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
568 _______________________________________________________________________
569 ''')
571     def testMultipartCharsetLatin1NoAttach(self):
572         c = 'umlaut \xc3\xa4\xc3\xb6\xc3\xbc\xc3\x84\xc3\x96\xc3\x9c\xc3\x9f'
573         self.doNewIssue()
574         self.db.config.NOSY_MAX_ATTACHMENT_SIZE = 0
575         self.db.config.MAIL_CHARSET = 'iso-8859-1'
576         self._handle_mail(self.multipart_msg_latin1)
577         messages = self.db.issue.get('1', 'messages')
578         messages.sort()
579         msg = self.db.msg.getnode (messages[-1])
580         assert(len(msg.files) == 1)
581         name = 'unnamed'
582         content = '<html>' + c + '</html>\n'
583         for n, id in enumerate (msg.files):
584             f = self.db.file.getnode (id)
585             self.assertEqual(f.name, name)
586             self.assertEqual(f.content, content)
587         self.assertEqual(msg.content, c)
588         self.compareMessages(self._get_mail(),
589 '''FROM: roundup-admin@your.tracker.email.domain.example
590 TO: chef@bork.bork.bork, richard@test.test
591 Content-Type: text/plain; charset="iso-8859-1"
592 Subject: [issue1] Testing...
593 To: chef@bork.bork.bork, richard@test.test
594 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
595 Reply-To: Roundup issue tracker
596  <issue_tracker@your.tracker.email.domain.example>
597 MIME-Version: 1.0
598 Message-Id: <followup_dummy_id>
599 In-Reply-To: <dummy_test_message_id>
600 X-Roundup-Name: Roundup issue tracker
601 X-Roundup-Loop: hello
602 X-Roundup-Issue-Status: chatting
603 X-Roundup-Issue-Files: unnamed
604 Content-Transfer-Encoding: quoted-printable
607 Contrary, Mary <mary@test.test> added the comment:
609 umlaut =E4=F6=FC=C4=D6=DC=DF
610 File 'unnamed' not attached - you can download it from http://tracker.examp=
611 le/cgi-bin/roundup.cgi/bugs/file1.
613 ----------
614 status: unread -> chatting
616 _______________________________________________________________________
617 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
618 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
619 _______________________________________________________________________
620 ''')
622     def testMultipartCharsetUTF8AttachFile(self):
623         c = 'umlaut \xc3\xa4\xc3\xb6\xc3\xbc\xc3\x84\xc3\x96\xc3\x9c\xc3\x9f'
624         self.doNewIssue()
625         self._handle_mail(self.multipart_msg_latin1)
626         messages = self.db.issue.get('1', 'messages')
627         messages.sort()
628         msg = self.db.msg.getnode (messages[-1])
629         assert(len(msg.files) == 1)
630         name = 'unnamed'
631         content = '<html>' + c + '</html>\n'
632         for n, id in enumerate (msg.files):
633             f = self.db.file.getnode (id)
634             self.assertEqual(f.name, name)
635             self.assertEqual(f.content, content)
636         self.assertEqual(msg.content, c)
637         self.compareMessages(self._get_mail(),
638 '''FROM: roundup-admin@your.tracker.email.domain.example
639 TO: chef@bork.bork.bork, richard@test.test
640 Content-Type: multipart/mixed; boundary="utf-8"
641 Subject: [issue1] Testing...
642 To: chef@bork.bork.bork, richard@test.test
643 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
644 Reply-To: Roundup issue tracker
645  <issue_tracker@your.tracker.email.domain.example>
646 MIME-Version: 1.0
647 Message-Id: <followup_dummy_id>
648 In-Reply-To: <dummy_test_message_id>
649 X-Roundup-Name: Roundup issue tracker
650 X-Roundup-Loop: hello
651 X-Roundup-Issue-Status: chatting
652 X-Roundup-Issue-Files: unnamed
653 Content-Transfer-Encoding: quoted-printable
656 --utf-8
657 MIME-Version: 1.0
658 Content-Type: text/plain; charset="utf-8"
659 Content-Transfer-Encoding: quoted-printable
662 Contrary, Mary <mary@test.test> added the comment:
664 umlaut =C3=A4=C3=B6=C3=BC=C3=84=C3=96=C3=9C=C3=9F
666 ----------
667 status: unread -> chatting
669 _______________________________________________________________________
670 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
671 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
672 _______________________________________________________________________
673 --utf-8
674 Content-Type: text/html
675 MIME-Version: 1.0
676 Content-Transfer-Encoding: base64
677 Content-Disposition: attachment;
678  filename="unnamed"
680 PGh0bWw+dW1sYXV0IMOkw7bDvMOEw5bDnMOfPC9odG1sPgo=
682 --utf-8--
683 ''')
685     def testMultipartCharsetLatin1AttachFile(self):
686         c = 'umlaut \xc3\xa4\xc3\xb6\xc3\xbc\xc3\x84\xc3\x96\xc3\x9c\xc3\x9f'
687         self.doNewIssue()
688         self.db.config.MAIL_CHARSET = 'iso-8859-1'
689         self._handle_mail(self.multipart_msg_latin1)
690         messages = self.db.issue.get('1', 'messages')
691         messages.sort()
692         msg = self.db.msg.getnode (messages[-1])
693         assert(len(msg.files) == 1)
694         name = 'unnamed'
695         content = '<html>' + c + '</html>\n'
696         for n, id in enumerate (msg.files):
697             f = self.db.file.getnode (id)
698             self.assertEqual(f.name, name)
699             self.assertEqual(f.content, content)
700         self.assertEqual(msg.content, c)
701         self.compareMessages(self._get_mail(),
702 '''FROM: roundup-admin@your.tracker.email.domain.example
703 TO: chef@bork.bork.bork, richard@test.test
704 Content-Type: multipart/mixed; boundary="utf-8"
705 Subject: [issue1] Testing...
706 To: chef@bork.bork.bork, richard@test.test
707 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
708 Reply-To: Roundup issue tracker
709  <issue_tracker@your.tracker.email.domain.example>
710 MIME-Version: 1.0
711 Message-Id: <followup_dummy_id>
712 In-Reply-To: <dummy_test_message_id>
713 X-Roundup-Name: Roundup issue tracker
714 X-Roundup-Loop: hello
715 X-Roundup-Issue-Status: chatting
716 X-Roundup-Issue-Files: unnamed
717 Content-Transfer-Encoding: quoted-printable
720 --utf-8
721 MIME-Version: 1.0
722 Content-Type: text/plain; charset="iso-8859-1"
723 Content-Transfer-Encoding: quoted-printable
726 Contrary, Mary <mary@test.test> added the comment:
728 umlaut =E4=F6=FC=C4=D6=DC=DF
730 ----------
731 status: unread -> chatting
733 _______________________________________________________________________
734 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
735 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
736 _______________________________________________________________________
737 --utf-8
738 Content-Type: text/html
739 MIME-Version: 1.0
740 Content-Transfer-Encoding: base64
741 Content-Disposition: attachment;
742  filename="unnamed"
744 PGh0bWw+dW1sYXV0IMOkw7bDvMOEw5bDnMOfPC9odG1sPgo=
746 --utf-8--
747 ''')
749     def testSimpleFollowup(self):
750         self.doNewIssue()
751         self._handle_mail('''Content-Type: text/plain;
752   charset="iso-8859-1"
753 From: mary <mary@test.test>
754 To: issue_tracker@your.tracker.email.domain.example
755 Message-Id: <followup_dummy_id>
756 In-Reply-To: <dummy_test_message_id>
757 Subject: [issue1] Testing...
759 This is a second followup
760 ''')
761         self.compareMessages(self._get_mail(),
762 '''FROM: roundup-admin@your.tracker.email.domain.example
763 TO: chef@bork.bork.bork, richard@test.test
764 Content-Type: text/plain; charset="utf-8"
765 Subject: [issue1] Testing...
766 To: chef@bork.bork.bork, richard@test.test
767 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
768 Reply-To: Roundup issue tracker
769  <issue_tracker@your.tracker.email.domain.example>
770 MIME-Version: 1.0
771 Message-Id: <followup_dummy_id>
772 In-Reply-To: <dummy_test_message_id>
773 X-Roundup-Name: Roundup issue tracker
774 X-Roundup-Loop: hello
775 X-Roundup-Issue-Status: chatting
776 Content-Transfer-Encoding: quoted-printable
779 Contrary, Mary <mary@test.test> added the comment:
781 This is a second followup
783 ----------
784 status: unread -> chatting
786 _______________________________________________________________________
787 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
788 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
789 _______________________________________________________________________
790 ''')
792     def testFollowup(self):
793         self.doNewIssue()
795         self._handle_mail('''Content-Type: text/plain;
796   charset="iso-8859-1"
797 From: richard <richard@test.test>
798 To: issue_tracker@your.tracker.email.domain.example
799 Message-Id: <followup_dummy_id>
800 In-Reply-To: <dummy_test_message_id>
801 Subject: [issue1] Testing... [assignedto=mary; nosy=+john]
803 This is a followup
804 ''')
805         l = self.db.issue.get('1', 'nosy')
806         l.sort()
807         self.assertEqual(l, [self.chef_id, self.richard_id, self.mary_id,
808             self.john_id])
810         self.compareMessages(self._get_mail(),
811 '''FROM: roundup-admin@your.tracker.email.domain.example
812 TO: chef@bork.bork.bork, john@test.test, mary@test.test
813 Content-Type: text/plain; charset="utf-8"
814 Subject: [issue1] Testing...
815 To: chef@bork.bork.bork, john@test.test, mary@test.test
816 From: richard <issue_tracker@your.tracker.email.domain.example>
817 Reply-To: Roundup issue tracker
818  <issue_tracker@your.tracker.email.domain.example>
819 MIME-Version: 1.0
820 Message-Id: <followup_dummy_id>
821 In-Reply-To: <dummy_test_message_id>
822 X-Roundup-Name: Roundup issue tracker
823 X-Roundup-Loop: hello
824 X-Roundup-Issue-Status: chatting
825 Content-Transfer-Encoding: quoted-printable
828 richard <richard@test.test> added the comment:
830 This is a followup
832 ----------
833 assignedto:  -> mary
834 nosy: +john, mary
835 status: unread -> chatting
837 _______________________________________________________________________
838 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
839 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
840 _______________________________________________________________________
841 ''')
843     def testFollowupNoSubjectChange(self):
844         self.db.config.MAILGW_SUBJECT_UPDATES_TITLE = 'no'
845         self.doNewIssue()
847         self._handle_mail('''Content-Type: text/plain;
848   charset="iso-8859-1"
849 From: richard <richard@test.test>
850 To: issue_tracker@your.tracker.email.domain.example
851 Message-Id: <followup_dummy_id>
852 In-Reply-To: <dummy_test_message_id>
853 Subject: [issue1] Wrzlbrmft... [assignedto=mary; nosy=+john]
855 This is a followup
856 ''')
857         l = self.db.issue.get('1', 'nosy')
858         l.sort()
859         self.assertEqual(l, [self.chef_id, self.richard_id, self.mary_id,
860             self.john_id])
862         self.compareMessages(self._get_mail(),
863 '''FROM: roundup-admin@your.tracker.email.domain.example
864 TO: chef@bork.bork.bork, john@test.test, mary@test.test
865 Content-Type: text/plain; charset="utf-8"
866 Subject: [issue1] Testing...
867 To: chef@bork.bork.bork, john@test.test, mary@test.test
868 From: richard <issue_tracker@your.tracker.email.domain.example>
869 Reply-To: Roundup issue tracker
870  <issue_tracker@your.tracker.email.domain.example>
871 MIME-Version: 1.0
872 Message-Id: <followup_dummy_id>
873 In-Reply-To: <dummy_test_message_id>
874 X-Roundup-Name: Roundup issue tracker
875 X-Roundup-Loop: hello
876 X-Roundup-Issue-Status: chatting
877 Content-Transfer-Encoding: quoted-printable
880 richard <richard@test.test> added the comment:
882 This is a followup
884 ----------
885 assignedto:  -> mary
886 nosy: +john, mary
887 status: unread -> chatting
889 _______________________________________________________________________
890 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
891 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
892 _______________________________________________________________________
893 ''')
894         self.assertEqual(self.db.issue.get('1','title'), 'Testing...')
896     def testFollowupExplicitSubjectChange(self):
897         self.doNewIssue()
899         self._handle_mail('''Content-Type: text/plain;
900   charset="iso-8859-1"
901 From: richard <richard@test.test>
902 To: issue_tracker@your.tracker.email.domain.example
903 Message-Id: <followup_dummy_id>
904 In-Reply-To: <dummy_test_message_id>
905 Subject: [issue1] Wrzlbrmft... [assignedto=mary; nosy=+john; title=new title]
907 This is a followup
908 ''')
909         l = self.db.issue.get('1', 'nosy')
910         l.sort()
911         self.assertEqual(l, [self.chef_id, self.richard_id, self.mary_id,
912             self.john_id])
914         self.compareMessages(self._get_mail(),
915 '''FROM: roundup-admin@your.tracker.email.domain.example
916 TO: chef@bork.bork.bork, john@test.test, mary@test.test
917 Content-Type: text/plain; charset="utf-8"
918 Subject: [issue1] new title
919 To: chef@bork.bork.bork, john@test.test, mary@test.test
920 From: richard <issue_tracker@your.tracker.email.domain.example>
921 Reply-To: Roundup issue tracker
922  <issue_tracker@your.tracker.email.domain.example>
923 MIME-Version: 1.0
924 Message-Id: <followup_dummy_id>
925 In-Reply-To: <dummy_test_message_id>
926 X-Roundup-Name: Roundup issue tracker
927 X-Roundup-Loop: hello
928 X-Roundup-Issue-Status: chatting
929 Content-Transfer-Encoding: quoted-printable
932 richard <richard@test.test> added the comment:
934 This is a followup
936 ----------
937 assignedto:  -> mary
938 nosy: +john, mary
939 status: unread -> chatting
940 title: Testing... -> new title
942 _______________________________________________________________________
943 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
944 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
945 _______________________________________________________________________
946 ''')
948     def testNosyGeneration(self):
949         self.db.issue.create(title='test')
951         # create a nosy message
952         msg = self.db.msg.create(content='This is a test',
953             author=self.richard_id, messageid='<dummy_test_message_id>')
954         self.db.journaltag = 'richard'
955         l = self.db.issue.create(title='test', messages=[msg],
956             nosy=[self.chef_id, self.mary_id, self.john_id])
958         self.compareMessages(self._get_mail(),
959 '''FROM: roundup-admin@your.tracker.email.domain.example
960 TO: chef@bork.bork.bork, john@test.test, mary@test.test
961 Content-Type: text/plain; charset="utf-8"
962 Subject: [issue2] test
963 To: chef@bork.bork.bork, john@test.test, mary@test.test
964 From: richard <issue_tracker@your.tracker.email.domain.example>
965 Reply-To: Roundup issue tracker
966  <issue_tracker@your.tracker.email.domain.example>
967 MIME-Version: 1.0
968 Message-Id: <dummy_test_message_id>
969 X-Roundup-Name: Roundup issue tracker
970 X-Roundup-Loop: hello
971 X-Roundup-Issue-Status: unread
972 Content-Transfer-Encoding: quoted-printable
975 New submission from richard <richard@test.test>:
977 This is a test
979 ----------
980 messages: 1
981 nosy: Chef, john, mary, richard
982 status: unread
983 title: test
985 _______________________________________________________________________
986 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
987 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue2>
988 _______________________________________________________________________
989 ''')
991     def testPropertyChangeOnly(self):
992         self.doNewIssue()
993         oldvalues = self.db.getnode('issue', '1').copy()
994         oldvalues['assignedto'] = None
995         # reconstruct old behaviour: This would reuse the
996         # database-handle from the doNewIssue above which has committed
997         # as user "Chef". So we close and reopen the db as that user.
998         #self.db.close() actually don't close 'cos this empties memorydb
999         self.db = self.instance.open('Chef')
1000         self.db.issue.set('1', assignedto=self.chef_id)
1001         self.db.commit()
1002         self.db.issue.nosymessage('1', None, oldvalues)
1004         new_mail = ""
1005         for line in self._get_mail().split("\n"):
1006             if "Message-Id: " in line:
1007                 continue
1008             if "Date: " in line:
1009                 continue
1010             new_mail += line+"\n"
1012         self.compareMessages(new_mail, """
1013 FROM: roundup-admin@your.tracker.email.domain.example
1014 TO: chef@bork.bork.bork, richard@test.test
1015 Content-Type: text/plain; charset="utf-8"
1016 Subject: [issue1] Testing...
1017 To: chef@bork.bork.bork, richard@test.test
1018 From: "Bork, Chef" <issue_tracker@your.tracker.email.domain.example>
1019 X-Roundup-Name: Roundup issue tracker
1020 X-Roundup-Loop: hello
1021 X-Roundup-Issue-Status: unread
1022 X-Roundup-Version: 1.3.3
1023 In-Reply-To: <dummy_test_message_id>
1024 MIME-Version: 1.0
1025 Reply-To: Roundup issue tracker
1026  <issue_tracker@your.tracker.email.domain.example>
1027 Content-Transfer-Encoding: quoted-printable
1030 Change by Bork, Chef <chef@bork.bork.bork>:
1033 ----------
1034 assignedto:  -> Chef
1036 _______________________________________________________________________
1037 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1038 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1039 _______________________________________________________________________
1040 """)
1043     #
1044     # FOLLOWUP TITLE MATCH
1045     #
1046     def testFollowupTitleMatch(self):
1047         self.doNewIssue()
1048         self._handle_mail('''Content-Type: text/plain;
1049   charset="iso-8859-1"
1050 From: richard <richard@test.test>
1051 To: issue_tracker@your.tracker.email.domain.example
1052 Message-Id: <followup_dummy_id>
1053 Subject: Re: Testing... [assignedto=mary; nosy=+john]
1055 This is a followup
1056 ''')
1057         self.compareMessages(self._get_mail(),
1058 '''FROM: roundup-admin@your.tracker.email.domain.example
1059 TO: chef@bork.bork.bork, john@test.test, mary@test.test
1060 Content-Type: text/plain; charset="utf-8"
1061 Subject: [issue1] Testing...
1062 To: chef@bork.bork.bork, john@test.test, mary@test.test
1063 From: richard <issue_tracker@your.tracker.email.domain.example>
1064 Reply-To: Roundup issue tracker
1065  <issue_tracker@your.tracker.email.domain.example>
1066 MIME-Version: 1.0
1067 Message-Id: <followup_dummy_id>
1068 In-Reply-To: <dummy_test_message_id>
1069 X-Roundup-Name: Roundup issue tracker
1070 X-Roundup-Loop: hello
1071 X-Roundup-Issue-Status: chatting
1072 Content-Transfer-Encoding: quoted-printable
1075 richard <richard@test.test> added the comment:
1077 This is a followup
1079 ----------
1080 assignedto:  -> mary
1081 nosy: +john, mary
1082 status: unread -> chatting
1084 _______________________________________________________________________
1085 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1086 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1087 _______________________________________________________________________
1088 ''')
1090     def testFollowupTitleMatchMultiRe(self):
1091         nodeid1 = self.doNewIssue()
1092         nodeid2 = self._handle_mail('''Content-Type: text/plain;
1093   charset="iso-8859-1"
1094 From: richard <richard@test.test>
1095 To: issue_tracker@your.tracker.email.domain.example
1096 Message-Id: <followup_dummy_id>
1097 Subject: Re: Testing... [assignedto=mary; nosy=+john]
1099 This is a followup
1100 ''')
1102         nodeid3 = self._handle_mail('''Content-Type: text/plain;
1103   charset="iso-8859-1"
1104 From: richard <richard@test.test>
1105 To: issue_tracker@your.tracker.email.domain.example
1106 Message-Id: <followup2_dummy_id>
1107 Subject: Ang: Re: Testing...
1109 This is a followup
1110 ''')
1111         self.assertEqual(nodeid1, nodeid2)
1112         self.assertEqual(nodeid1, nodeid3)
1114     def testFollowupTitleMatchNever(self):
1115         nodeid = self.doNewIssue()
1116         self.db.config.MAILGW_SUBJECT_CONTENT_MATCH = 'never'
1117         self.assertNotEqual(self._handle_mail('''Content-Type: text/plain;
1118   charset="iso-8859-1"
1119 From: richard <richard@test.test>
1120 To: issue_tracker@your.tracker.email.domain.example
1121 Message-Id: <followup_dummy_id>
1122 Subject: Re: Testing...
1124 This is a followup
1125 '''), nodeid)
1127     def testFollowupTitleMatchNeverInterval(self):
1128         nodeid = self.doNewIssue()
1129         # force failure of the interval
1130         time.sleep(2)
1131         self.db.config.MAILGW_SUBJECT_CONTENT_MATCH = 'creation 00:00:01'
1132         self.assertNotEqual(self._handle_mail('''Content-Type: text/plain;
1133   charset="iso-8859-1"
1134 From: richard <richard@test.test>
1135 To: issue_tracker@your.tracker.email.domain.example
1136 Message-Id: <followup_dummy_id>
1137 Subject: Re: Testing...
1139 This is a followup
1140 '''), nodeid)
1143     def testFollowupTitleMatchInterval(self):
1144         nodeid = self.doNewIssue()
1145         self.db.config.MAILGW_SUBJECT_CONTENT_MATCH = 'creation +1d'
1146         self.assertEqual(self._handle_mail('''Content-Type: text/plain;
1147   charset="iso-8859-1"
1148 From: richard <richard@test.test>
1149 To: issue_tracker@your.tracker.email.domain.example
1150 Message-Id: <followup_dummy_id>
1151 Subject: Re: Testing...
1153 This is a followup
1154 '''), nodeid)
1157     def testFollowupNosyAuthor(self):
1158         self.doNewIssue()
1159         self.db.config.ADD_AUTHOR_TO_NOSY = 'yes'
1160         self._handle_mail('''Content-Type: text/plain;
1161   charset="iso-8859-1"
1162 From: john@test.test
1163 To: issue_tracker@your.tracker.email.domain.example
1164 Message-Id: <followup_dummy_id>
1165 In-Reply-To: <dummy_test_message_id>
1166 Subject: [issue1] Testing...
1168 This is a followup
1169 ''')
1171         self.compareMessages(self._get_mail(),
1172 '''FROM: roundup-admin@your.tracker.email.domain.example
1173 TO: chef@bork.bork.bork, richard@test.test
1174 Content-Type: text/plain; charset="utf-8"
1175 Subject: [issue1] Testing...
1176 To: chef@bork.bork.bork, richard@test.test
1177 From: John Doe <issue_tracker@your.tracker.email.domain.example>
1178 Reply-To: Roundup issue tracker
1179  <issue_tracker@your.tracker.email.domain.example>
1180 MIME-Version: 1.0
1181 Message-Id: <followup_dummy_id>
1182 In-Reply-To: <dummy_test_message_id>
1183 X-Roundup-Name: Roundup issue tracker
1184 X-Roundup-Loop: hello
1185 X-Roundup-Issue-Status: chatting
1186 Content-Transfer-Encoding: quoted-printable
1189 John Doe <john@test.test> added the comment:
1191 This is a followup
1193 ----------
1194 nosy: +john
1195 status: unread -> chatting
1197 _______________________________________________________________________
1198 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1199 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1200 _______________________________________________________________________
1202 ''')
1204     def testFollowupNosyRecipients(self):
1205         self.doNewIssue()
1206         self.db.config.ADD_RECIPIENTS_TO_NOSY = 'yes'
1207         self._handle_mail('''Content-Type: text/plain;
1208   charset="iso-8859-1"
1209 From: richard@test.test
1210 To: issue_tracker@your.tracker.email.domain.example
1211 Cc: john@test.test
1212 Message-Id: <followup_dummy_id>
1213 In-Reply-To: <dummy_test_message_id>
1214 Subject: [issue1] Testing...
1216 This is a followup
1217 ''')
1218         self.compareMessages(self._get_mail(),
1219 '''FROM: roundup-admin@your.tracker.email.domain.example
1220 TO: chef@bork.bork.bork
1221 Content-Type: text/plain; charset="utf-8"
1222 Subject: [issue1] Testing...
1223 To: chef@bork.bork.bork
1224 From: richard <issue_tracker@your.tracker.email.domain.example>
1225 Reply-To: Roundup issue tracker
1226  <issue_tracker@your.tracker.email.domain.example>
1227 MIME-Version: 1.0
1228 Message-Id: <followup_dummy_id>
1229 In-Reply-To: <dummy_test_message_id>
1230 X-Roundup-Name: Roundup issue tracker
1231 X-Roundup-Loop: hello
1232 X-Roundup-Issue-Status: chatting
1233 Content-Transfer-Encoding: quoted-printable
1236 richard <richard@test.test> added the comment:
1238 This is a followup
1240 ----------
1241 nosy: +john
1242 status: unread -> chatting
1244 _______________________________________________________________________
1245 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1246 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1247 _______________________________________________________________________
1249 ''')
1251     def testFollowupNosyAuthorAndCopy(self):
1252         self.doNewIssue()
1253         self.db.config.ADD_AUTHOR_TO_NOSY = 'yes'
1254         self.db.config.MESSAGES_TO_AUTHOR = 'yes'
1255         self._handle_mail('''Content-Type: text/plain;
1256   charset="iso-8859-1"
1257 From: john@test.test
1258 To: issue_tracker@your.tracker.email.domain.example
1259 Message-Id: <followup_dummy_id>
1260 In-Reply-To: <dummy_test_message_id>
1261 Subject: [issue1] Testing...
1263 This is a followup
1264 ''')
1265         self.compareMessages(self._get_mail(),
1266 '''FROM: roundup-admin@your.tracker.email.domain.example
1267 TO: chef@bork.bork.bork, john@test.test, richard@test.test
1268 Content-Type: text/plain; charset="utf-8"
1269 Subject: [issue1] Testing...
1270 To: chef@bork.bork.bork, john@test.test, richard@test.test
1271 From: John Doe <issue_tracker@your.tracker.email.domain.example>
1272 Reply-To: Roundup issue tracker
1273  <issue_tracker@your.tracker.email.domain.example>
1274 MIME-Version: 1.0
1275 Message-Id: <followup_dummy_id>
1276 In-Reply-To: <dummy_test_message_id>
1277 X-Roundup-Name: Roundup issue tracker
1278 X-Roundup-Loop: hello
1279 X-Roundup-Issue-Status: chatting
1280 Content-Transfer-Encoding: quoted-printable
1283 John Doe <john@test.test> added the comment:
1285 This is a followup
1287 ----------
1288 nosy: +john
1289 status: unread -> chatting
1291 _______________________________________________________________________
1292 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1293 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1294 _______________________________________________________________________
1296 ''')
1298     def testFollowupNoNosyAuthor(self):
1299         self.doNewIssue()
1300         self.instance.config.ADD_AUTHOR_TO_NOSY = 'no'
1301         self._handle_mail('''Content-Type: text/plain;
1302   charset="iso-8859-1"
1303 From: john@test.test
1304 To: issue_tracker@your.tracker.email.domain.example
1305 Message-Id: <followup_dummy_id>
1306 In-Reply-To: <dummy_test_message_id>
1307 Subject: [issue1] Testing...
1309 This is a followup
1310 ''')
1311         self.compareMessages(self._get_mail(),
1312 '''FROM: roundup-admin@your.tracker.email.domain.example
1313 TO: chef@bork.bork.bork, richard@test.test
1314 Content-Type: text/plain; charset="utf-8"
1315 Subject: [issue1] Testing...
1316 To: chef@bork.bork.bork, richard@test.test
1317 From: John Doe <issue_tracker@your.tracker.email.domain.example>
1318 Reply-To: Roundup issue tracker
1319  <issue_tracker@your.tracker.email.domain.example>
1320 MIME-Version: 1.0
1321 Message-Id: <followup_dummy_id>
1322 In-Reply-To: <dummy_test_message_id>
1323 X-Roundup-Name: Roundup issue tracker
1324 X-Roundup-Loop: hello
1325 X-Roundup-Issue-Status: chatting
1326 Content-Transfer-Encoding: quoted-printable
1329 John Doe <john@test.test> added the comment:
1331 This is a followup
1333 ----------
1334 status: unread -> chatting
1336 _______________________________________________________________________
1337 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1338 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1339 _______________________________________________________________________
1341 ''')
1343     def testFollowupNoNosyRecipients(self):
1344         self.doNewIssue()
1345         self.instance.config.ADD_RECIPIENTS_TO_NOSY = 'no'
1346         self._handle_mail('''Content-Type: text/plain;
1347   charset="iso-8859-1"
1348 From: richard@test.test
1349 To: issue_tracker@your.tracker.email.domain.example
1350 Cc: john@test.test
1351 Message-Id: <followup_dummy_id>
1352 In-Reply-To: <dummy_test_message_id>
1353 Subject: [issue1] Testing...
1355 This is a followup
1356 ''')
1357         self.compareMessages(self._get_mail(),
1358 '''FROM: roundup-admin@your.tracker.email.domain.example
1359 TO: chef@bork.bork.bork
1360 Content-Type: text/plain; charset="utf-8"
1361 Subject: [issue1] Testing...
1362 To: chef@bork.bork.bork
1363 From: richard <issue_tracker@your.tracker.email.domain.example>
1364 Reply-To: Roundup issue tracker
1365  <issue_tracker@your.tracker.email.domain.example>
1366 MIME-Version: 1.0
1367 Message-Id: <followup_dummy_id>
1368 In-Reply-To: <dummy_test_message_id>
1369 X-Roundup-Name: Roundup issue tracker
1370 X-Roundup-Loop: hello
1371 X-Roundup-Issue-Status: chatting
1372 Content-Transfer-Encoding: quoted-printable
1375 richard <richard@test.test> added the comment:
1377 This is a followup
1379 ----------
1380 status: unread -> chatting
1382 _______________________________________________________________________
1383 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1384 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1385 _______________________________________________________________________
1387 ''')
1389     def testFollowupEmptyMessage(self):
1390         self.doNewIssue()
1392         self._handle_mail('''Content-Type: text/plain;
1393   charset="iso-8859-1"
1394 From: richard <richard@test.test>
1395 To: issue_tracker@your.tracker.email.domain.example
1396 Message-Id: <followup_dummy_id>
1397 In-Reply-To: <dummy_test_message_id>
1398 Subject: [issue1] Testing... [assignedto=mary; nosy=+john]
1400 ''')
1401         l = self.db.issue.get('1', 'nosy')
1402         l.sort()
1403         self.assertEqual(l, [self.chef_id, self.richard_id, self.mary_id,
1404             self.john_id])
1406         # should be no file created (ie. no message)
1407         assert not os.path.exists(SENDMAILDEBUG)
1409     def testFollowupEmptyMessageNoSubject(self):
1410         self.doNewIssue()
1412         self._handle_mail('''Content-Type: text/plain;
1413   charset="iso-8859-1"
1414 From: richard <richard@test.test>
1415 To: issue_tracker@your.tracker.email.domain.example
1416 Message-Id: <followup_dummy_id>
1417 In-Reply-To: <dummy_test_message_id>
1418 Subject: [issue1] [assignedto=mary; nosy=+john]
1420 ''')
1421         l = self.db.issue.get('1', 'nosy')
1422         l.sort()
1423         self.assertEqual(l, [self.chef_id, self.richard_id, self.mary_id,
1424             self.john_id])
1426         # should be no file created (ie. no message)
1427         assert not os.path.exists(SENDMAILDEBUG)
1429     def testNosyRemove(self):
1430         self.doNewIssue()
1432         self._handle_mail('''Content-Type: text/plain;
1433   charset="iso-8859-1"
1434 From: richard <richard@test.test>
1435 To: issue_tracker@your.tracker.email.domain.example
1436 Message-Id: <followup_dummy_id>
1437 In-Reply-To: <dummy_test_message_id>
1438 Subject: [issue1] Testing... [nosy=-richard]
1440 ''')
1441         l = self.db.issue.get('1', 'nosy')
1442         l.sort()
1443         self.assertEqual(l, [self.chef_id])
1445         # NO NOSY MESSAGE SHOULD BE SENT!
1446         assert not os.path.exists(SENDMAILDEBUG)
1448     def testNewUserAuthor(self):
1449         self.db.commit()
1450         l = self.db.user.list()
1451         l.sort()
1452         message = '''Content-Type: text/plain;
1453   charset="iso-8859-1"
1454 From: fubar <fubar@bork.bork.bork>
1455 To: issue_tracker@your.tracker.email.domain.example
1456 Message-Id: <dummy_test_message_id>
1457 Subject: [issue] Testing...
1459 This is a test submission of a new issue.
1460 '''
1461         self.db.security.role['anonymous'].permissions=[]
1462         anonid = self.db.user.lookup('anonymous')
1463         self.db.user.set(anonid, roles='Anonymous')
1464         try:
1465             self._handle_mail(message)
1466         except Unauthorized, value:
1467             body_diff = self.compareMessages(str(value), """
1468 You are not a registered user.
1470 Unknown address: fubar@bork.bork.bork
1471 """)
1472             assert not body_diff, body_diff
1473         else:
1474             raise AssertionError, "Unathorized not raised when handling mail"
1476         # Add Web Access role to anonymous, and try again to make sure
1477         # we get a "please register at:" message this time.
1478         p = [
1479             self.db.security.getPermission('Register', 'user'),
1480             self.db.security.getPermission('Web Access', None),
1481         ]
1482         self.db.security.role['anonymous'].permissions=p
1483         try:
1484             self._handle_mail(message)
1485         except Unauthorized, value:
1486             body_diff = self.compareMessages(str(value), """
1487 You are not a registered user. Please register at:
1489 http://tracker.example/cgi-bin/roundup.cgi/bugs/user?template=register
1491 ...before sending mail to the tracker.
1493 Unknown address: fubar@bork.bork.bork
1494 """)
1495             assert not body_diff, body_diff
1496         else:
1497             raise AssertionError, "Unathorized not raised when handling mail"
1499         # Make sure list of users is the same as before.
1500         m = self.db.user.list()
1501         m.sort()
1502         self.assertEqual(l, m)
1504         # now with the permission
1505         p = [
1506             self.db.security.getPermission('Register', 'user'),
1507             self.db.security.getPermission('Email Access', None),
1508         ]
1509         self.db.security.role['anonymous'].permissions=p
1510         self._handle_mail(message)
1511         m = self.db.user.list()
1512         m.sort()
1513         self.assertNotEqual(l, m)
1515     def testNewUserAuthorEncodedName(self):
1516         l = set(self.db.user.list())
1517         # From: name has Euro symbol in it
1518         message = '''Content-Type: text/plain;
1519   charset="iso-8859-1"
1520 From: =?utf8?b?SOKCrGxsbw==?= <fubar@bork.bork.bork>
1521 To: issue_tracker@your.tracker.email.domain.example
1522 Message-Id: <dummy_test_message_id>
1523 Subject: [issue] Testing...
1525 This is a test submission of a new issue.
1526 '''
1527         p = [
1528             self.db.security.getPermission('Register', 'user'),
1529             self.db.security.getPermission('Email Access', None),
1530             self.db.security.getPermission('Create', 'issue'),
1531             self.db.security.getPermission('Create', 'msg'),
1532         ]
1533         self.db.security.role['anonymous'].permissions = p
1534         self._handle_mail(message)
1535         m = set(self.db.user.list())
1536         new = list(m - l)[0]
1537         name = self.db.user.get(new, 'realname')
1538         self.assertEquals(name, 'H€llo')
1540     def testUnknownUser(self):
1541         l = set(self.db.user.list())
1542         message = '''Content-Type: text/plain;
1543   charset="iso-8859-1"
1544 From: Nonexisting User <nonexisting@bork.bork.bork>
1545 To: issue_tracker@your.tracker.email.domain.example
1546 Message-Id: <dummy_test_message_id>
1547 Subject: [issue] Testing nonexisting user...
1549 This is a test submission of a new issue.
1550 '''
1551         handler = self._create_mailgw(message)
1552         # we want a bounce message:
1553         handler.trapExceptions = 1
1554         ret = handler.main(StringIO(message))
1555         self.compareMessages(self._get_mail(),
1556 '''FROM: Roundup issue tracker <roundup-admin@your.tracker.email.domain.example>
1557 TO: nonexisting@bork.bork.bork
1558 From nobody Tue Jul 14 12:04:11 2009
1559 Content-Type: multipart/mixed; boundary="===============0639262320=="
1560 MIME-Version: 1.0
1561 Subject: Failed issue tracker submission
1562 To: nonexisting@bork.bork.bork
1563 From: Roundup issue tracker <roundup-admin@your.tracker.email.domain.example>
1564 Date: Tue, 14 Jul 2009 12:04:11 +0000
1565 Precedence: bulk
1566 X-Roundup-Name: Roundup issue tracker
1567 X-Roundup-Loop: hello
1568 X-Roundup-Version: 1.4.8
1569 MIME-Version: 1.0
1571 --===============0639262320==
1572 Content-Type: text/plain; charset="us-ascii"
1573 MIME-Version: 1.0
1574 Content-Transfer-Encoding: 7bit
1578 You are not a registered user. Please register at:
1580 http://tracker.example/cgi-bin/roundup.cgi/bugs/user?template=register
1582 ...before sending mail to the tracker.
1584 Unknown address: nonexisting@bork.bork.bork
1586 --===============0639262320==
1587 Content-Type: text/plain; charset="us-ascii"
1588 MIME-Version: 1.0
1589 Content-Transfer-Encoding: 7bit
1591 Content-Type: text/plain;
1592   charset="iso-8859-1"
1593 From: Nonexisting User <nonexisting@bork.bork.bork>
1594 To: issue_tracker@your.tracker.email.domain.example
1595 Message-Id: <dummy_test_message_id>
1596 Subject: [issue] Testing nonexisting user...
1598 This is a test submission of a new issue.
1600 --===============0639262320==--
1601 ''')
1603     def testEnc01(self):
1604         self.db.user.set(self.mary_id,
1605             realname='\xe4\xf6\xfc\xc4\xd6\xdc\xdf, Mary'.decode
1606             ('latin-1').encode('utf-8'))
1607         self.doNewIssue()
1608         self._handle_mail('''Content-Type: text/plain;
1609   charset="iso-8859-1"
1610 From: mary <mary@test.test>
1611 To: issue_tracker@your.tracker.email.domain.example
1612 Message-Id: <followup_dummy_id>
1613 In-Reply-To: <dummy_test_message_id>
1614 Subject: [issue1] Testing...
1615 Content-Type: text/plain;
1616         charset="iso-8859-1"
1617 Content-Transfer-Encoding: quoted-printable
1619 A message with encoding (encoded oe =F6)
1621 ''')
1622         self.compareMessages(self._get_mail(),
1623 '''FROM: roundup-admin@your.tracker.email.domain.example
1624 TO: chef@bork.bork.bork, richard@test.test
1625 Content-Type: text/plain; charset="utf-8"
1626 Subject: [issue1] Testing...
1627 To: chef@bork.bork.bork, richard@test.test
1628 From: =?utf-8?b?w6TDtsO8w4TDlsOcw58sIE1hcnk=?=
1629  <issue_tracker@your.tracker.email.domain.example>
1630 Reply-To: Roundup issue tracker
1631  <issue_tracker@your.tracker.email.domain.example>
1632 MIME-Version: 1.0
1633 Message-Id: <followup_dummy_id>
1634 In-Reply-To: <dummy_test_message_id>
1635 X-Roundup-Name: Roundup issue tracker
1636 X-Roundup-Loop: hello
1637 X-Roundup-Issue-Status: chatting
1638 Content-Transfer-Encoding: quoted-printable
1641 =C3=A4=C3=B6=C3=BC=C3=84=C3=96=C3=9C=C3=9F, Mary <mary@test.test> added the=
1642  comment:
1644 A message with encoding (encoded oe =C3=B6)
1646 ----------
1647 status: unread -> chatting
1649 _______________________________________________________________________
1650 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1651 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1652 _______________________________________________________________________
1653 ''')
1655     def testEncNonUTF8(self):
1656         self.doNewIssue()
1657         self.instance.config.EMAIL_CHARSET = 'iso-8859-1'
1658         self._handle_mail('''Content-Type: text/plain;
1659   charset="iso-8859-1"
1660 From: mary <mary@test.test>
1661 To: issue_tracker@your.tracker.email.domain.example
1662 Message-Id: <followup_dummy_id>
1663 In-Reply-To: <dummy_test_message_id>
1664 Subject: [issue1] Testing...
1665 Content-Type: text/plain;
1666         charset="iso-8859-1"
1667 Content-Transfer-Encoding: quoted-printable
1669 A message with encoding (encoded oe =F6)
1671 ''')
1672         self.compareMessages(self._get_mail(),
1673 '''FROM: roundup-admin@your.tracker.email.domain.example
1674 TO: chef@bork.bork.bork, richard@test.test
1675 Content-Type: text/plain; charset="iso-8859-1"
1676 Subject: [issue1] Testing...
1677 To: chef@bork.bork.bork, richard@test.test
1678 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
1679 Reply-To: Roundup issue tracker
1680  <issue_tracker@your.tracker.email.domain.example>
1681 MIME-Version: 1.0
1682 Message-Id: <followup_dummy_id>
1683 In-Reply-To: <dummy_test_message_id>
1684 X-Roundup-Name: Roundup issue tracker
1685 X-Roundup-Loop: hello
1686 X-Roundup-Issue-Status: chatting
1687 Content-Transfer-Encoding: quoted-printable
1690 Contrary, Mary <mary@test.test> added the comment:
1692 A message with encoding (encoded oe =F6)
1694 ----------
1695 status: unread -> chatting
1697 _______________________________________________________________________
1698 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1699 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1700 _______________________________________________________________________
1701 ''')
1704     def testMultipartEnc01(self):
1705         self.doNewIssue()
1706         self._handle_mail('''Content-Type: text/plain;
1707   charset="iso-8859-1"
1708 From: mary <mary@test.test>
1709 To: issue_tracker@your.tracker.email.domain.example
1710 Message-Id: <followup_dummy_id>
1711 In-Reply-To: <dummy_test_message_id>
1712 Subject: [issue1] Testing...
1713 Content-Type: multipart/mixed;
1714         boundary="----_=_NextPart_000_01"
1716 This message is in MIME format. Since your mail reader does not understand
1717 this format, some or all of this message may not be legible.
1719 ------_=_NextPart_000_01
1720 Content-Type: text/plain;
1721         charset="iso-8859-1"
1722 Content-Transfer-Encoding: quoted-printable
1724 A message with first part encoded (encoded oe =F6)
1726 ''')
1727         self.compareMessages(self._get_mail(),
1728 '''FROM: roundup-admin@your.tracker.email.domain.example
1729 TO: chef@bork.bork.bork, richard@test.test
1730 Content-Type: text/plain; charset="utf-8"
1731 Subject: [issue1] Testing...
1732 To: chef@bork.bork.bork, richard@test.test
1733 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
1734 Reply-To: Roundup issue tracker
1735  <issue_tracker@your.tracker.email.domain.example>
1736 MIME-Version: 1.0
1737 Message-Id: <followup_dummy_id>
1738 In-Reply-To: <dummy_test_message_id>
1739 X-Roundup-Name: Roundup issue tracker
1740 X-Roundup-Loop: hello
1741 X-Roundup-Issue-Status: chatting
1742 Content-Transfer-Encoding: quoted-printable
1745 Contrary, Mary <mary@test.test> added the comment:
1747 A message with first part encoded (encoded oe =C3=B6)
1749 ----------
1750 status: unread -> chatting
1752 _______________________________________________________________________
1753 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1754 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1755 _______________________________________________________________________
1756 ''')
1758     def testContentDisposition(self):
1759         self.doNewIssue()
1760         self._handle_mail('''Content-Type: text/plain;
1761   charset="iso-8859-1"
1762 From: mary <mary@test.test>
1763 To: issue_tracker@your.tracker.email.domain.example
1764 Message-Id: <followup_dummy_id>
1765 In-Reply-To: <dummy_test_message_id>
1766 Subject: [issue1] Testing...
1767 Content-Type: multipart/mixed; boundary="bCsyhTFzCvuiizWE"
1768 Content-Disposition: inline
1771 --bCsyhTFzCvuiizWE
1772 Content-Type: text/plain; charset=us-ascii
1773 Content-Disposition: inline
1775 test attachment binary
1777 --bCsyhTFzCvuiizWE
1778 Content-Type: application/octet-stream
1779 Content-Disposition: attachment; filename="main.dvi"
1780 Content-Transfer-Encoding: base64
1782 SnVzdCBhIHRlc3QgAQo=
1784 --bCsyhTFzCvuiizWE--
1785 ''')
1786         messages = self.db.issue.get('1', 'messages')
1787         messages.sort()
1788         file = self.db.file.getnode (self.db.msg.get(messages[-1], 'files')[0])
1789         self.assertEqual(file.name, 'main.dvi')
1790         self.assertEqual(file.content, 'Just a test \001\n')
1792     def testFollowupStupidQuoting(self):
1793         self.doNewIssue()
1795         self._handle_mail('''Content-Type: text/plain;
1796   charset="iso-8859-1"
1797 From: richard <richard@test.test>
1798 To: issue_tracker@your.tracker.email.domain.example
1799 Message-Id: <followup_dummy_id>
1800 In-Reply-To: <dummy_test_message_id>
1801 Subject: Re: "[issue1] Testing... "
1803 This is a followup
1804 ''')
1805         self.compareMessages(self._get_mail(),
1806 '''FROM: roundup-admin@your.tracker.email.domain.example
1807 TO: chef@bork.bork.bork
1808 Content-Type: text/plain; charset="utf-8"
1809 Subject: [issue1] Testing...
1810 To: chef@bork.bork.bork
1811 From: richard <issue_tracker@your.tracker.email.domain.example>
1812 Reply-To: Roundup issue tracker
1813  <issue_tracker@your.tracker.email.domain.example>
1814 MIME-Version: 1.0
1815 Message-Id: <followup_dummy_id>
1816 In-Reply-To: <dummy_test_message_id>
1817 X-Roundup-Name: Roundup issue tracker
1818 X-Roundup-Loop: hello
1819 X-Roundup-Issue-Status: chatting
1820 Content-Transfer-Encoding: quoted-printable
1823 richard <richard@test.test> added the comment:
1825 This is a followup
1827 ----------
1828 status: unread -> chatting
1830 _______________________________________________________________________
1831 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1832 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1833 _______________________________________________________________________
1834 ''')
1836     def testEmailQuoting(self):
1837         self.instance.config.EMAIL_KEEP_QUOTED_TEXT = 'no'
1838         self.innerTestQuoting('''This is a followup
1839 ''')
1841     def testEmailQuotingRemove(self):
1842         self.instance.config.EMAIL_KEEP_QUOTED_TEXT = 'yes'
1843         self.innerTestQuoting('''Blah blah wrote:
1844 > Blah bklaskdfj sdf asdf jlaskdf skj sdkfjl asdf
1845 >  skdjlkjsdfalsdkfjasdlfkj dlfksdfalksd fj
1848 This is a followup
1849 ''')
1851     def innerTestQuoting(self, expect):
1852         nodeid = self.doNewIssue()
1854         messages = self.db.issue.get(nodeid, 'messages')
1856         self._handle_mail('''Content-Type: text/plain;
1857   charset="iso-8859-1"
1858 From: richard <richard@test.test>
1859 To: issue_tracker@your.tracker.email.domain.example
1860 Message-Id: <followup_dummy_id>
1861 In-Reply-To: <dummy_test_message_id>
1862 Subject: Re: [issue1] Testing...
1864 Blah blah wrote:
1865 > Blah bklaskdfj sdf asdf jlaskdf skj sdkfjl asdf
1866 >  skdjlkjsdfalsdkfjasdlfkj dlfksdfalksd fj
1869 This is a followup
1870 ''')
1871         # figure the new message id
1872         newmessages = self.db.issue.get(nodeid, 'messages')
1873         for msg in messages:
1874             newmessages.remove(msg)
1875         messageid = newmessages[0]
1877         self.compareMessages(self.db.msg.get(messageid, 'content'), expect)
1879     def testUserLookup(self):
1880         i = self.db.user.create(username='user1', address='user1@foo.com')
1881         self.assertEqual(uidFromAddress(self.db, ('', 'user1@foo.com'), 0), i)
1882         self.assertEqual(uidFromAddress(self.db, ('', 'USER1@foo.com'), 0), i)
1883         i = self.db.user.create(username='user2', address='USER2@foo.com')
1884         self.assertEqual(uidFromAddress(self.db, ('', 'USER2@foo.com'), 0), i)
1885         self.assertEqual(uidFromAddress(self.db, ('', 'user2@foo.com'), 0), i)
1887     def testUserAlternateLookup(self):
1888         i = self.db.user.create(username='user1', address='user1@foo.com',
1889                                 alternate_addresses='user1@bar.com')
1890         self.assertEqual(uidFromAddress(self.db, ('', 'user1@bar.com'), 0), i)
1891         self.assertEqual(uidFromAddress(self.db, ('', 'USER1@bar.com'), 0), i)
1893     def testUserCreate(self):
1894         i = uidFromAddress(self.db, ('', 'user@foo.com'), 1)
1895         self.assertNotEqual(uidFromAddress(self.db, ('', 'user@bar.com'), 1), i)
1897     def testRFC2822(self):
1898         ascii_header = "[issue243] This is a \"test\" - with 'quotation' marks"
1899         unicode_header = '[issue244] \xd0\xb0\xd0\xbd\xd0\xb4\xd1\x80\xd0\xb5\xd0\xb9'
1900         unicode_encoded = '=?utf-8?q?[issue244]_=D0=B0=D0=BD=D0=B4=D1=80=D0=B5=D0=B9?='
1901         self.assertEqual(rfc2822.encode_header(ascii_header), ascii_header)
1902         self.assertEqual(rfc2822.encode_header(unicode_header), unicode_encoded)
1904     def testRegistrationConfirmation(self):
1905         otk = "Aj4euk4LZSAdwePohj90SME5SpopLETL"
1906         self.db.getOTKManager().set(otk, username='johannes')
1907         self._handle_mail('''Content-Type: text/plain;
1908   charset="iso-8859-1"
1909 From: Chef <chef@bork.bork.bork>
1910 To: issue_tracker@your.tracker.email.domain.example
1911 Cc: richard@test.test
1912 Message-Id: <dummy_test_message_id>
1913 Subject: Re: Complete your registration to Roundup issue tracker
1914  -- key %s
1916 This is a test confirmation of registration.
1917 ''' % otk)
1918         self.db.user.lookup('johannes')
1920     def testFollowupOnNonIssue(self):
1921         self.db.keyword.create(name='Foo')
1922         self._handle_mail('''Content-Type: text/plain;
1923   charset="iso-8859-1"
1924 From: richard <richard@test.test>
1925 To: issue_tracker@your.tracker.email.domain.example
1926 Message-Id: <followup_dummy_id>
1927 In-Reply-To: <dummy_test_message_id>
1928 Subject: [keyword1] Testing... [name=Bar]
1930 ''')
1931         self.assertEqual(self.db.keyword.get('1', 'name'), 'Bar')
1933     def testResentFrom(self):
1934         nodeid = self._handle_mail('''Content-Type: text/plain;
1935   charset="iso-8859-1"
1936 From: Chef <chef@bork.bork.bork>
1937 Resent-From: mary <mary@test.test>
1938 To: issue_tracker@your.tracker.email.domain.example
1939 Cc: richard@test.test
1940 Message-Id: <dummy_test_message_id>
1941 Subject: [issue] Testing...
1943 This is a test submission of a new issue.
1944 ''')
1945         assert not os.path.exists(SENDMAILDEBUG)
1946         l = self.db.issue.get(nodeid, 'nosy')
1947         l.sort()
1948         self.assertEqual(l, [self.richard_id, self.mary_id])
1949         return nodeid
1951     def testDejaVu(self):
1952         self.assertRaises(IgnoreLoop, self._handle_mail,
1953             '''Content-Type: text/plain;
1954   charset="iso-8859-1"
1955 From: Chef <chef@bork.bork.bork>
1956 X-Roundup-Loop: hello
1957 To: issue_tracker@your.tracker.email.domain.example
1958 Cc: richard@test.test
1959 Message-Id: <dummy_test_message_id>
1960 Subject: Re: [issue] Testing...
1962 Hi, I've been mis-configured to loop messages back to myself.
1963 ''')
1965     def testItsBulkStupid(self):
1966         self.assertRaises(IgnoreBulk, self._handle_mail,
1967             '''Content-Type: text/plain;
1968   charset="iso-8859-1"
1969 From: Chef <chef@bork.bork.bork>
1970 Precedence: bulk
1971 To: issue_tracker@your.tracker.email.domain.example
1972 Cc: richard@test.test
1973 Message-Id: <dummy_test_message_id>
1974 Subject: Re: [issue] Testing...
1976 Hi, I'm on holidays, and this is a dumb auto-responder.
1977 ''')
1979     def testAutoReplyEmailsAreIgnored(self):
1980         self.assertRaises(IgnoreBulk, self._handle_mail,
1981             '''Content-Type: text/plain;
1982   charset="iso-8859-1"
1983 From: Chef <chef@bork.bork.bork>
1984 To: issue_tracker@your.tracker.email.domain.example
1985 Cc: richard@test.test
1986 Message-Id: <dummy_test_message_id>
1987 Subject: Re: [issue] Out of office AutoReply: Back next week
1989 Hi, I am back in the office next week
1990 ''')
1992     def testNoSubject(self):
1993         self.assertRaises(MailUsageError, self._handle_mail,
1994             '''Content-Type: text/plain;
1995   charset="iso-8859-1"
1996 From: Chef <chef@bork.bork.bork>
1997 To: issue_tracker@your.tracker.email.domain.example
1998 Cc: richard@test.test
1999 Reply-To: chef@bork.bork.bork
2000 Message-Id: <dummy_test_message_id>
2002 ''')
2004     #
2005     # TEST FOR INVALID DESIGNATOR HANDLING
2006     #
2007     def testInvalidDesignator(self):
2008         self.assertRaises(MailUsageError, self._handle_mail,
2009             '''Content-Type: text/plain;
2010   charset="iso-8859-1"
2011 From: Chef <chef@bork.bork.bork>
2012 To: issue_tracker@your.tracker.email.domain.example
2013 Subject: [frobulated] testing
2014 Cc: richard@test.test
2015 Reply-To: chef@bork.bork.bork
2016 Message-Id: <dummy_test_message_id>
2018 ''')
2019         self.assertRaises(MailUsageError, self._handle_mail,
2020             '''Content-Type: text/plain;
2021   charset="iso-8859-1"
2022 From: Chef <chef@bork.bork.bork>
2023 To: issue_tracker@your.tracker.email.domain.example
2024 Subject: [issue12345] testing
2025 Cc: richard@test.test
2026 Reply-To: chef@bork.bork.bork
2027 Message-Id: <dummy_test_message_id>
2029 ''')
2031     def testInvalidClassLoose(self):
2032         self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'loose'
2033         nodeid = self._handle_mail('''Content-Type: text/plain;
2034   charset="iso-8859-1"
2035 From: Chef <chef@bork.bork.bork>
2036 To: issue_tracker@your.tracker.email.domain.example
2037 Subject: [frobulated] testing
2038 Cc: richard@test.test
2039 Reply-To: chef@bork.bork.bork
2040 Message-Id: <dummy_test_message_id>
2042 ''')
2043         assert not os.path.exists(SENDMAILDEBUG)
2044         self.assertEqual(self.db.issue.get(nodeid, 'title'),
2045             '[frobulated] testing')
2047     def testInvalidClassLooseReply(self):
2048         self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'loose'
2049         nodeid = self._handle_mail('''Content-Type: text/plain;
2050   charset="iso-8859-1"
2051 From: Chef <chef@bork.bork.bork>
2052 To: issue_tracker@your.tracker.email.domain.example
2053 Subject: Re: [frobulated] testing
2054 Cc: richard@test.test
2055 Reply-To: chef@bork.bork.bork
2056 Message-Id: <dummy_test_message_id>
2058 ''')
2059         assert not os.path.exists(SENDMAILDEBUG)
2060         self.assertEqual(self.db.issue.get(nodeid, 'title'),
2061             '[frobulated] testing')
2063     def testInvalidClassLoose(self):
2064         self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'loose'
2065         nodeid = self._handle_mail('''Content-Type: text/plain;
2066   charset="iso-8859-1"
2067 From: Chef <chef@bork.bork.bork>
2068 To: issue_tracker@your.tracker.email.domain.example
2069 Subject: [issue1234] testing
2070 Cc: richard@test.test
2071 Reply-To: chef@bork.bork.bork
2072 Message-Id: <dummy_test_message_id>
2074 ''')
2075         assert not os.path.exists(SENDMAILDEBUG)
2076         self.assertEqual(self.db.issue.get(nodeid, 'title'),
2077             '[issue1234] testing')
2079     def testClassLooseOK(self):
2080         self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'loose'
2081         self.db.keyword.create(name='Foo')
2082         nodeid = self._handle_mail('''Content-Type: text/plain;
2083   charset="iso-8859-1"
2084 From: Chef <chef@bork.bork.bork>
2085 To: issue_tracker@your.tracker.email.domain.example
2086 Subject: [keyword1] Testing... [name=Bar]
2087 Cc: richard@test.test
2088 Reply-To: chef@bork.bork.bork
2089 Message-Id: <dummy_test_message_id>
2091 ''')
2092         assert not os.path.exists(SENDMAILDEBUG)
2093         self.assertEqual(self.db.keyword.get('1', 'name'), 'Bar')
2095     def testClassStrictInvalid(self):
2096         self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'strict'
2097         self.instance.config.MAILGW_DEFAULT_CLASS = ''
2099         message = '''Content-Type: text/plain;
2100   charset="iso-8859-1"
2101 From: Chef <chef@bork.bork.bork>
2102 To: issue_tracker@your.tracker.email.domain.example
2103 Subject: Testing...
2104 Cc: richard@test.test
2105 Reply-To: chef@bork.bork.bork
2106 Message-Id: <dummy_test_message_id>
2108 '''
2109         self.assertRaises(MailUsageError, self._handle_mail, message)
2111     def testClassStrictValid(self):
2112         self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'strict'
2113         self.instance.config.MAILGW_DEFAULT_CLASS = ''
2115         nodeid = self._handle_mail('''Content-Type: text/plain;
2116   charset="iso-8859-1"
2117 From: Chef <chef@bork.bork.bork>
2118 To: issue_tracker@your.tracker.email.domain.example
2119 Subject: [issue] Testing...
2120 Cc: richard@test.test
2121 Reply-To: chef@bork.bork.bork
2122 Message-Id: <dummy_test_message_id>
2124 ''')
2126         assert not os.path.exists(SENDMAILDEBUG)
2127         self.assertEqual(self.db.issue.get(nodeid, 'title'), 'Testing...')
2129     #
2130     # TEST FOR INVALID COMMANDS HANDLING
2131     #
2132     def testInvalidCommands(self):
2133         self.assertRaises(MailUsageError, self._handle_mail,
2134             '''Content-Type: text/plain;
2135   charset="iso-8859-1"
2136 From: Chef <chef@bork.bork.bork>
2137 To: issue_tracker@your.tracker.email.domain.example
2138 Subject: testing [frobulated]
2139 Cc: richard@test.test
2140 Reply-To: chef@bork.bork.bork
2141 Message-Id: <dummy_test_message_id>
2143 ''')
2145     def testInvalidCommandPassthrough(self):
2146         self.instance.config.MAILGW_SUBJECT_SUFFIX_PARSING = 'none'
2147         nodeid = self._handle_mail('''Content-Type: text/plain;
2148   charset="iso-8859-1"
2149 From: Chef <chef@bork.bork.bork>
2150 To: issue_tracker@your.tracker.email.domain.example
2151 Subject: testing [frobulated]
2152 Cc: richard@test.test
2153 Reply-To: chef@bork.bork.bork
2154 Message-Id: <dummy_test_message_id>
2156 ''')
2157         assert not os.path.exists(SENDMAILDEBUG)
2158         self.assertEqual(self.db.issue.get(nodeid, 'title'),
2159             'testing [frobulated]')
2161     def testInvalidCommandPassthroughLoose(self):
2162         self.instance.config.MAILGW_SUBJECT_SUFFIX_PARSING = 'loose'
2163         nodeid = self._handle_mail('''Content-Type: text/plain;
2164   charset="iso-8859-1"
2165 From: Chef <chef@bork.bork.bork>
2166 To: issue_tracker@your.tracker.email.domain.example
2167 Subject: testing [frobulated]
2168 Cc: richard@test.test
2169 Reply-To: chef@bork.bork.bork
2170 Message-Id: <dummy_test_message_id>
2172 ''')
2173         assert not os.path.exists(SENDMAILDEBUG)
2174         self.assertEqual(self.db.issue.get(nodeid, 'title'),
2175             'testing [frobulated]')
2177     def testInvalidCommandPassthroughLooseOK(self):
2178         self.instance.config.MAILGW_SUBJECT_SUFFIX_PARSING = 'loose'
2179         nodeid = self._handle_mail('''Content-Type: text/plain;
2180   charset="iso-8859-1"
2181 From: Chef <chef@bork.bork.bork>
2182 To: issue_tracker@your.tracker.email.domain.example
2183 Subject: testing [assignedto=mary]
2184 Cc: richard@test.test
2185 Reply-To: chef@bork.bork.bork
2186 Message-Id: <dummy_test_message_id>
2188 ''')
2189         assert not os.path.exists(SENDMAILDEBUG)
2190         self.assertEqual(self.db.issue.get(nodeid, 'title'), 'testing')
2191         self.assertEqual(self.db.issue.get(nodeid, 'assignedto'), self.mary_id)
2193     def testCommandDelimiters(self):
2194         self.instance.config.MAILGW_SUBJECT_SUFFIX_DELIMITERS = '{}'
2195         nodeid = self._handle_mail('''Content-Type: text/plain;
2196   charset="iso-8859-1"
2197 From: Chef <chef@bork.bork.bork>
2198 To: issue_tracker@your.tracker.email.domain.example
2199 Subject: testing {assignedto=mary}
2200 Cc: richard@test.test
2201 Reply-To: chef@bork.bork.bork
2202 Message-Id: <dummy_test_message_id>
2204 ''')
2205         assert not os.path.exists(SENDMAILDEBUG)
2206         self.assertEqual(self.db.issue.get(nodeid, 'title'), 'testing')
2207         self.assertEqual(self.db.issue.get(nodeid, 'assignedto'), self.mary_id)
2209     def testPrefixDelimiters(self):
2210         self.instance.config.MAILGW_SUBJECT_SUFFIX_DELIMITERS = '{}'
2211         self.db.keyword.create(name='Foo')
2212         self._handle_mail('''Content-Type: text/plain;
2213   charset="iso-8859-1"
2214 From: richard <richard@test.test>
2215 To: issue_tracker@your.tracker.email.domain.example
2216 Message-Id: <followup_dummy_id>
2217 In-Reply-To: <dummy_test_message_id>
2218 Subject: {keyword1} Testing... {name=Bar}
2220 ''')
2221         assert not os.path.exists(SENDMAILDEBUG)
2222         self.assertEqual(self.db.keyword.get('1', 'name'), 'Bar')
2224     def testCommandDelimitersIgnore(self):
2225         self.instance.config.MAILGW_SUBJECT_SUFFIX_DELIMITERS = '{}'
2226         nodeid = self._handle_mail('''Content-Type: text/plain;
2227   charset="iso-8859-1"
2228 From: Chef <chef@bork.bork.bork>
2229 To: issue_tracker@your.tracker.email.domain.example
2230 Subject: testing [assignedto=mary]
2231 Cc: richard@test.test
2232 Reply-To: chef@bork.bork.bork
2233 Message-Id: <dummy_test_message_id>
2235 ''')
2236         assert not os.path.exists(SENDMAILDEBUG)
2237         self.assertEqual(self.db.issue.get(nodeid, 'title'),
2238             'testing [assignedto=mary]')
2239         self.assertEqual(self.db.issue.get(nodeid, 'assignedto'), None)
2241     def testReplytoMatch(self):
2242         self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'loose'
2243         nodeid = self.doNewIssue()
2244         nodeid2 = self._handle_mail('''Content-Type: text/plain;
2245   charset="iso-8859-1"
2246 From: Chef <chef@bork.bork.bork>
2247 To: issue_tracker@your.tracker.email.domain.example
2248 Message-Id: <dummy_test_message_id2>
2249 In-Reply-To: <dummy_test_message_id>
2250 Subject: Testing...
2252 Followup message.
2253 ''')
2255         nodeid3 = self._handle_mail('''Content-Type: text/plain;
2256   charset="iso-8859-1"
2257 From: Chef <chef@bork.bork.bork>
2258 To: issue_tracker@your.tracker.email.domain.example
2259 Message-Id: <dummy_test_message_id3>
2260 In-Reply-To: <dummy_test_message_id2>
2261 Subject: Testing...
2263 Yet another message in the same thread/issue.
2264 ''')
2266         self.assertEqual(nodeid, nodeid2)
2267         self.assertEqual(nodeid, nodeid3)
2269     def testHelpSubject(self):
2270         message = '''Content-Type: text/plain;
2271   charset="iso-8859-1"
2272 From: Chef <chef@bork.bork.bork>
2273 To: issue_tracker@your.tracker.email.domain.example
2274 Message-Id: <dummy_test_message_id2>
2275 In-Reply-To: <dummy_test_message_id>
2276 Subject: hElp
2279 '''
2280         self.assertRaises(MailUsageHelp, self._handle_mail, message)
2282     def testMaillistSubject(self):
2283         self.instance.config.MAILGW_SUBJECT_SUFFIX_DELIMITERS = '[]'
2284         self.db.keyword.create(name='Foo')
2285         self._handle_mail('''Content-Type: text/plain;
2286   charset="iso-8859-1"
2287 From: Chef <chef@bork.bork.bork>
2288 To: issue_tracker@your.tracker.email.domain.example
2289 Subject: [mailinglist-name] [keyword1] Testing.. [name=Bar]
2290 Cc: richard@test.test
2291 Reply-To: chef@bork.bork.bork
2292 Message-Id: <dummy_test_message_id>
2294 ''')
2296         assert not os.path.exists(SENDMAILDEBUG)
2297         self.assertEqual(self.db.keyword.get('1', 'name'), 'Bar')
2299     def testUnknownPrefixSubject(self):
2300         self.db.keyword.create(name='Foo')
2301         self._handle_mail('''Content-Type: text/plain;
2302   charset="iso-8859-1"
2303 From: Chef <chef@bork.bork.bork>
2304 To: issue_tracker@your.tracker.email.domain.example
2305 Subject: VeryStrangeRe: [keyword1] Testing.. [name=Bar]
2306 Cc: richard@test.test
2307 Reply-To: chef@bork.bork.bork
2308 Message-Id: <dummy_test_message_id>
2310 ''')
2312         assert not os.path.exists(SENDMAILDEBUG)
2313         self.assertEqual(self.db.keyword.get('1', 'name'), 'Bar')
2315     def testOneCharSubject(self):
2316         message = '''Content-Type: text/plain;
2317   charset="iso-8859-1"
2318 From: Chef <chef@bork.bork.bork>
2319 To: issue_tracker@your.tracker.email.domain.example
2320 Subject: b
2321 Cc: richard@test.test
2322 Reply-To: chef@bork.bork.bork
2323 Message-Id: <dummy_test_message_id>
2325 '''
2326         try:
2327             self._handle_mail(message)
2328         except MailUsageError:
2329             self.fail('MailUsageError raised')
2331     def testIssueidLast(self):
2332         nodeid1 = self.doNewIssue()
2333         nodeid2 = self._handle_mail('''Content-Type: text/plain;
2334   charset="iso-8859-1"
2335 From: mary <mary@test.test>
2336 To: issue_tracker@your.tracker.email.domain.example
2337 Message-Id: <followup_dummy_id>
2338 In-Reply-To: <dummy_test_message_id>
2339 Subject: New title [issue1]
2341 This is a second followup
2342 ''')
2344         assert nodeid1 == nodeid2
2345         self.assertEqual(self.db.issue.get(nodeid2, 'title'), "Testing...")
2347     def testSecurityMessagePermissionContent(self):
2348         id = self.doNewIssue()
2349         issue = self.db.issue.getnode (id)
2350         self.db.security.addRole(name='Nomsg')
2351         self.db.security.addPermissionToRole('Nomsg', 'Email Access')
2352         for cl in 'issue', 'file', 'keyword':
2353             for p in 'View', 'Edit', 'Create':
2354                 self.db.security.addPermissionToRole('Nomsg', p, cl)
2355         self.db.user.set(self.mary_id, roles='Nomsg')
2356         nodeid = self._handle_mail('''Content-Type: text/plain;
2357   charset="iso-8859-1"
2358 From: Chef <chef@bork.bork.bork>
2359 To: issue_tracker@your.tracker.email.domain.example
2360 Message-Id: <dummy_test_message_id_2>
2361 Subject: [issue%(id)s] Testing... [nosy=+mary]
2363 Just a test reply
2364 '''%locals())
2365         assert os.path.exists(SENDMAILDEBUG)
2366         self.compareMessages(self._get_mail(),
2367 '''FROM: roundup-admin@your.tracker.email.domain.example
2368 TO: chef@bork.bork.bork, richard@test.test
2369 Content-Type: text/plain; charset="utf-8"
2370 Subject: [issue1] Testing...
2371 To: richard@test.test
2372 From: "Bork, Chef" <issue_tracker@your.tracker.email.domain.example>
2373 Reply-To: Roundup issue tracker
2374  <issue_tracker@your.tracker.email.domain.example>
2375 MIME-Version: 1.0
2376 Message-Id: <dummy_test_message_id_2>
2377 In-Reply-To: <dummy_test_message_id>
2378 X-Roundup-Name: Roundup issue tracker
2379 X-Roundup-Loop: hello
2380 X-Roundup-Issue-Status: chatting
2381 Content-Transfer-Encoding: quoted-printable
2384 Bork, Chef <chef@bork.bork.bork> added the comment:
2386 Just a test reply
2388 ----------
2389 nosy: +mary
2390 status: unread -> chatting
2392 _______________________________________________________________________
2393 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
2394 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
2395 _______________________________________________________________________
2396 ''')
2398     def testOutlookAttachment(self):
2399         message = '''X-MimeOLE: Produced By Microsoft Exchange V6.5
2400 Content-class: urn:content-classes:message
2401 MIME-Version: 1.0
2402 Content-Type: multipart/mixed;
2403         boundary="----_=_NextPart_001_01CACA65.40A51CBC"
2404 Subject: Example of a failed outlook attachment e-mail
2405 Date: Tue, 23 Mar 2010 01:43:44 -0700
2406 Message-ID: <CA37F17219784343816CA6613D2E339205E7D0F9@nrcwstexb1.nrc.ca>
2407 X-MS-Has-Attach: yes
2408 X-MS-TNEF-Correlator: 
2409 Thread-Topic: Example of a failed outlook attachment e-mail
2410 Thread-Index: AcrKJo/t3pUBBwTpSwWNE3LE67UBDQ==
2411 From: "Hugh" <richard@test.test>
2412 To: <richard@test.test>
2413 X-OriginalArrivalTime: 23 Mar 2010 08:45:57.0350 (UTC) FILETIME=[41893860:01CACA65]
2415 This is a multi-part message in MIME format.
2417 ------_=_NextPart_001_01CACA65.40A51CBC
2418 Content-Type: multipart/alternative;
2419         boundary="----_=_NextPart_002_01CACA65.40A51CBC"
2422 ------_=_NextPart_002_01CACA65.40A51CBC
2423 Content-Type: text/plain;
2424         charset="us-ascii"
2425 Content-Transfer-Encoding: quoted-printable
2428 Hi Richard,
2430 I suppose this isn't the exact message that was sent but is a resend of
2431 one of my trial messages that failed.  For your benefit I changed the
2432 subject line and am adding these words to the message body.  Should
2433 still be as problematic, but if you like I can resend an exact copy of a
2434 failed message changing nothing except putting your address instead of
2435 our tracker.
2437 Thanks very much for taking time to look into this.  Much appreciated.
2439  <<battery backup>>=20
2441 ------_=_NextPart_002_01CACA65.40A51CBC
2442 Content-Type: text/html;
2443         charset="us-ascii"
2444 Content-Transfer-Encoding: quoted-printable
2446 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
2447 <HTML>
2448 <HEAD>
2449 <META HTTP-EQUIV=3D"Content-Type" CONTENT=3D"text/html; =
2450 charset=3Dus-ascii">
2451 <META NAME=3D"Generator" CONTENT=3D"MS Exchange Server version =
2452 6.5.7654.12">
2453 <TITLE>Example of a failed outlook attachment e-mail</TITLE>
2454 </HEAD>
2455 <BODY>
2456 <!-- Converted from text/rtf format -->
2457 <BR>
2459 <P><FONT SIZE=3D2 FACE=3D"Arial">Hi Richard,</FONT>
2460 </P>
2462 <P><FONT SIZE=3D2 FACE=3D"Arial">I suppose this isn't the exact message =
2463 that was sent but is a resend of one of my trial messages that =
2464 failed.&nbsp; For your benefit I changed the subject line and am adding =
2465 these words to the message body.&nbsp; Should still be as problematic, =
2466 but if you like I can resend an exact copy of a failed message changing =
2467 nothing except putting your address instead of our tracker.</FONT></P>
2469 <P><FONT SIZE=3D2 FACE=3D"Arial">Thanks very much for taking time to =
2470 look into this.&nbsp; Much appreciated.</FONT>
2471 </P>
2472 <BR>
2474 <P><FONT FACE=3D"Arial" SIZE=3D2 COLOR=3D"#000000"> &lt;&lt;battery =
2475 backup&gt;&gt; </FONT>
2476 </P>
2478 </BODY>
2479 </HTML>
2480 ------_=_NextPart_002_01CACA65.40A51CBC--
2482 ------_=_NextPart_001_01CACA65.40A51CBC
2483 Content-Type: message/rfc822
2484 Content-Transfer-Encoding: 7bit
2486 X-MimeOLE: Produced By Microsoft Exchange V6.5
2487 MIME-Version: 1.0
2488 Content-Type: multipart/alternative;
2489         boundary="----_=_NextPart_003_01CAC15A.29717800"
2490 X-OriginalArrivalTime: 11 Mar 2010 20:33:51.0249 (UTC) FILETIME=[28FEE010:01CAC15A]
2491 Content-class: urn:content-classes:message
2492 Subject: battery backup
2493 Date: Thu, 11 Mar 2010 13:33:43 -0700
2494 Message-ID: <p06240809c7bf02f9624c@[128.114.22.203]>
2495 X-MS-Has-Attach: 
2496 X-MS-TNEF-Correlator: 
2497 Thread-Topic: battery backup
2498 Thread-Index: AcrBWimtulTrSvBdQ2CcfZ8lyQdxmQ==
2499 From: "Jerry" <jerry@test.test>
2500 To: "Hugh" <hugh@test.test>
2502 This is a multi-part message in MIME format.
2504 ------_=_NextPart_003_01CAC15A.29717800
2505 Content-Type: text/plain;
2506         charset="iso-8859-1"
2507 Content-Transfer-Encoding: quoted-printable
2509 Dear Hugh,
2510         A car batter has an energy capacity of ~ 500Wh.  A UPS=20
2511 battery is worse than this.
2513 if we need to provied 100kW for 30 minutes that will take 100 car=20
2514 batteries.  This seems like an awful lot of batteries.
2516 Of course I like your idea of making the time 1 minute, so we get to=20
2517 a more modest number of batteries
2519 Jerry
2522 ------_=_NextPart_003_01CAC15A.29717800
2523 Content-Type: text/html;
2524         charset="iso-8859-1"
2525 Content-Transfer-Encoding: quoted-printable
2527 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
2528 <HTML>
2529 <HEAD>
2530 <META HTTP-EQUIV=3D"Content-Type" CONTENT=3D"text/html; =
2531 charset=3Diso-8859-1">
2532 <META NAME=3D"Generator" CONTENT=3D"MS Exchange Server version =
2533 6.5.7654.12">
2534 <TITLE>battery backup</TITLE>
2535 </HEAD>
2536 <BODY>
2537 <!-- Converted from text/plain format -->
2539 <P><FONT SIZE=3D2>Dear Hugh,</FONT>
2541 <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <FONT SIZE=3D2>A car =
2542 batter has an energy capacity of ~ 500Wh.&nbsp; A UPS </FONT>
2544 <BR><FONT SIZE=3D2>battery is worse than this.</FONT>
2545 </P>
2547 <P><FONT SIZE=3D2>if we need to provied 100kW for 30 minutes that will =
2548 take 100 car </FONT>
2550 <BR><FONT SIZE=3D2>batteries.&nbsp; This seems like an awful lot of =
2551 batteries.</FONT>
2552 </P>
2554 <P><FONT SIZE=3D2>Of course I like your idea of making the time 1 =
2555 minute, so we get to </FONT>
2557 <BR><FONT SIZE=3D2>a more modest number of batteries</FONT>
2558 </P>
2560 <P><FONT SIZE=3D2>Jerry</FONT>
2561 </P>
2563 </BODY>
2564 </HTML>
2565 ------_=_NextPart_003_01CAC15A.29717800--
2567 ------_=_NextPart_001_01CACA65.40A51CBC--
2568 '''
2569         nodeid = self._handle_mail(message)
2570         assert not os.path.exists(SENDMAILDEBUG)
2571         msgid = self.db.issue.get(nodeid, 'messages')[0]
2572         self.assert_(self.db.msg.get(msgid, 'content').startswith('Hi Richard'))
2573         self.assertEqual(self.db.msg.get(msgid, 'files'), ['1', '2'])
2574         fileid = self.db.msg.get(msgid, 'files')[0]
2575         self.assertEqual(self.db.file.get(fileid, 'type'), 'text/html')
2576         fileid = self.db.msg.get(msgid, 'files')[1]
2577         self.assertEqual(self.db.file.get(fileid, 'type'), 'message/rfc822')
2579     def testForwardedMessageAttachment(self):
2580         message = '''Return-Path: <rgg@test.test>
2581 Received: from localhost(127.0.0.1), claiming to be "[115.130.26.69]"
2582 via SMTP by localhost, id smtpdAAApLaWrq; Tue Apr 13 23:10:05 2010
2583 Message-ID: <4BC4F9C7.50409@test.test>
2584 Date: Wed, 14 Apr 2010 09:09:59 +1000
2585 From: Rupert Goldie <rgg@test.test>
2586 User-Agent: Thunderbird 2.0.0.24 (Windows/20100228)
2587 MIME-Version: 1.0
2588 To: ekit issues <issues@test.test>
2589 Subject: [Fwd: PHP ERROR (fb)] post limit reached
2590 Content-Type: multipart/mixed; boundary="------------000807090608060304010403"
2592 This is a multi-part message in MIME format.
2593 --------------000807090608060304010403
2594 Content-Type: text/plain; charset=ISO-8859-1; format=flowed
2595 Content-Transfer-Encoding: 7bit
2597 Catch this exception and log it without emailing.
2599 --------------000807090608060304010403
2600 Content-Type: message/rfc822; name="PHP ERROR (fb).eml"
2601 Content-Transfer-Encoding: 7bit
2602 Content-Disposition: inline; filename="PHP ERROR (fb).eml"
2604 Return-Path: <ektravj@test.test>
2605 X-Sieve: CMU Sieve 2.2
2606 via SMTP by crown.off.ekorp.com, id smtpdAAA1JaW1o; Tue Apr 13 23:01:04 2010
2607 X-Virus-Scanned: by amavisd-new at ekit.com
2608 To: facebook-errors@test.test
2609 From: ektravj@test.test
2610 Subject: PHP ERROR (fb)
2611 Message-Id: <20100413230100.D601D27E84@mail2.elax3.ekorp.com>
2612 Date: Tue, 13 Apr 2010 23:01:00 +0000 (UTC)
2614 [13-Apr-2010 22:49:02] PHP Fatal error:  Uncaught exception 'Exception' with message 'Facebook Error Message: Feed action request limit reached' in /app/01/www/virtual/fb.ekit.com/htdocs/includes/functions.php:280
2615 Stack trace:
2616 #0 /app/01/www/virtual/fb.ekit.com/htdocs/gateway/ekit/feed/index.php(178): fb_exceptions(Object(FacebookRestClientException))
2617 #1 {main}
2618  thrown in /app/01/www/virtual/fb.ekit.com/htdocs/includes/functions.php on line 280
2621 --------------000807090608060304010403--
2622 '''
2623         nodeid = self._handle_mail(message)
2624         assert not os.path.exists(SENDMAILDEBUG)
2625         msgid = self.db.issue.get(nodeid, 'messages')[0]
2626         self.assertEqual(self.db.msg.get(msgid, 'content'),
2627             'Catch this exception and log it without emailing.')
2628         self.assertEqual(self.db.msg.get(msgid, 'files'), ['1'])
2629         fileid = self.db.msg.get(msgid, 'files')[0]
2630         self.assertEqual(self.db.file.get(fileid, 'type'), 'message/rfc822')
2632 def test_suite():
2633     suite = unittest.TestSuite()
2634     suite.addTest(unittest.makeSuite(MailgwTestCase))
2635     return suite
2637 if __name__ == '__main__':
2638     runner = unittest.TextTestRunner()
2639     unittest.main(testRunner=runner)
2641 # vim: set filetype=python sts=4 sw=4 et si :