/Lib/bsddb/test/test_early_close.py

http://unladen-swallow.googlecode.com/ · Python · 195 lines · 145 code · 35 blank · 15 comment · 17 complexity · d428f7eac61bfccc96b635d4158a2566 MD5 · raw file

  1. """TestCases for checking that it does not segfault when a DBEnv object
  2. is closed before its DB objects.
  3. """
  4. import os
  5. import unittest
  6. from test_all import db, test_support, verbose, get_new_environment_path, get_new_database_path
  7. # We're going to get warnings in this module about trying to close the db when
  8. # its env is already closed. Let's just ignore those.
  9. try:
  10. import warnings
  11. except ImportError:
  12. pass
  13. else:
  14. warnings.filterwarnings('ignore',
  15. message='DB could not be closed in',
  16. category=RuntimeWarning)
  17. #----------------------------------------------------------------------
  18. class DBEnvClosedEarlyCrash(unittest.TestCase):
  19. def setUp(self):
  20. self.homeDir = get_new_environment_path()
  21. self.filename = "test"
  22. def tearDown(self):
  23. test_support.rmtree(self.homeDir)
  24. def test01_close_dbenv_before_db(self):
  25. dbenv = db.DBEnv()
  26. dbenv.open(self.homeDir,
  27. db.DB_INIT_CDB| db.DB_CREATE |db.DB_THREAD|db.DB_INIT_MPOOL,
  28. 0666)
  29. d = db.DB(dbenv)
  30. d2 = db.DB(dbenv)
  31. d.open(self.filename, db.DB_BTREE, db.DB_CREATE | db.DB_THREAD, 0666)
  32. self.assertRaises(db.DBNoSuchFileError, d2.open,
  33. self.filename+"2", db.DB_BTREE, db.DB_THREAD, 0666)
  34. d.put("test","this is a test")
  35. self.assertEqual(d.get("test"), "this is a test", "put!=get")
  36. dbenv.close() # This "close" should close the child db handle also
  37. self.assertRaises(db.DBError, d.get, "test")
  38. def test02_close_dbenv_before_dbcursor(self):
  39. dbenv = db.DBEnv()
  40. dbenv.open(self.homeDir,
  41. db.DB_INIT_CDB| db.DB_CREATE |db.DB_THREAD|db.DB_INIT_MPOOL,
  42. 0666)
  43. d = db.DB(dbenv)
  44. d.open(self.filename, db.DB_BTREE, db.DB_CREATE | db.DB_THREAD, 0666)
  45. d.put("test","this is a test")
  46. d.put("test2","another test")
  47. d.put("test3","another one")
  48. self.assertEqual(d.get("test"), "this is a test", "put!=get")
  49. c=d.cursor()
  50. c.first()
  51. c.next()
  52. d.close() # This "close" should close the child db handle also
  53. # db.close should close the child cursor
  54. self.assertRaises(db.DBError,c.next)
  55. d = db.DB(dbenv)
  56. d.open(self.filename, db.DB_BTREE, db.DB_CREATE | db.DB_THREAD, 0666)
  57. c=d.cursor()
  58. c.first()
  59. c.next()
  60. dbenv.close()
  61. # The "close" should close the child db handle also, with cursors
  62. self.assertRaises(db.DBError, c.next)
  63. def test03_close_db_before_dbcursor_without_env(self):
  64. import os.path
  65. path=os.path.join(self.homeDir,self.filename)
  66. d = db.DB()
  67. d.open(path, db.DB_BTREE, db.DB_CREATE | db.DB_THREAD, 0666)
  68. d.put("test","this is a test")
  69. d.put("test2","another test")
  70. d.put("test3","another one")
  71. self.assertEqual(d.get("test"), "this is a test", "put!=get")
  72. c=d.cursor()
  73. c.first()
  74. c.next()
  75. d.close()
  76. # The "close" should close the child db handle also
  77. self.assertRaises(db.DBError, c.next)
  78. def test04_close_massive(self):
  79. dbenv = db.DBEnv()
  80. dbenv.open(self.homeDir,
  81. db.DB_INIT_CDB| db.DB_CREATE |db.DB_THREAD|db.DB_INIT_MPOOL,
  82. 0666)
  83. dbs=[db.DB(dbenv) for i in xrange(16)]
  84. cursors=[]
  85. for i in dbs :
  86. i.open(self.filename, db.DB_BTREE, db.DB_CREATE | db.DB_THREAD, 0666)
  87. dbs[10].put("test","this is a test")
  88. dbs[10].put("test2","another test")
  89. dbs[10].put("test3","another one")
  90. self.assertEqual(dbs[4].get("test"), "this is a test", "put!=get")
  91. for i in dbs :
  92. cursors.extend([i.cursor() for j in xrange(32)])
  93. for i in dbs[::3] :
  94. i.close()
  95. for i in cursors[::3] :
  96. i.close()
  97. # Check for missing exception in DB! (after DB close)
  98. self.assertRaises(db.DBError, dbs[9].get, "test")
  99. # Check for missing exception in DBCursor! (after DB close)
  100. self.assertRaises(db.DBError, cursors[101].first)
  101. cursors[80].first()
  102. cursors[80].next()
  103. dbenv.close() # This "close" should close the child db handle also
  104. # Check for missing exception! (after DBEnv close)
  105. self.assertRaises(db.DBError, cursors[80].next)
  106. def test05_close_dbenv_delete_db_success(self):
  107. dbenv = db.DBEnv()
  108. dbenv.open(self.homeDir,
  109. db.DB_INIT_CDB| db.DB_CREATE |db.DB_THREAD|db.DB_INIT_MPOOL,
  110. 0666)
  111. d = db.DB(dbenv)
  112. d.open(self.filename, db.DB_BTREE, db.DB_CREATE | db.DB_THREAD, 0666)
  113. dbenv.close() # This "close" should close the child db handle also
  114. del d
  115. try:
  116. import gc
  117. except ImportError:
  118. gc = None
  119. if gc:
  120. # force d.__del__ [DB_dealloc] to be called
  121. gc.collect()
  122. def test06_close_txn_before_dup_cursor(self) :
  123. dbenv = db.DBEnv()
  124. dbenv.open(self.homeDir,db.DB_INIT_TXN | db.DB_INIT_MPOOL |
  125. db.DB_INIT_LOG | db.DB_CREATE)
  126. d = db.DB(dbenv)
  127. txn = dbenv.txn_begin()
  128. if db.version() < (4,1) :
  129. d.open(self.filename, dbtype = db.DB_HASH, flags = db.DB_CREATE)
  130. else :
  131. d.open(self.filename, dbtype = db.DB_HASH, flags = db.DB_CREATE,
  132. txn=txn)
  133. d.put("XXX", "yyy", txn=txn)
  134. txn.commit()
  135. txn = dbenv.txn_begin()
  136. c1 = d.cursor(txn)
  137. c2 = c1.dup()
  138. self.assertEquals(("XXX", "yyy"), c1.first())
  139. import warnings
  140. # Not interested in warnings about implicit close.
  141. with warnings.catch_warnings():
  142. warnings.simplefilter("ignore")
  143. txn.commit()
  144. self.assertRaises(db.DBCursorClosedError, c2.first)
  145. if db.version() > (4,3,0) :
  146. def test07_close_db_before_sequence(self):
  147. import os.path
  148. path=os.path.join(self.homeDir,self.filename)
  149. d = db.DB()
  150. d.open(path, db.DB_BTREE, db.DB_CREATE | db.DB_THREAD, 0666)
  151. dbs=db.DBSequence(d)
  152. d.close() # This "close" should close the child DBSequence also
  153. dbs.close() # If not closed, core dump (in Berkeley DB 4.6.*)
  154. #----------------------------------------------------------------------
  155. def test_suite():
  156. suite = unittest.TestSuite()
  157. suite.addTest(unittest.makeSuite(DBEnvClosedEarlyCrash))
  158. return suite
  159. if __name__ == '__main__':
  160. unittest.main(defaultTest='test_suite')