PageRenderTime 484ms CodeModel.GetById 100ms app.highlight 209ms RepoModel.GetById 103ms app.codeStats 0ms

/Lib/bsddb/test/test_associate.py

http://unladen-swallow.googlecode.com/
Python | 445 lines | 418 code | 18 blank | 9 comment | 1 complexity | 1de9fcd8c80ad4bcc767e3dee26f03ad MD5 | raw file
  1"""
  2TestCases for DB.associate.
  3"""
  4
  5import sys, os, string
  6import time
  7from pprint import pprint
  8
  9import unittest
 10from test_all import db, dbshelve, test_support, verbose, have_threads, \
 11        get_new_environment_path
 12
 13
 14#----------------------------------------------------------------------
 15
 16
 17musicdata = {
 181 : ("Bad English", "The Price Of Love", "Rock"),
 192 : ("DNA featuring Suzanne Vega", "Tom's Diner", "Rock"),
 203 : ("George Michael", "Praying For Time", "Rock"),
 214 : ("Gloria Estefan", "Here We Are", "Rock"),
 225 : ("Linda Ronstadt", "Don't Know Much", "Rock"),
 236 : ("Michael Bolton", "How Am I Supposed To Live Without You", "Blues"),
 247 : ("Paul Young", "Oh Girl", "Rock"),
 258 : ("Paula Abdul", "Opposites Attract", "Rock"),
 269 : ("Richard Marx", "Should've Known Better", "Rock"),
 2710: ("Rod Stewart", "Forever Young", "Rock"),
 2811: ("Roxette", "Dangerous", "Rock"),
 2912: ("Sheena Easton", "The Lover In Me", "Rock"),
 3013: ("Sinead O'Connor", "Nothing Compares 2 U", "Rock"),
 3114: ("Stevie B.", "Because I Love You", "Rock"),
 3215: ("Taylor Dayne", "Love Will Lead You Back", "Rock"),
 3316: ("The Bangles", "Eternal Flame", "Rock"),
 3417: ("Wilson Phillips", "Release Me", "Rock"),
 3518: ("Billy Joel", "Blonde Over Blue", "Rock"),
 3619: ("Billy Joel", "Famous Last Words", "Rock"),
 3720: ("Billy Joel", "Lullabye (Goodnight, My Angel)", "Rock"),
 3821: ("Billy Joel", "The River Of Dreams", "Rock"),
 3922: ("Billy Joel", "Two Thousand Years", "Rock"),
 4023: ("Janet Jackson", "Alright", "Rock"),
 4124: ("Janet Jackson", "Black Cat", "Rock"),
 4225: ("Janet Jackson", "Come Back To Me", "Rock"),
 4326: ("Janet Jackson", "Escapade", "Rock"),
 4427: ("Janet Jackson", "Love Will Never Do (Without You)", "Rock"),
 4528: ("Janet Jackson", "Miss You Much", "Rock"),
 4629: ("Janet Jackson", "Rhythm Nation", "Rock"),
 4730: ("Janet Jackson", "State Of The World", "Rock"),
 4831: ("Janet Jackson", "The Knowledge", "Rock"),
 4932: ("Spyro Gyra", "End of Romanticism", "Jazz"),
 5033: ("Spyro Gyra", "Heliopolis", "Jazz"),
 5134: ("Spyro Gyra", "Jubilee", "Jazz"),
 5235: ("Spyro Gyra", "Little Linda", "Jazz"),
 5336: ("Spyro Gyra", "Morning Dance", "Jazz"),
 5437: ("Spyro Gyra", "Song for Lorraine", "Jazz"),
 5538: ("Yes", "Owner Of A Lonely Heart", "Rock"),
 5639: ("Yes", "Rhythm Of Love", "Rock"),
 5740: ("Cusco", "Dream Catcher", "New Age"),
 5841: ("Cusco", "Geronimos Laughter", "New Age"),
 5942: ("Cusco", "Ghost Dance", "New Age"),
 6043: ("Blue Man Group", "Drumbone", "New Age"),
 6144: ("Blue Man Group", "Endless Column", "New Age"),
 6245: ("Blue Man Group", "Klein Mandelbrot", "New Age"),
 6346: ("Kenny G", "Silhouette", "Jazz"),
 6447: ("Sade", "Smooth Operator", "Jazz"),
 6548: ("David Arkenstone", "Papillon (On The Wings Of The Butterfly)",
 66     "New Age"),
 6749: ("David Arkenstone", "Stepping Stars", "New Age"),
 6850: ("David Arkenstone", "Carnation Lily Lily Rose", "New Age"),
 6951: ("David Lanz", "Behind The Waterfall", "New Age"),
 7052: ("David Lanz", "Cristofori's Dream", "New Age"),
 7153: ("David Lanz", "Heartsounds", "New Age"),
 7254: ("David Lanz", "Leaves on the Seine", "New Age"),
 7399: ("unknown artist", "Unnamed song", "Unknown"),
 74}
 75
 76#----------------------------------------------------------------------
 77
 78class AssociateErrorTestCase(unittest.TestCase):
 79    def setUp(self):
 80        self.filename = self.__class__.__name__ + '.db'
 81        self.homeDir = get_new_environment_path()
 82        self.env = db.DBEnv()
 83        self.env.open(self.homeDir, db.DB_CREATE | db.DB_INIT_MPOOL)
 84
 85    def tearDown(self):
 86        self.env.close()
 87        self.env = None
 88        test_support.rmtree(self.homeDir)
 89
 90    def test00_associateDBError(self):
 91        if verbose:
 92            print '\n', '-=' * 30
 93            print "Running %s.test00_associateDBError..." % \
 94                  self.__class__.__name__
 95
 96        dupDB = db.DB(self.env)
 97        dupDB.set_flags(db.DB_DUP)
 98        dupDB.open(self.filename, "primary", db.DB_BTREE, db.DB_CREATE)
 99
