您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

256 行
9.1KB

  1. # Copyright (C) 2010, 2011 Sebastian Thiel (byronimo@gmail.com) and contributors
  2. #
  3. # This module is part of GitDB and is released under
  4. # the New BSD License: http://www.opensource.org/licenses/bsd-license.php
  5. """Test everything about packs reading and writing"""
  6. from gitdb.test.lib import (
  7. TestBase,
  8. with_rw_directory,
  9. fixture_path
  10. )
  11. from gitdb.stream import DeltaApplyReader
  12. from gitdb.pack import (
  13. PackEntity,
  14. PackIndexFile,
  15. PackFile
  16. )
  17. from gitdb.base import (
  18. OInfo,
  19. OStream,
  20. )
  21. from gitdb.fun import delta_types
  22. from gitdb.exc import UnsupportedOperation
  23. from gitdb.util import to_bin_sha
  24. from gitdb.utils.compat import xrange
  25. try:
  26. from itertools import izip
  27. except ImportError:
  28. izip = zip
  29. from nose import SkipTest
  30. import os
  31. import tempfile
  32. #{ Utilities
  33. def bin_sha_from_filename(filename):
  34. return to_bin_sha(os.path.splitext(os.path.basename(filename))[0][5:])
  35. #} END utilities
  36. class TestPack(TestBase):
  37. packindexfile_v1 = (fixture_path('packs/pack-c0438c19fb16422b6bbcce24387b3264416d485b.idx'), 1, 67)
  38. packindexfile_v2 = (fixture_path('packs/pack-11fdfa9e156ab73caae3b6da867192221f2089c2.idx'), 2, 30)
  39. packindexfile_v2_3_ascii = (fixture_path('packs/pack-a2bf8e71d8c18879e499335762dd95119d93d9f1.idx'), 2, 42)
  40. packfile_v2_1 = (fixture_path('packs/pack-c0438c19fb16422b6bbcce24387b3264416d485b.pack'), 2, packindexfile_v1[2])
  41. packfile_v2_2 = (fixture_path('packs/pack-11fdfa9e156ab73caae3b6da867192221f2089c2.pack'), 2, packindexfile_v2[2])
  42. packfile_v2_3_ascii = (
  43. fixture_path('packs/pack-a2bf8e71d8c18879e499335762dd95119d93d9f1.pack'), 2, packindexfile_v2_3_ascii[2])
  44. def _assert_index_file(self, index, version, size):
  45. assert index.packfile_checksum() != index.indexfile_checksum()
  46. assert len(index.packfile_checksum()) == 20
  47. assert len(index.indexfile_checksum()) == 20
  48. assert index.version() == version
  49. assert index.size() == size
  50. assert len(index.offsets()) == size
  51. # get all data of all objects
  52. for oidx in xrange(index.size()):
  53. sha = index.sha(oidx)
  54. assert oidx == index.sha_to_index(sha)
  55. entry = index.entry(oidx)
  56. assert len(entry) == 3
  57. assert entry[0] == index.offset(oidx)
  58. assert entry[1] == sha
  59. assert entry[2] == index.crc(oidx)
  60. # verify partial sha
  61. for l in (4, 8, 11, 17, 20):
  62. assert index.partial_sha_to_index(sha[:l], l * 2) == oidx
  63. # END for each object index in indexfile
  64. self.failUnlessRaises(ValueError, index.partial_sha_to_index, "\0", 2)
  65. def _assert_pack_file(self, pack, version, size):
  66. assert pack.version() == 2
  67. assert pack.size() == size
  68. assert len(pack.checksum()) == 20
  69. num_obj = 0
  70. for obj in pack.stream_iter():
  71. num_obj += 1
  72. info = pack.info(obj.pack_offset)
  73. stream = pack.stream(obj.pack_offset)
  74. assert info.pack_offset == stream.pack_offset
  75. assert info.type_id == stream.type_id
  76. assert hasattr(stream, 'read')
  77. # it should be possible to read from both streams
  78. assert obj.read() == stream.read()
  79. streams = pack.collect_streams(obj.pack_offset)
  80. assert streams
  81. # read the stream
  82. try:
  83. dstream = DeltaApplyReader.new(streams)
  84. except ValueError:
  85. # ignore these, old git versions use only ref deltas,
  86. # which we havent resolved ( as we are without an index )
  87. # Also ignore non-delta streams
  88. continue
  89. # END get deltastream
  90. # read all
  91. data = dstream.read()
  92. assert len(data) == dstream.size
  93. # test seek
  94. dstream.seek(0)
  95. assert dstream.read() == data
  96. # read chunks
  97. # NOTE: the current implementation is safe, it basically transfers
  98. # all calls to the underlying memory map
  99. # END for each object
  100. assert num_obj == size
  101. def test_pack_index(self):
  102. # check version 1 and 2
  103. for indexfile, version, size in (self.packindexfile_v1, self.packindexfile_v2):
  104. index = PackIndexFile(indexfile)
  105. self._assert_index_file(index, version, size)
  106. # END run tests
  107. def test_pack(self):
  108. # there is this special version 3, but apparently its like 2 ...
  109. for packfile, version, size in (self.packfile_v2_3_ascii, self.packfile_v2_1, self.packfile_v2_2):
  110. pack = PackFile(packfile)
  111. self._assert_pack_file(pack, version, size)
  112. # END for each pack to test
  113. @with_rw_directory
  114. def test_pack_entity(self, rw_dir):
  115. pack_objs = list()
  116. for packinfo, indexinfo in ((self.packfile_v2_1, self.packindexfile_v1),
  117. (self.packfile_v2_2, self.packindexfile_v2),
  118. (self.packfile_v2_3_ascii, self.packindexfile_v2_3_ascii)):
  119. packfile, version, size = packinfo
  120. indexfile, version, size = indexinfo
  121. entity = PackEntity(packfile)
  122. assert entity.pack().path() == packfile
  123. assert entity.index().path() == indexfile
  124. pack_objs.extend(entity.stream_iter())
  125. count = 0
  126. for info, stream in izip(entity.info_iter(), entity.stream_iter()):
  127. count += 1
  128. assert info.binsha == stream.binsha
  129. assert len(info.binsha) == 20
  130. assert info.type_id == stream.type_id
  131. assert info.size == stream.size
  132. # we return fully resolved items, which is implied by the sha centric access
  133. assert not info.type_id in delta_types
  134. # try all calls
  135. assert len(entity.collect_streams(info.binsha))
  136. oinfo = entity.info(info.binsha)
  137. assert isinstance(oinfo, OInfo)
  138. assert oinfo.binsha is not None
  139. ostream = entity.stream(info.binsha)
  140. assert isinstance(ostream, OStream)
  141. assert ostream.binsha is not None
  142. # verify the stream
  143. try:
  144. assert entity.is_valid_stream(info.binsha, use_crc=True)
  145. except UnsupportedOperation:
  146. pass
  147. # END ignore version issues
  148. assert entity.is_valid_stream(info.binsha, use_crc=False)
  149. # END for each info, stream tuple
  150. assert count == size
  151. # END for each entity
  152. # pack writing - write all packs into one
  153. # index path can be None
  154. pack_path1 = tempfile.mktemp('', "pack1", rw_dir)
  155. pack_path2 = tempfile.mktemp('', "pack2", rw_dir)
  156. index_path = tempfile.mktemp('', 'index', rw_dir)
  157. iteration = 0
  158. def rewind_streams():
  159. for obj in pack_objs:
  160. obj.stream.seek(0)
  161. # END utility
  162. for ppath, ipath, num_obj in zip((pack_path1, pack_path2),
  163. (index_path, None),
  164. (len(pack_objs), None)):
  165. iwrite = None
  166. if ipath:
  167. ifile = open(ipath, 'wb')
  168. iwrite = ifile.write
  169. # END handle ip
  170. # make sure we rewind the streams ... we work on the same objects over and over again
  171. if iteration > 0:
  172. rewind_streams()
  173. # END rewind streams
  174. iteration += 1
  175. with open(ppath, 'wb') as pfile:
  176. pack_sha, index_sha = PackEntity.write_pack(pack_objs, pfile.write, iwrite, object_count=num_obj)
  177. assert os.path.getsize(ppath) > 100
  178. # verify pack
  179. pf = PackFile(ppath)
  180. assert pf.size() == len(pack_objs)
  181. assert pf.version() == PackFile.pack_version_default
  182. assert pf.checksum() == pack_sha
  183. pf.close()
  184. # verify index
  185. if ipath is not None:
  186. ifile.close()
  187. assert os.path.getsize(ipath) > 100
  188. idx = PackIndexFile(ipath)
  189. assert idx.version() == PackIndexFile.index_version_default
  190. assert idx.packfile_checksum() == pack_sha
  191. assert idx.indexfile_checksum() == index_sha
  192. assert idx.size() == len(pack_objs)
  193. idx.close()
  194. # END verify files exist
  195. # END for each packpath, indexpath pair
  196. # verify the packs thoroughly
  197. rewind_streams()
  198. entity = PackEntity.create(pack_objs, rw_dir)
  199. count = 0
  200. for info in entity.info_iter():
  201. count += 1
  202. for use_crc in range(2):
  203. assert entity.is_valid_stream(info.binsha, use_crc)
  204. # END for each crc mode
  205. # END for each info
  206. assert count == len(pack_objs)
  207. entity.close()
  208. def test_pack_64(self):
  209. # TODO: hex-edit a pack helping us to verify that we can handle 64 byte offsets
  210. # of course without really needing such a huge pack
  211. raise SkipTest()