/bravo/tests/test_world.py

https://github.com/mmcgill/bravo · Python · 238 lines · 153 code · 52 blank · 33 comment · 6 complexity · 77f76eca184ae0b640232c2f3745bea5 MD5 · raw file

  1. from twisted.trial import unittest
  2. from twisted.internet.defer import inlineCallbacks
  3. import numpy
  4. import shutil
  5. import tempfile
  6. from itertools import product
  7. import bravo.config
  8. from bravo.errors import ChunkNotLoaded, SerializerReadException
  9. from bravo.world import World
  10. class TestWorldChunks(unittest.TestCase):
  11. def setUp(self):
  12. self.name = "unittest"
  13. self.d = tempfile.mkdtemp()
  14. bravo.config.configuration.add_section("world unittest")
  15. bravo.config.configuration.set("world unittest", "url", "file://%s" % self.d)
  16. bravo.config.configuration.set("world unittest", "serializer",
  17. "alpha")
  18. self.w = World(self.name)
  19. self.w.pipeline = []
  20. self.w.start()
  21. def tearDown(self):
  22. self.w.stop()
  23. del self.w
  24. shutil.rmtree(self.d)
  25. bravo.config.configuration.remove_section("world unittest")
  26. def test_trivial(self):
  27. pass
  28. @inlineCallbacks
  29. def test_get_block(self):
  30. chunk = yield self.w.request_chunk(0, 0)
  31. # Fill the chunk with random stuff.
  32. chunk.blocks = numpy.fromstring(numpy.random.bytes(chunk.blocks.size),
  33. dtype=numpy.uint8)
  34. chunk.blocks.shape = (16, 16, 128)
  35. for x, y, z in product(xrange(2), repeat=3):
  36. # This works because the chunk is at (0, 0) so the coords don't
  37. # need to be adjusted.
  38. block = yield self.w.get_block((x, y, z))
  39. self.assertEqual(block, chunk.get_block((x, y, z)))
  40. @inlineCallbacks
  41. def test_get_metadata(self):
  42. chunk = yield self.w.request_chunk(0, 0)
  43. # Fill the chunk with random stuff.
  44. chunk.metadata = numpy.fromstring(numpy.random.bytes(chunk.blocks.size),
  45. dtype=numpy.uint8)
  46. chunk.metadata.shape = (16, 16, 128)
  47. for x, y, z in product(xrange(2), repeat=3):
  48. # This works because the chunk is at (0, 0) so the coords don't
  49. # need to be adjusted.
  50. metadata = yield self.w.get_metadata((x, y, z))
  51. self.assertEqual(metadata, chunk.get_metadata((x, y, z)))
  52. @inlineCallbacks
  53. def test_get_block_readback(self):
  54. chunk = yield self.w.request_chunk(0, 0)
  55. # Fill the chunk with random stuff.
  56. chunk.blocks = numpy.fromstring(numpy.random.bytes(chunk.blocks.size),
  57. dtype=numpy.uint8)
  58. chunk.blocks.shape = (16, 16, 128)
  59. # Evict the chunk and grab it again.
  60. self.w.save_chunk(chunk)
  61. del chunk
  62. self.w.chunk_cache.clear()
  63. self.w.dirty_chunk_cache.clear()
  64. chunk = yield self.w.request_chunk(0, 0)
  65. for x, y, z in product(xrange(2), repeat=3):
  66. # This works because the chunk is at (0, 0) so the coords don't
  67. # need to be adjusted.
  68. block = yield self.w.get_block((x, y, z))
  69. self.assertEqual(block, chunk.get_block((x, y, z)))
  70. @inlineCallbacks
  71. def test_get_block_readback_negative(self):
  72. chunk = yield self.w.request_chunk(-1, -1)
  73. # Fill the chunk with random stuff.
  74. chunk.blocks = numpy.fromstring(numpy.random.bytes(chunk.blocks.size),
  75. dtype=numpy.uint8)
  76. chunk.blocks.shape = (16, 16, 128)
  77. # Evict the chunk and grab it again.
  78. self.w.save_chunk(chunk)
  79. del chunk
  80. self.w.chunk_cache.clear()
  81. self.w.dirty_chunk_cache.clear()
  82. chunk = yield self.w.request_chunk(-1, -1)
  83. for x, y, z in product(xrange(2), repeat=3):
  84. block = yield self.w.get_block((x - 16, y, z - 16))
  85. self.assertEqual(block, chunk.get_block((x, y, z)))
  86. @inlineCallbacks
  87. def test_get_metadata_readback(self):
  88. chunk = yield self.w.request_chunk(0, 0)
  89. # Fill the chunk with random stuff.
  90. chunk.metadata = numpy.fromstring(numpy.random.bytes(chunk.blocks.size),
  91. dtype=numpy.uint8)
  92. chunk.metadata.shape = (16, 16, 128)
  93. # Evict the chunk and grab it again.
  94. self.w.save_chunk(chunk)
  95. del chunk
  96. self.w.chunk_cache.clear()
  97. self.w.dirty_chunk_cache.clear()
  98. chunk = yield self.w.request_chunk(0, 0)
  99. for x, y, z in product(xrange(2), repeat=3):
  100. # This works because the chunk is at (0, 0) so the coords don't
  101. # need to be adjusted.
  102. metadata = yield self.w.get_metadata((x, y, z))
  103. self.assertEqual(metadata, chunk.get_metadata((x, y, z)))
  104. @inlineCallbacks
  105. def test_world_level_mark_chunk_dirty(self):
  106. chunk = yield self.w.request_chunk(0, 0)
  107. # Reload chunk.
  108. self.w.save_chunk(chunk)
  109. del chunk
  110. self.w.chunk_cache.clear()
  111. self.w.dirty_chunk_cache.clear()
  112. chunk = yield self.w.request_chunk(0, 0)
  113. self.assertFalse(chunk.dirty)
  114. self.w.mark_dirty((12, 64, 4))
  115. chunk = yield self.w.request_chunk(0, 0)
  116. self.assertTrue(chunk.dirty)
  117. @inlineCallbacks
  118. def test_world_level_mark_chunk_dirty_offset(self):
  119. chunk = yield self.w.request_chunk(1, 2)
  120. # Reload chunk.
  121. self.w.save_chunk(chunk)
  122. del chunk
  123. self.w.chunk_cache.clear()
  124. self.w.dirty_chunk_cache.clear()
  125. chunk = yield self.w.request_chunk(1, 2)
  126. self.assertFalse(chunk.dirty)
  127. self.w.mark_dirty((29, 64, 43))
  128. chunk = yield self.w.request_chunk(1, 2)
  129. self.assertTrue(chunk.dirty)
  130. @inlineCallbacks
  131. def test_sync_get_block(self):
  132. chunk = yield self.w.request_chunk(0, 0)
  133. # Fill the chunk with random stuff.
  134. chunk.blocks = numpy.fromstring(numpy.random.bytes(chunk.blocks.size),
  135. dtype=numpy.uint8)
  136. chunk.blocks.shape = (16, 16, 128)
  137. for x, y, z in product(xrange(2), repeat=3):
  138. # This works because the chunk is at (0, 0) so the coords don't
  139. # need to be adjusted.
  140. block = self.w.sync_get_block((x, y, z))
  141. self.assertEqual(block, chunk.get_block((x, y, z)))
  142. def test_sync_get_block_unloaded(self):
  143. self.assertRaises(ChunkNotLoaded, self.w.sync_get_block, (0, 0, 0))
  144. def test_sync_get_metadata_neighboring(self):
  145. """
  146. Even if a neighboring chunk is loaded, the target chunk could still be
  147. unloaded.
  148. Test with sync_get_metadata() to increase test coverage.
  149. """
  150. d = self.w.request_chunk(0, 0)
  151. @d.addCallback
  152. def cb(chunk):
  153. self.assertRaises(ChunkNotLoaded,
  154. self.w.sync_get_metadata, (16, 0, 0))
  155. return d
  156. class TestWorld(unittest.TestCase):
  157. def setUp(self):
  158. self.name = "unittest"
  159. self.d = tempfile.mkdtemp()
  160. bravo.config.configuration.add_section("world unittest")
  161. bravo.config.configuration.set("world unittest", "url", "file://%s" % self.d)
  162. bravo.config.configuration.set("world unittest", "serializer",
  163. "alpha")
  164. self.w = World(self.name)
  165. self.w.pipeline = []
  166. self.w.start()
  167. def tearDown(self):
  168. self.w.stop()
  169. del self.w
  170. shutil.rmtree(self.d)
  171. bravo.config.configuration.remove_section("world unittest")
  172. def test_trivial(self):
  173. pass
  174. def test_load_player_initial(self):
  175. """
  176. Calling load_player() on a player which has never been loaded should
  177. not result in an exception. Instead, the player should be returned,
  178. wrapped in a Deferred.
  179. """
  180. # For bonus points, assert that the player's username is correct.
  181. d = self.w.load_player("unittest")
  182. @d.addCallback
  183. def cb(player):
  184. self.assertEqual(player.username, "unittest")
  185. return d