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.

209 lines
5.9KB

  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. """Utilities used in ODB testing"""
  6. from gitdb import OStream
  7. from gitdb.utils.compat import xrange
  8. import sys
  9. import random
  10. from array import array
  11. from io import BytesIO
  12. import glob
  13. import unittest
  14. import tempfile
  15. import shutil
  16. import os
  17. import gc
  18. import logging
  19. from functools import wraps
  20. #{ Bases
  21. class TestBase(unittest.TestCase):
  22. """Base class for all tests
  23. TestCase providing access to readonly repositories using the following member variables.
  24. * gitrepopath
  25. * read-only base path of the git source repository, i.e. .../git/.git
  26. """
  27. #{ Invvariants
  28. k_env_git_repo = "GITDB_TEST_GIT_REPO_BASE"
  29. #} END invariants
  30. @classmethod
  31. def setUpClass(cls):
  32. try:
  33. super(TestBase, cls).setUpClass()
  34. except AttributeError:
  35. pass
  36. cls.gitrepopath = os.environ.get(cls.k_env_git_repo)
  37. if not cls.gitrepopath:
  38. logging.info(
  39. "You can set the %s environment variable to a .git repository of your choice - defaulting to the gitdb repository", cls.k_env_git_repo)
  40. ospd = os.path.dirname
  41. cls.gitrepopath = os.path.join(ospd(ospd(ospd(__file__))), '.git')
  42. # end assure gitrepo is set
  43. assert cls.gitrepopath.endswith('.git')
  44. #} END bases
  45. #{ Decorators
  46. def skip_on_travis_ci(func):
  47. """All tests decorated with this one will raise SkipTest when run on travis ci.
  48. Use it to workaround difficult to solve issues
  49. NOTE: copied from bcore (https://github.com/Byron/bcore)"""
  50. @wraps(func)
  51. def wrapper(self, *args, **kwargs):
  52. if 'TRAVIS' in os.environ:
  53. import nose
  54. raise nose.SkipTest("Cannot run on travis-ci")
  55. # end check for travis ci
  56. return func(self, *args, **kwargs)
  57. # end wrapper
  58. return wrapper
  59. def with_rw_directory(func):
  60. """Create a temporary directory which can be written to, remove it if the
  61. test succeeds, but leave it otherwise to aid additional debugging"""
  62. def wrapper(self):
  63. path = tempfile.mktemp(prefix=func.__name__)
  64. os.mkdir(path)
  65. keep = False
  66. try:
  67. try:
  68. return func(self, path)
  69. except Exception:
  70. sys.stderr.write("Test {}.{} failed, output is at {!r}\n".format(type(self).__name__, func.__name__, path))
  71. keep = True
  72. raise
  73. finally:
  74. # Need to collect here to be sure all handles have been closed. It appears
  75. # a windows-only issue. In fact things should be deleted, as well as
  76. # memory maps closed, once objects go out of scope. For some reason
  77. # though this is not the case here unless we collect explicitly.
  78. if not keep:
  79. gc.collect()
  80. shutil.rmtree(path)
  81. # END handle exception
  82. # END wrapper
  83. wrapper.__name__ = func.__name__
  84. return wrapper
  85. def with_packs_rw(func):
  86. """Function that provides a path into which the packs for testing should be
  87. copied. Will pass on the path to the actual function afterwards"""
  88. def wrapper(self, path):
  89. src_pack_glob = fixture_path('packs/*')
  90. copy_files_globbed(src_pack_glob, path, hard_link_ok=True)
  91. return func(self, path)
  92. # END wrapper
  93. wrapper.__name__ = func.__name__
  94. return wrapper
  95. #} END decorators
  96. #{ Routines
  97. def fixture_path(relapath=''):
  98. """:return: absolute path into the fixture directory
  99. :param relapath: relative path into the fixtures directory, or ''
  100. to obtain the fixture directory itself"""
  101. return os.path.join(os.path.dirname(__file__), 'fixtures', relapath)
  102. def copy_files_globbed(source_glob, target_dir, hard_link_ok=False):
  103. """Copy all files found according to the given source glob into the target directory
  104. :param hard_link_ok: if True, hard links will be created if possible. Otherwise
  105. the files will be copied"""
  106. for src_file in glob.glob(source_glob):
  107. if hard_link_ok and hasattr(os, 'link'):
  108. target = os.path.join(target_dir, os.path.basename(src_file))
  109. try:
  110. os.link(src_file, target)
  111. except OSError:
  112. shutil.copy(src_file, target_dir)
  113. # END handle cross device links ( and resulting failure )
  114. else:
  115. shutil.copy(src_file, target_dir)
  116. # END try hard link
  117. # END for each file to copy
  118. def make_bytes(size_in_bytes, randomize=False):
  119. """:return: string with given size in bytes
  120. :param randomize: try to produce a very random stream"""
  121. actual_size = size_in_bytes // 4
  122. producer = xrange(actual_size)
  123. if randomize:
  124. producer = list(producer)
  125. random.shuffle(producer)
  126. # END randomize
  127. a = array('i', producer)
  128. return a.tostring()
  129. def make_object(type, data):
  130. """:return: bytes resembling an uncompressed object"""
  131. odata = "blob %i\0" % len(data)
  132. return odata.encode("ascii") + data
  133. def make_memory_file(size_in_bytes, randomize=False):
  134. """:return: tuple(size_of_stream, stream)
  135. :param randomize: try to produce a very random stream"""
  136. d = make_bytes(size_in_bytes, randomize)
  137. return len(d), BytesIO(d)
  138. #} END routines
  139. #{ Stream Utilities
  140. class DummyStream(object):
  141. def __init__(self):
  142. self.was_read = False
  143. self.bytes = 0
  144. self.closed = False
  145. def read(self, size):
  146. self.was_read = True
  147. self.bytes = size
  148. def close(self):
  149. self.closed = True
  150. def _assert(self):
  151. assert self.was_read
  152. class DeriveTest(OStream):
  153. def __init__(self, sha, type, size, stream, *args, **kwargs):
  154. self.myarg = kwargs.pop('myarg')
  155. self.args = args
  156. def _assert(self):
  157. assert self.args
  158. assert self.myarg
  159. #} END stream utilitiess