Home | History | Annotate | Download | only in test
      1 """
      2 TestCases for DB.associate.
      3 """
      4 
      5 import sys, os, string
      6 import time
      7 from pprint import pprint
      8 
      9 import unittest
     10 from test_all import db, dbshelve, test_support, verbose, have_threads, \
     11         get_new_environment_path
     12 
     13 
     14 #----------------------------------------------------------------------
     15 
     16 
     17 musicdata = {
     18 1 : ("Bad English", "The Price Of Love", "Rock"),
     19 2 : ("DNA featuring Suzanne Vega", "Tom's Diner", "Rock"),
     20 3 : ("George Michael", "Praying For Time", "Rock"),
     21 4 : ("Gloria Estefan", "Here We Are", "Rock"),
     22 5 : ("Linda Ronstadt", "Don't Know Much", "Rock"),
     23 6 : ("Michael Bolton", "How Am I Supposed To Live Without You", "Blues"),
     24 7 : ("Paul Young", "Oh Girl", "Rock"),
     25 8 : ("Paula Abdul", "Opposites Attract", "Rock"),
     26 9 : ("Richard Marx", "Should've Known Better", "Rock"),
     27 10: ("Rod Stewart", "Forever Young", "Rock"),
     28 11: ("Roxette", "Dangerous", "Rock"),
     29 12: ("Sheena Easton", "The Lover In Me", "Rock"),
     30 13: ("Sinead O'Connor", "Nothing Compares 2 U", "Rock"),
     31 14: ("Stevie B.", "Because I Love You", "Rock"),
     32 15: ("Taylor Dayne", "Love Will Lead You Back", "Rock"),
     33 16: ("The Bangles", "Eternal Flame", "Rock"),
     34 17: ("Wilson Phillips", "Release Me", "Rock"),
     35 18: ("Billy Joel", "Blonde Over Blue", "Rock"),
     36 19: ("Billy Joel", "Famous Last Words", "Rock"),
     37 20: ("Billy Joel", "Lullabye (Goodnight, My Angel)", "Rock"),
     38 21: ("Billy Joel", "The River Of Dreams", "Rock"),
     39 22: ("Billy Joel", "Two Thousand Years", "Rock"),
     40 23: ("Janet Jackson", "Alright", "Rock"),
     41 24: ("Janet Jackson", "Black Cat", "Rock"),
     42 25: ("Janet Jackson", "Come Back To Me", "Rock"),
     43 26: ("Janet Jackson", "Escapade", "Rock"),
     44 27: ("Janet Jackson", "Love Will Never Do (Without You)", "Rock"),
     45 28: ("Janet Jackson", "Miss You Much", "Rock"),
     46 29: ("Janet Jackson", "Rhythm Nation", "Rock"),
     47 30: ("Janet Jackson", "State Of The World", "Rock"),
     48 31: ("Janet Jackson", "The Knowledge", "Rock"),
     49 32: ("Spyro Gyra", "End of Romanticism", "Jazz"),
     50 33: ("Spyro Gyra", "Heliopolis", "Jazz"),
     51 34: ("Spyro Gyra", "Jubilee", "Jazz"),
     52 35: ("Spyro Gyra", "Little Linda", "Jazz"),
     53 36: ("Spyro Gyra", "Morning Dance", "Jazz"),
     54 37: ("Spyro Gyra", "Song for Lorraine", "Jazz"),
     55 38: ("Yes", "Owner Of A Lonely Heart", "Rock"),
     56 39: ("Yes", "Rhythm Of Love", "Rock"),
     57 40: ("Cusco", "Dream Catcher", "New Age"),
     58 41: ("Cusco", "Geronimos Laughter", "New Age"),
     59 42: ("Cusco", "Ghost Dance", "New Age"),
     60 43: ("Blue Man Group", "Drumbone", "New Age"),
     61 44: ("Blue Man Group", "Endless Column", "New Age"),
     62 45: ("Blue Man Group", "Klein Mandelbrot", "New Age"),
     63 46: ("Kenny G", "Silhouette", "Jazz"),
     64 47: ("Sade", "Smooth Operator", "Jazz"),
     65 48: ("David Arkenstone", "Papillon (On The Wings Of The Butterfly)",
     66      "New Age"),
     67 49: ("David Arkenstone", "Stepping Stars", "New Age"),
     68 50: ("David Arkenstone", "Carnation Lily Lily Rose", "New Age"),
     69 51: ("David Lanz", "Behind The Waterfall", "New Age"),
     70 52: ("David Lanz", "Cristofori's Dream", "New Age"),
     71 53: ("David Lanz", "Heartsounds", "New Age"),
     72 54: ("David Lanz", "Leaves on the Seine", "New Age"),
     73 99: ("unknown artist", "Unnamed song", "Unknown"),
     74 }
     75 
     76 #----------------------------------------------------------------------
     77 
     78 class 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 
    122 class 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         self.primary.open(self.filename, "primary", self.dbtype,
    152                       db.DB_CREATE | db.DB_THREAD | self.dbFlags, txn=txn)
    153 
    154     def closeDB(self):
    155         if self.cur:
    156             self.cur.close()
    157             self.cur = None
    158         if self.secDB:
    159             self.secDB.close()
    160             self.secDB = None
    161         self.primary.close()
    162         self.primary = None
    163 
    164     def getDB(self):
    165         return self.primary
    166 
    167 
    168     def _associateWithDB(self, getGenre):
    169         self.createDB()
    170 
    171         self.secDB = db.DB(self.env)
    172         self.secDB.set_flags(db.DB_DUP)
    173         self.secDB.set_get_returns_none(2)
    174         self.secDB.open(self.filename, "secondary", db.DB_BTREE,
    175                    db.DB_CREATE | db.DB_THREAD | self.dbFlags)
    176         self.getDB().associate(self.secDB, getGenre)
    177 
    178         self.addDataToDB(self.getDB())
    179 
    180         self.finish_test(self.secDB)
    181 
    182     def test01_associateWithDB(self):
    183         if verbose:
    184             print '\n', '-=' * 30
    185             print "Running %s.test01_associateWithDB..." % \
    186                   self.__class__.__name__
    187 
    188         return self._associateWithDB(self.getGenre)
    189 
    190     def _associateAfterDB(self, getGenre) :
    191         self.createDB()
    192         self.addDataToDB(self.getDB())
    193 
    194         self.secDB = db.DB(self.env)
    195         self.secDB.set_flags(db.DB_DUP)
    196         self.secDB.open(self.filename, "secondary", db.DB_BTREE,
    197                    db.DB_CREATE | db.DB_THREAD | self.dbFlags)
    198 
    199         # adding the DB_CREATE flag will cause it to index existing records
    200         self.getDB().associate(self.secDB, getGenre, db.DB_CREATE)
    201 
    202         self.finish_test(self.secDB)
    203 
    204     def test02_associateAfterDB(self):
    205         if verbose:
    206             print '\n', '-=' * 30
    207             print "Running %s.test02_associateAfterDB..." % \
    208                   self.__class__.__name__
    209 
    210         return self._associateAfterDB(self.getGenre)
    211 
    212     if db.version() >= (4, 6):
    213         def test03_associateWithDB(self):
    214             if verbose:
    215                 print '\n', '-=' * 30
    216                 print "Running %s.test03_associateWithDB..." % \
    217                       self.__class__.__name__
    218 
    219             return self._associateWithDB(self.getGenreList)
    220 
    221         def test04_associateAfterDB(self):
    222             if verbose:
    223                 print '\n', '-=' * 30
    224                 print "Running %s.test04_associateAfterDB..." % \
    225                       self.__class__.__name__
    226 
    227             return self._associateAfterDB(self.getGenreList)
    228 
    229 
    230     def finish_test(self, secDB, txn=None):
    231         # 'Blues' should not be in the secondary database
    232         vals = secDB.pget('Blues', txn=txn)
    233         self.assertEqual(vals, None, vals)
    234 
    235         vals = secDB.pget('Unknown', txn=txn)
    236         self.assertTrue(vals[0] == 99 or vals[0] == '99', vals)
    237         vals[1].index('Unknown')
    238         vals[1].index('Unnamed')
    239         vals[1].index('unknown')
    240 
    241         if verbose:
    242             print "Primary key traversal:"
    243         self.cur = self.getDB().cursor(txn)
    244         count = 0
    245         rec = self.cur.first()
    246         while rec is not None:
    247             if type(self.keytype) == type(''):
    248                 self.assertTrue(int(rec[0]))  # for primary db, key is a number
    249             else:
    250                 self.assertTrue(rec[0] and type(rec[0]) == type(0))
    251             count = count + 1
    252             if verbose:
    253                 print rec
    254             rec = getattr(self.cur, "next")()
    255         self.assertEqual(count, len(musicdata))  # all items accounted for
    256 
    257 
    258         if verbose:
    259             print "Secondary key traversal:"
    260         self.cur = secDB.cursor(txn)
    261         count = 0
    262 
    263         # test cursor pget
    264         vals = self.cur.pget('Unknown', flags=db.DB_LAST)
    265         self.assertTrue(vals[1] == 99 or vals[1] == '99', vals)
    266         self.assertEqual(vals[0], 'Unknown')
    267         vals[2].index('Unknown')
    268         vals[2].index('Unnamed')
    269         vals[2].index('unknown')
    270 
    271         vals = self.cur.pget('Unknown', data='wrong value', flags=db.DB_GET_BOTH)
    272         self.assertEqual(vals, None, vals)
    273 
    274         rec = self.cur.first()
    275         self.assertEqual(rec[0], "Jazz")
    276         while rec is not None:
    277             count = count + 1
    278             if verbose:
    279                 print rec
    280             rec = getattr(self.cur, "next")()
    281         # all items accounted for EXCEPT for 1 with "Blues" genre
    282         self.assertEqual(count, len(musicdata)-1)
    283 
    284         self.cur = None
    285 
    286     def getGenre(self, priKey, priData):
    287         self.assertEqual(type(priData), type(""))
    288         genre = priData.split('|')[2]
    289 
    290         if verbose:
    291             print 'getGenre key: %r data: %r' % (priKey, priData)
    292 
    293         if genre == 'Blues':
    294             return db.DB_DONOTINDEX
    295         else:
    296             return genre
    297 
    298     def getGenreList(self, priKey, PriData) :
    299         v = self.getGenre(priKey, PriData)
    300         if type(v) == type("") :
    301             v = [v]
    302         return v
    303 
    304 
    305 #----------------------------------------------------------------------
    306 
    307 
    308 class AssociateHashTestCase(AssociateTestCase):
    309     dbtype = db.DB_HASH
    310 
    311 class AssociateBTreeTestCase(AssociateTestCase):
    312     dbtype = db.DB_BTREE
    313 
    314 class AssociateRecnoTestCase(AssociateTestCase):
    315     dbtype = db.DB_RECNO
    316     keytype = 0
    317 
    318 #----------------------------------------------------------------------
    319 
    320 class AssociateBTreeTxnTestCase(AssociateBTreeTestCase):
    321     envFlags = db.DB_INIT_TXN
    322     dbFlags = 0
    323 
    324     def txn_finish_test(self, sDB, txn):
    325         try:
    326             self.finish_test(sDB, txn=txn)
    327         finally:
    328             if self.cur:
    329                 self.cur.close()
    330                 self.cur = None
    331             if txn:
    332                 txn.commit()
    333 
    334     def test13_associate_in_transaction(self):
    335         if verbose:
    336             print '\n', '-=' * 30
    337             print "Running %s.test13_associateAutoCommit..." % \
    338                   self.__class__.__name__
    339 
    340         txn = self.env.txn_begin()
    341         try:
    342             self.createDB(txn=txn)
    343 
    344             self.secDB = db.DB(self.env)
    345             self.secDB.set_flags(db.DB_DUP)
    346             self.secDB.set_get_returns_none(2)
    347             self.secDB.open(self.filename, "secondary", db.DB_BTREE,
    348                        db.DB_CREATE | db.DB_THREAD, txn=txn)
    349             self.getDB().associate(self.secDB, self.getGenre, txn=txn)
    350 
    351             self.addDataToDB(self.getDB(), txn=txn)
    352         except:
    353             txn.abort()
    354             raise
    355 
    356         self.txn_finish_test(self.secDB, txn=txn)
    357 
    358 
    359 #----------------------------------------------------------------------
    360 
    361 class ShelveAssociateTestCase(AssociateTestCase):
    362 
    363     def createDB(self):
    364         self.primary = dbshelve.open(self.filename,
    365                                      dbname="primary",
    366                                      dbenv=self.env,
    367                                      filetype=self.dbtype)
    368 
    369     def addDataToDB(self, d):
    370         for key, value in musicdata.items():
    371             if type(self.keytype) == type(''):
    372                 key = "%02d" % key
    373             d.put(key, value)    # save the value as is this time
    374 
    375 
    376     def getGenre(self, priKey, priData):
    377         self.assertEqual(type(priData), type(()))
    378         if verbose:
    379             print 'getGenre key: %r data: %r' % (priKey, priData)
    380         genre = priData[2]
    381         if genre == 'Blues':
    382             return db.DB_DONOTINDEX
    383         else:
    384             return genre
    385 
    386 
    387 class ShelveAssociateHashTestCase(ShelveAssociateTestCase):
    388     dbtype = db.DB_HASH
    389 
    390 class ShelveAssociateBTreeTestCase(ShelveAssociateTestCase):
    391     dbtype = db.DB_BTREE
    392 
    393 class ShelveAssociateRecnoTestCase(ShelveAssociateTestCase):
    394     dbtype = db.DB_RECNO
    395     keytype = 0
    396 
    397 
    398 #----------------------------------------------------------------------
    399 
    400 class ThreadedAssociateTestCase(AssociateTestCase):
    401 
    402     def addDataToDB(self, d):
    403         t1 = Thread(target = self.writer1,
    404                     args = (d, ))
    405         t2 = Thread(target = self.writer2,
    406                     args = (d, ))
    407 
    408         t1.setDaemon(True)
    409         t2.setDaemon(True)
    410         t1.start()
    411         t2.start()
    412         t1.join()
    413         t2.join()
    414 
    415     def writer1(self, d):
    416         for key, value in musicdata.items():
    417             if type(self.keytype) == type(''):
    418                 key = "%02d" % key
    419             d.put(key, '|'.join(value))
    420 
    421     def writer2(self, d):
    422         for x in range(100, 600):
    423             key = 'z%2d' % x
    424             value = [key] * 4
    425             d.put(key, '|'.join(value))
    426 
    427 
    428 class ThreadedAssociateHashTestCase(ShelveAssociateTestCase):
    429     dbtype = db.DB_HASH
    430 
    431 class ThreadedAssociateBTreeTestCase(ShelveAssociateTestCase):
    432     dbtype = db.DB_BTREE
    433 
    434 class ThreadedAssociateRecnoTestCase(ShelveAssociateTestCase):
    435     dbtype = db.DB_RECNO
    436     keytype = 0
    437 
    438 
    439 #----------------------------------------------------------------------
    440 
    441 def test_suite():
    442     suite = unittest.TestSuite()
    443 
    444     suite.addTest(unittest.makeSuite(AssociateErrorTestCase))
    445 
    446     suite.addTest(unittest.makeSuite(AssociateHashTestCase))
    447     suite.addTest(unittest.makeSuite(AssociateBTreeTestCase))
    448     suite.addTest(unittest.makeSuite(AssociateRecnoTestCase))
    449 
    450     suite.addTest(unittest.makeSuite(AssociateBTreeTxnTestCase))
    451 
    452     suite.addTest(unittest.makeSuite(ShelveAssociateHashTestCase))
    453     suite.addTest(unittest.makeSuite(ShelveAssociateBTreeTestCase))
    454     suite.addTest(unittest.makeSuite(ShelveAssociateRecnoTestCase))
    455 
    456     if have_threads:
    457         suite.addTest(unittest.makeSuite(ThreadedAssociateHashTestCase))
    458         suite.addTest(unittest.makeSuite(ThreadedAssociateBTreeTestCase))
    459         suite.addTest(unittest.makeSuite(ThreadedAssociateRecnoTestCase))
    460 
    461     return suite
    462 
    463 
    464 if __name__ == '__main__':
    465     unittest.main(defaultTest='test_suite')
    466