100        secDB = db.DB(self.env)
101        secDB.open(self.filename, "secondary", db.DB_BTREE, db.DB_CREATE)
102
103        # dupDB has been configured to allow duplicates, it can't
104        # associate with a secondary.  Berkeley DB will return an error.
105        try:
106            def f(a,b): return a+b
107            dupDB.associate(secDB, f)
108        except db.DBError:
109            # good
110            secDB.close()
111            dupDB.close()
112        else:
113            secDB.close()
114            dupDB.close()
115            self.fail("DBError exception was expected")
116
117
118
119#----------------------------------------------------------------------
120
121
122class AssociateTestCase(unittest.TestCase):
123    keytype = ''
124    envFlags = 0
125    dbFlags = 0
126
127    def setUp(self):
128        self.filename = self.__class__.__name__ + '.db'
129        self.homeDir = get_new_environment_path()
130        self.env = db.DBEnv()
131        self.env.open(self.homeDir, db.DB_CREATE | db.DB_INIT_MPOOL |
132                               db.DB_INIT_LOCK | db.DB_THREAD | self.envFlags)
133
134    def tearDown(self):
135        self.closeDB()
136        self.env.close()
137        self.env = None
138        test_support.rmtree(self.homeDir)
139
140    def addDataToDB(self, d, txn=None):
141        for key, value in musicdata.items():
142            if type(self.keytype) == type(''):
143                key = "%02d" % key
144            d.put(key, '|'.join(value), txn=txn)
145
146    def createDB(self, txn=None):
147        self.cur = None
148        self.secDB = None
149        self.primary = db.DB(self.env)
150        self.primary.set_get_returns_none(2)
151        if db.version() >= (4, 1):
152            self.primary.open(self.filename, "primary", self.dbtype,
153                          db.DB_CREATE | db.DB_THREAD | self.dbFlags, txn=txn)
154        else:
155            self.primary.open(self.filename, "primary", self.dbtype,
156                          db.DB_CREATE | db.DB_THREAD | self.dbFlags)
157
158    def closeDB(self):
159        if self.cur:
160            self.cur.close()
161            self.cur = None
162        if self.secDB:
163            self.secDB.close()
164            self.secDB = None
165        self.primary.close()
166        self.primary = None
167
168    def getDB(self):
169        return self.primary
170
171
172    def test01_associateWithDB(self):
173        if verbose:
174            print '\n', '-=' * 30
175            print "Running %s.test01_associateWithDB..." % \
176                  self.__class__.__name__
177
178        self.createDB()
179
180        self.secDB = db.DB(self.env)
181        self.secDB.set_flags(db.DB_DUP)
182        self.secDB.set_get_returns_none(2)
183        self.secDB.open(self.filename, "secondary", db.DB_BTREE,
184                   db.DB_CREATE | db.DB_THREAD | self.dbFlags)
185        self.getDB().associate(self.secDB, self.getGenre)
186
187        self.addDataToDB(self.getDB())
188
189        self.finish_test(self.secDB)
190
191
192    def test02_associateAfterDB(self):
193        if verbose:
194            print '\n', '-=' * 30
195            print "Running %s.test02_associateAfterDB..." % \
196                  self.__class__.__name__
197
198        self.createDB()
199        self.addDataToDB(self.getDB())
200
201        self.secDB = db.DB(self.env)
202        self.secDB.set_flags(db.DB_DUP)
203        self.secDB.open(self.filename, "secondary", db.DB_BTREE,
204                   db.DB_CREATE | db.DB_THREAD | self.dbFlags)
205
206        # adding the DB_CREATE flag will cause it to index existing records
207        self.getDB().associate(self.secDB, self.getGenre, db.DB_CREATE)
208
209        self.finish_test(self.secDB)
210
211
212    def finish_test(self, secDB, txn=None):
213        # 'Blues' should not be in the secondary database
214        vals = secDB.pget('Blues', txn=txn)
215        self.assertEqual(vals, None, vals)
216
217        vals = secDB.pget('Unknown', txn=txn)
218        self.assert_(vals[0] == 99 or vals[0] == '99', vals)
219        vals[1].index('Unknown')
220        vals[1].index('Unnamed')
221        vals[1].index('unknown')
222
223        if verbose:
224            print "Primary key traversal:"
225        self.cur = self.getDB().cursor(txn)
226        count = 0
227        rec = self.cur.first()
228        while rec is not None:
229            if type(self.keytype) == type(''):
230                self.assert_(int(rec[0]))  # for primary db, key is a number
231            else:
232                self.assert_(rec[0] and type(rec[0]) == type(0))
233            count = count + 1
234            if verbose:
235                print rec
236            rec = getattr(self.cur, "next")()
237        self.assertEqual(count, len(musicdata))  # all items accounted for
238
239
240        if verbose:
241            print "Secondary key traversal:"
242        self.cur = secDB.cursor(txn)
243        count = 0
244
245        # test cursor pget
246        vals = self.cur.pget('Unknown', flags=db.DB_LAST)
247        self.assert_(vals[1] == 99 or vals[1] == '99', vals)
248        self.assertEqual(vals[0], 'Unknown')
249        vals[2].index('Unknown')
250        vals[2].index('Unnamed')
251        vals[2].index('unknown')
252
253        vals = self.cur.pget('Unknown', data='wrong value', flags=db.DB_GET_BOTH)
254        self.assertEqual(vals, None, vals)
255
256        rec = self.cur.first()
257        self.assertEqual(rec[0], "Jazz")
258        while rec is not None:
259            count = count + 1
260            if verbose:
261                print rec
262            rec = getattr(self.cur, "next")()
263        # all items accounted for EXCEPT for 1 with "Blues" genre
264        self.assertEqual(count, len(musicdata)-1)
265
266        self.cur = None
267
268    def getGenre(self, priKey, priData):
269        self.assertEqual(type(priData), type(""))
270        genre = priData.split('|')[2]
271
272        if verbose:
273            print 'getGenre key: %r data: %r' % (priKey, priData)
274
275        if genre == 'Blues':
276            return db.DB_DONOTINDEX
277        else:
278            return genre
279
280
281#----------------------------------------------------------------------
282
283
284class AssociateHashTestCase(AssociateTestCase):
285    dbtype = db.DB_HASH
286
287class AssociateBTreeTestCase(AssociateTestCase):
288    dbtype = db.DB_BTREE
289
290class AssociateRecnoTestCase(AssociateTestCase):
291    dbtype = db.DB_RECNO
292    keytype = 0
293
294#----------------------------------------------------------------------
295
296class AssociateBTreeTxnTestCase(AssociateBTreeTestCase):
297    envFlags = db.DB_INIT_TXN
298    dbFlags = 0
299
300    def txn_finish_test(self, sDB, txn):
301        try:
302            self.finish_test(sDB, txn=txn)
303        finally:
304            if self.cur:
305                self.cur.close()
306                self.cur = None
307            if txn:
308                txn.commit()
309
310    def test13_associate_in_transaction(self):
311        if verbose:
312            print '\n', '-=' * 30
313            print "Running %s.test13_associateAutoCommit..." % \
314                  self.__class__.__name__
315
316        txn = self.env.txn_begin()
317        try:
318            self.createDB(txn=txn)
319
320            self.secDB = db.DB(self.env)
321            self.secDB.set_flags(db.DB_DUP)
322            self.secDB.set_get_returns_none(2)
323            self.secDB.open(self.filename, "secondary", db.DB_BTREE,
324                       db.DB_CREATE | db.DB_THREAD, txn=txn)
325            if db.version() >= (4,1):
326                self.getDB().associate(self.secDB, self.getGenre, txn=txn)
327            else:
328                self.getDB().associate(self.secDB, self.getGenre)
329
330            self.addDataToDB(self.getDB(), txn=txn)
331        except:
332            txn.abort()
333            raise
334
335        self.txn_finish_test(self.secDB, txn=txn)
336
337
338#----------------------------------------------------------------------
339
340class ShelveAssociateTestCase(AssociateTestCase):
341
342    def createDB(self):
343        self.primary = dbshelve.open(self.filename,
344                                     dbname="primary",
345                                     dbenv=self.env,
346                                     filetype=self.dbtype)
347
348    def addDataToDB(self, d):
349        for key, value in musicdata.items():
350            if type(self.keytype) == type(''):
351                key = "%02d" % key
352            d.put(key, value)    # save the value as is this time
353
354
355    def getGenre(self, priKey, priData):
356        self.assertEqual(type(priData), type(()))
357        if verbose:
358            print 'getGenre key: %r data: %r' % (priKey, priData)
359        genre = priData[2]
360        if genre == 'Blues':
361            return db.DB_DONOTINDEX
362        else:
363            return genre
364
365
366class ShelveAssociateHashTestCase(ShelveAssociateTestCase):
367    dbtype = db.DB_HASH
368
369class ShelveAssociateBTreeTestCase(ShelveAssociateTestCase):
370    dbtype = db.DB_BTREE
371
372class ShelveAssociateRecnoTestCase(ShelveAssociateTestCase):
373    dbtype = db.DB_RECNO
374    keytype = 0
375
376
377#----------------------------------------------------------------------
378
379class ThreadedAssociateTestCase(AssociateTestCase):
380
381    def addDataToDB(self, d):
382        t1 = Thread(target = self.writer1,
383                    args = (d, ))
384        t2 = Thread(target = self.writer2,
385                    args = (d, ))
386
387        t1.setDaemon(True)
388        t2.setDaemon(True)
389        t1.start()
390        t2.start()
391        t1.join()
392        t2.join()
393
394    def writer1(self, d):
395        for key, value in musicdata.items():
396            if type(self.keytype) == type(''):
397                key = "%02d" % key
398            d.put(key, '|'.join(value))
399
400    def writer2(self, d):
401        for x in range(100, 600):
402            key = 'z%2d' % x
403            value = [key] * 4
404            d.put(key, '|'.join(value))
405
406
407class ThreadedAssociateHashTestCase(ShelveAssociateTestCase):
408    dbtype = db.DB_HASH
409
410class ThreadedAssociateBTreeTestCase(ShelveAssociateTestCase):
411    dbtype = db.DB_BTREE
412
413class ThreadedAssociateRecnoTestCase(ShelveAssociateTestCase):
414    dbtype = db.DB_RECNO
415    keytype = 0
416
417
418#----------------------------------------------------------------------
419
420def test_suite():
421    suite = unittest.TestSuite()
422
423    suite.addTest(unittest.makeSuite(AssociateErrorTestCase))
424
425    suite.addTest(unittest.makeSuite(AssociateHashTestCase))
426    suite.addTest(unittest.makeSuite(AssociateBTreeTestCase))
427    suite.addTest(unittest.makeSuite(AssociateRecnoTestCase))
428
429    if db.version() >= (4, 1):
430        suite.addTest(unittest.makeSuite(AssociateBTreeTxnTestCase))
431
432    suite.addTest(unittest.makeSuite(ShelveAssociateHashTestCase))
433    suite.addTest(unittest.makeSuite(ShelveAssociateBTreeTestCase))
434    suite.addTest(unittest.makeSuite(ShelveAssociateRecnoTestCase))
435
436    if have_threads:
437        suite.addTest(unittest.makeSuite(ThreadedAssociateHashTestCase))
438        suite.addTest(unittest.makeSuite(ThreadedAssociateBTreeTestCase))
439        suite.addTest(unittest.makeSuite(ThreadedAssociateRecnoTestCase))
440
441    return suite
442
443
444if __name__ == '__main__':
445    unittest.main(defaultTest='test_suite')