Funktionierender Prototyp des Serious Games zur Vermittlung von Wissen zu Software-Engineering-Arbeitsmodellen.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

test_dirdbm.py 6.7KB

1 year ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. # Copyright (c) Twisted Matrix Laboratories.
  2. # See LICENSE for details.
  3. """
  4. Test cases for dirdbm module.
  5. """
  6. import shutil
  7. from base64 import b64decode
  8. from twisted.persisted import dirdbm
  9. from twisted.python import rebuild
  10. from twisted.python.filepath import FilePath
  11. from twisted.trial import unittest
  12. class DirDbmTests(unittest.TestCase):
  13. def setUp(self):
  14. self.path = FilePath(self.mktemp())
  15. self.dbm = dirdbm.open(self.path.path)
  16. self.items = ((b"abc", b"foo"), (b"/lalal", b"\000\001"), (b"\000\012", b"baz"))
  17. def test_all(self):
  18. k = b64decode("//==")
  19. self.dbm[k] = b"a"
  20. self.dbm[k] = b"a"
  21. self.assertEqual(self.dbm[k], b"a")
  22. def test_rebuildInteraction(self):
  23. s = dirdbm.Shelf("dirdbm.rebuild.test")
  24. s[b"key"] = b"value"
  25. rebuild.rebuild(dirdbm)
  26. def test_dbm(self):
  27. d = self.dbm
  28. # Insert keys
  29. keys = []
  30. values = set()
  31. for k, v in self.items:
  32. d[k] = v
  33. keys.append(k)
  34. values.add(v)
  35. keys.sort()
  36. # Check they exist
  37. for k, v in self.items:
  38. self.assertIn(k, d)
  39. self.assertEqual(d[k], v)
  40. # Check non existent key
  41. try:
  42. d[b"XXX"]
  43. except KeyError:
  44. pass
  45. else:
  46. assert 0, "didn't raise KeyError on non-existent key"
  47. # Check keys(), values() and items()
  48. dbkeys = d.keys()
  49. dbvalues = set(d.values())
  50. dbitems = set(d.items())
  51. dbkeys.sort()
  52. items = set(self.items)
  53. self.assertEqual(
  54. keys,
  55. dbkeys,
  56. f".keys() output didn't match: {repr(keys)} != {repr(dbkeys)}",
  57. )
  58. self.assertEqual(
  59. values,
  60. dbvalues,
  61. ".values() output didn't match: {} != {}".format(
  62. repr(values), repr(dbvalues)
  63. ),
  64. )
  65. self.assertEqual(
  66. items,
  67. dbitems,
  68. f"items() didn't match: {repr(items)} != {repr(dbitems)}",
  69. )
  70. copyPath = self.mktemp()
  71. d2 = d.copyTo(copyPath)
  72. copykeys = d.keys()
  73. copyvalues = set(d.values())
  74. copyitems = set(d.items())
  75. copykeys.sort()
  76. self.assertEqual(
  77. dbkeys,
  78. copykeys,
  79. ".copyTo().keys() didn't match: {} != {}".format(
  80. repr(dbkeys), repr(copykeys)
  81. ),
  82. )
  83. self.assertEqual(
  84. dbvalues,
  85. copyvalues,
  86. ".copyTo().values() didn't match: %s != %s"
  87. % (repr(dbvalues), repr(copyvalues)),
  88. )
  89. self.assertEqual(
  90. dbitems,
  91. copyitems,
  92. ".copyTo().items() didn't match: %s != %s"
  93. % (repr(dbkeys), repr(copyitems)),
  94. )
  95. d2.clear()
  96. self.assertTrue(
  97. len(d2.keys()) == len(d2.values()) == len(d2.items()) == len(d2) == 0,
  98. ".clear() failed",
  99. )
  100. self.assertNotEqual(len(d), len(d2))
  101. shutil.rmtree(copyPath)
  102. # Delete items
  103. for k, v in self.items:
  104. del d[k]
  105. self.assertNotIn(
  106. k, d, "key is still in database, even though we deleted it"
  107. )
  108. self.assertEqual(len(d.keys()), 0, "database has keys")
  109. self.assertEqual(len(d.values()), 0, "database has values")
  110. self.assertEqual(len(d.items()), 0, "database has items")
  111. self.assertEqual(len(d), 0, "database has items")
  112. def test_modificationTime(self):
  113. import time
  114. # The mtime value for files comes from a different place than the
  115. # gettimeofday() system call. On linux, gettimeofday() can be
  116. # slightly ahead (due to clock drift which gettimeofday() takes into
  117. # account but which open()/write()/close() do not), and if we are
  118. # close to the edge of the next second, time.time() can give a value
  119. # which is larger than the mtime which results from a subsequent
  120. # write(). I consider this a kernel bug, but it is beyond the scope
  121. # of this test. Thus we keep the range of acceptability to 3 seconds time.
  122. # -warner
  123. self.dbm[b"k"] = b"v"
  124. self.assertTrue(abs(time.time() - self.dbm.getModificationTime(b"k")) <= 3)
  125. self.assertRaises(KeyError, self.dbm.getModificationTime, b"nokey")
  126. def test_recovery(self):
  127. """
  128. DirDBM: test recovery from directory after a faked crash
  129. """
  130. k = self.dbm._encode(b"key1")
  131. with self.path.child(k + b".rpl").open(mode="wb") as f:
  132. f.write(b"value")
  133. k2 = self.dbm._encode(b"key2")
  134. with self.path.child(k2).open(mode="wb") as f:
  135. f.write(b"correct")
  136. with self.path.child(k2 + b".rpl").open(mode="wb") as f:
  137. f.write(b"wrong")
  138. with self.path.child("aa.new").open(mode="wb") as f:
  139. f.write(b"deleted")
  140. dbm = dirdbm.DirDBM(self.path.path)
  141. self.assertEqual(dbm[b"key1"], b"value")
  142. self.assertEqual(dbm[b"key2"], b"correct")
  143. self.assertFalse(self.path.globChildren("*.new"))
  144. self.assertFalse(self.path.globChildren("*.rpl"))
  145. def test_nonStringKeys(self):
  146. """
  147. L{dirdbm.DirDBM} operations only support string keys: other types
  148. should raise a L{TypeError}.
  149. """
  150. self.assertRaises(TypeError, self.dbm.__setitem__, 2, "3")
  151. try:
  152. self.assertRaises(TypeError, self.dbm.__setitem__, "2", 3)
  153. except unittest.FailTest:
  154. # dirdbm.Shelf.__setitem__ supports non-string values
  155. self.assertIsInstance(self.dbm, dirdbm.Shelf)
  156. self.assertRaises(TypeError, self.dbm.__getitem__, 2)
  157. self.assertRaises(TypeError, self.dbm.__delitem__, 2)
  158. self.assertRaises(TypeError, self.dbm.has_key, 2)
  159. self.assertRaises(TypeError, self.dbm.__contains__, 2)
  160. self.assertRaises(TypeError, self.dbm.getModificationTime, 2)
  161. def test_failSet(self):
  162. """
  163. Failure path when setting an item.
  164. """
  165. def _writeFail(path, data):
  166. path.setContent(data)
  167. raise OSError("fail to write")
  168. self.dbm[b"failkey"] = b"test"
  169. self.patch(self.dbm, "_writeFile", _writeFail)
  170. self.assertRaises(IOError, self.dbm.__setitem__, b"failkey", b"test2")
  171. class ShelfTests(DirDbmTests):
  172. def setUp(self):
  173. self.path = FilePath(self.mktemp())
  174. self.dbm = dirdbm.Shelf(self.path.path)
  175. self.items = (
  176. (b"abc", b"foo"),
  177. (b"/lalal", b"\000\001"),
  178. (b"\000\012", b"baz"),
  179. (b"int", 12),
  180. (b"float", 12.0),
  181. (b"tuple", (None, 12)),
  182. )
  183. testCases = [DirDbmTests, ShelfTests]