comparison test/db_test_base.py @ 3882:46ef2a6fd79d

config option to limit nosy attachments based on size reworking of patch [SF#772323] from Philipp Gortan It tries to avoid reading the file contents just to get the file size but that was too hard for metakit backends. They don't inherit from blobfiles.FileStorage which makes it more challenging. Really that backend should be reworked to inherit from FileStorage. I'm not sure I like the default being sys.maxint. Maybe have 0 == unlimited? But what if someone really wanted to set it to 0 to mean "don't attach anything"?
author Justus Pendleton <jpend@users.sourceforge.net>
date Mon, 03 Sep 2007 17:14:09 +0000
parents 34128a809e22
children 666b70676ec6
comparison
equal deleted inserted replaced
3881:e7050411a774 3882:46ef2a6fd79d
13 # BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 13 # BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
14 # FOR A PARTICULAR PURPOSE. THE CODE PROVIDED HEREUNDER IS ON AN "AS IS" 14 # FOR A PARTICULAR PURPOSE. THE CODE PROVIDED HEREUNDER IS ON AN "AS IS"
15 # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE, 15 # BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
16 # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 16 # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
17 # 17 #
18 # $Id: db_test_base.py,v 1.88 2007-08-31 15:44:03 jpend Exp $ 18 # $Id: db_test_base.py,v 1.89 2007-09-03 17:14:09 jpend Exp $
19 19
20 import unittest, os, shutil, errno, imp, sys, time, pprint, sets 20 import unittest, os, shutil, errno, imp, sys, time, pprint, sets, base64
21 21
22 from roundup.hyperdb import String, Password, Link, Multilink, Date, \ 22 from roundup.hyperdb import String, Password, Link, Multilink, Date, \
23 Interval, DatabaseError, Boolean, Number, Node 23 Interval, DatabaseError, Boolean, Number, Node
24 from roundup.mailer import Mailer
24 from roundup import date, password, init, instance, configuration, support 25 from roundup import date, password, init, instance, configuration, support
25 26
26 from mocknull import MockNull 27 from mocknull import MockNull
27 28
28 config = configuration.CoreConfig() 29 config = configuration.CoreConfig()
67 status = module.Class(db, "status", name=String()) 68 status = module.Class(db, "status", name=String())
68 status.setkey("name") 69 status.setkey("name")
69 priority = module.Class(db, "priority", name=String(), order=String()) 70 priority = module.Class(db, "priority", name=String(), order=String())
70 priority.setkey("name") 71 priority.setkey("name")
71 user = module.Class(db, "user", username=String(), password=Password(), 72 user = module.Class(db, "user", username=String(), password=Password(),
72 assignable=Boolean(), age=Number(), roles=String(), 73 assignable=Boolean(), age=Number(), roles=String(), address=String(),
73 supervisor=Link('user')) 74 supervisor=Link('user'),realname=String())
74 user.setkey("username") 75 user.setkey("username")
75 file = module.FileClass(db, "file", name=String(), type=String(), 76 file = module.FileClass(db, "file", name=String(), type=String(),
76 comment=String(indexme="yes"), fooz=Password()) 77 comment=String(indexme="yes"), fooz=Password())
77 file_nidx = module.FileClass(db, "file_nidx", content=String(indexme='no')) 78 file_nidx = module.FileClass(db, "file_nidx", content=String(indexme='no'))
78 issue = module.IssueClass(db, "issue", title=String(indexme="yes"), 79 issue = module.IssueClass(db, "issue", title=String(indexme="yes"),
80 foo=Interval(), files=Multilink("file"), assignedto=Link('user'), 81 foo=Interval(), files=Multilink("file"), assignedto=Link('user'),
81 priority=Link('priority'), spam=Multilink('msg')) 82 priority=Link('priority'), spam=Multilink('msg'))
82 stuff = module.Class(db, "stuff", stuff=String()) 83 stuff = module.Class(db, "stuff", stuff=String())
83 session = module.Class(db, 'session', title=String()) 84 session = module.Class(db, 'session', title=String())
84 msg = module.FileClass(db, "msg", date=Date(), 85 msg = module.FileClass(db, "msg", date=Date(),
85 author=Link("user", do_journal='no')) 86 author=Link("user", do_journal='no'),
87 files=Multilink('file'), inreplyto=String(),
88 messageid=String(),
89 recipients=Multilink("user", do_journal='no')
90 )
86 session.disableJournalling() 91 session.disableJournalling()
87 db.post_init() 92 db.post_init()
88 if create: 93 if create:
89 user.create(username="admin", roles='Admin', 94 user.create(username="admin", roles='Admin',
90 password=password.Password('sekrit')) 95 password=password.Password('sekrit'))
91 user.create(username="fred", roles='User', 96 user.create(username="fred", roles='User',
92 password=password.Password('sekrit')) 97 password=password.Password('sekrit'), address='fred@example.com')
93 status.create(name="unread") 98 status.create(name="unread")
94 status.create(name="in-progress") 99 status.create(name="in-progress")
95 status.create(name="testing") 100 status.create(name="testing")
96 status.create(name="resolved") 101 status.create(name="resolved")
97 priority.create(name="feature", order="2") 102 priority.create(name="feature", order="2")
915 self.assertEquals(self.db.indexer.search(['flebble'], self.db.issue), 920 self.assertEquals(self.db.indexer.search(['flebble'], self.db.issue),
916 {'1': {}}) 921 {'1': {}})
917 922
918 def testIndexingOnImport(self): 923 def testIndexingOnImport(self):
919 msgcontent = 'Glrk' 924 msgcontent = 'Glrk'
920 msgid = self.db.msg.import_list(['content'], [repr(msgcontent)]) 925 msgid = self.db.msg.import_list(['content', 'files', 'recipients'],
926 [repr(msgcontent), '[]', '[]'])
921 msg_filename = self.db.filename(self.db.msg.classname, msgid, 927 msg_filename = self.db.filename(self.db.msg.classname, msgid,
922 create=1) 928 create=1)
923 support.ensureParentsExist(msg_filename) 929 support.ensureParentsExist(msg_filename)
924 msg_file = open(msg_filename, 'w') 930 msg_file = open(msg_filename, 'w')
925 msg_file.write(msgcontent) 931 msg_file.write(msgcontent)
926 msg_file.close() 932 msg_file.close()
927 933
928 934
929 filecontent = 'Brrk' 935 filecontent = 'Brrk'
930 fileid = self.db.file.import_list(['content'], [repr(filecontent)]) 936 fileid = self.db.file.import_list(['content'], [repr(filecontent)])
931 file_filename = self.db.filename(self.db.file.classname, fileid, 937 file_filename = self.db.filename(self.db.file.classname, fileid,
932 create=1) 938 create=1)
933 support.ensureParentsExist(file_filename) 939 support.ensureParentsExist(file_filename)
934 file_file = open(file_filename, 'w') 940 file_file = open(file_filename, 'w')
935 file_file.write(filecontent) 941 file_file.write(filecontent)
936 file_file.close() 942 file_file.close()
937 943
938 title = 'Bzzt' 944 title = 'Bzzt'
939 nodeid = self.db.issue.import_list(['title', 'messages', 'files', 945 nodeid = self.db.issue.import_list(['title', 'messages', 'files',
940 'spam', 946 'spam',
941 'nosy', 947 'nosy',
956 {str(nodeid):{'messages':[str(msgid)]}}) 962 {str(nodeid):{'messages':[str(msgid)]}})
957 # Content of file is indexed 963 # Content of file is indexed
958 self.assertEquals(self.db.indexer.search([filecontent], self.db.issue), 964 self.assertEquals(self.db.indexer.search([filecontent], self.db.issue),
959 {str(nodeid):{'files':[str(fileid)]}}) 965 {str(nodeid):{'files':[str(fileid)]}})
960 966
961 967
962 968
963 # 969 #
964 # searching tests follow 970 # searching tests follow
965 # 971 #
966 def testFindIncorrectProperty(self): 972 def testFindIncorrectProperty(self):
1238 ae(filt(None, {}, ('+','title')), ['1', '2', '3', '4']) 1244 ae(filt(None, {}, ('+','title')), ['1', '2', '3', '4'])
1239 ae(filt(None, {}, ('-','title')), ['4', '3', '2', '1']) 1245 ae(filt(None, {}, ('-','title')), ['4', '3', '2', '1'])
1240 1246
1241 def testFilteringMultilinkSort(self): 1247 def testFilteringMultilinkSort(self):
1242 # 1: [] Reverse: 1: [] 1248 # 1: [] Reverse: 1: []
1243 # 2: [] 2: [] 1249 # 2: [] 2: []
1244 # 3: ['admin','fred'] 3: ['fred','admin'] 1250 # 3: ['admin','fred'] 3: ['fred','admin']
1245 # 4: ['admin','bleep','fred'] 4: ['fred','bleep','admin'] 1251 # 4: ['admin','bleep','fred'] 4: ['fred','bleep','admin']
1246 # Note the sort order for the multilink doen't change when 1252 # Note the sort order for the multilink doen't change when
1247 # reversing the sort direction due to the re-sorting of the 1253 # reversing the sort direction due to the re-sorting of the
1248 # multilink! 1254 # multilink!
1249 ae, filt = self.filteringSetup() 1255 ae, filt = self.filteringSetup()
1530 # author.username, *not* by author.orderprop() (author.age)! 1536 # author.username, *not* by author.orderprop() (author.age)!
1531 ae(filt(None, {}, [('+','messages')]), 1537 ae(filt(None, {}, [('+','messages')]),
1532 ['1', '2', '3', '4', '5', '8', '6', '7']) 1538 ['1', '2', '3', '4', '5', '8', '6', '7'])
1533 ae(filt(None, {}, [('+','messages.author'), ('+','messages')]), 1539 ae(filt(None, {}, [('+','messages.author'), ('+','messages')]),
1534 ['6', '7', '8', '5', '4', '3', '1', '2']) 1540 ['6', '7', '8', '5', '4', '3', '1', '2'])
1535 # The following will sort by 1541 # The following will sort by
1536 # author.supervisor.username and then by 1542 # author.supervisor.username and then by
1537 # author.username 1543 # author.username
1538 # I've resited the tempation to implement recursive orderprop 1544 # I've resited the tempation to implement recursive orderprop
1539 # here: There could even be loops if several classes specify a 1545 # here: There could even be loops if several classes specify a
1540 # Link or Multilink as the orderprop... 1546 # Link or Multilink as the orderprop...
1721 self.assertEqual(keys, ['activity', 'actor', 'assignedto', 'creation', 1727 self.assertEqual(keys, ['activity', 'actor', 'assignedto', 'creation',
1722 'creator', 'deadline', 'files', 'fixer', 'foo', 'id', 'messages', 1728 'creator', 'deadline', 'files', 'fixer', 'foo', 'id', 'messages',
1723 'nosy', 'priority', 'spam', 'status', 'superseder']) 1729 'nosy', 'priority', 'spam', 'status', 'superseder'])
1724 self.assertEqual(self.db.issue.list(), ['1']) 1730 self.assertEqual(self.db.issue.list(), ['1'])
1725 1731
1732 def testNosyMail(self) :
1733 """Creates one issue with two attachments, one smaller and one larger
1734 than the set max_attachment_size.
1735 """
1736 db = self.db
1737 db.config.NOSY_MAX_ATTACHMENT_SIZE = 4096
1738 res = dict(mail_to = None, mail_msg = None)
1739 def dummy_snd(s, to, msg, res=res) :
1740 res["mail_to"], res["mail_msg"] = to, msg
1741 backup, Mailer.smtp_send = Mailer.smtp_send, dummy_snd
1742 try :
1743 f1 = db.file.create(name="test1.txt", content="x" * 20)
1744 f2 = db.file.create(name="test2.txt", content="y" * 5000)
1745 m = db.msg.create(content="one two", author="admin",
1746 files = [f1, f2])
1747 i = db.issue.create(title='spam', files = [f1, f2],
1748 messages = [m], nosy = [db.user.lookup("fred")])
1749
1750 db.issue.nosymessage(i, m, {})
1751 mail_msg = res["mail_msg"].getvalue()
1752 self.assertEqual(res["mail_to"], ["fred@example.com"])
1753 self.failUnless("From: admin" in mail_msg)
1754 self.failUnless("Subject: [issue1] spam" in mail_msg)
1755 self.failUnless("New submission from admin" in mail_msg)
1756 self.failUnless("one two" in mail_msg)
1757 self.failIf("File 'test1.txt' not attached" in mail_msg)
1758 self.failUnless(base64.b64encode("xxx") in mail_msg)
1759 self.failUnless("File 'test2.txt' not attached" in mail_msg)
1760 self.failIf(base64.b64encode("yyy") in mail_msg)
1761 finally :
1762 Mailer.smtp_send = backup
1763
1726 class ROTest(MyTestCase): 1764 class ROTest(MyTestCase):
1727 def setUp(self): 1765 def setUp(self):
1728 # remove previous test, ignore errors 1766 # remove previous test, ignore errors
1729 if os.path.exists(config.DATABASE): 1767 if os.path.exists(config.DATABASE):
1730 shutil.rmtree(config.DATABASE) 1768 shutil.rmtree(config.DATABASE)

Roundup Issue Tracker: http://roundup-tracker.org/