git_cache_test.py 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  1. #!/usr/bin/env vpython3
  2. # Copyright 2015 The Chromium Authors. All rights reserved.
  3. # Use of this source code is governed by a BSD-style license that can be
  4. # found in the LICENSE file.
  5. """Unit tests for git_cache.py"""
  6. import os
  7. import shutil
  8. import subprocess
  9. import sys
  10. import tempfile
  11. import unittest
  12. if sys.version_info.major == 2:
  13. from StringIO import StringIO
  14. import mock
  15. else:
  16. from io import StringIO
  17. from unittest import mock
  18. DEPOT_TOOLS_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
  19. sys.path.insert(0, DEPOT_TOOLS_ROOT)
  20. from testing_support import coverage_utils
  21. import git_cache
  22. class GitCacheTest(unittest.TestCase):
  23. def setUp(self):
  24. self.cache_dir = tempfile.mkdtemp(prefix='git_cache_test_')
  25. self.addCleanup(shutil.rmtree, self.cache_dir, ignore_errors=True)
  26. self.origin_dir = tempfile.mkdtemp(suffix='origin.git')
  27. self.addCleanup(shutil.rmtree, self.origin_dir, ignore_errors=True)
  28. git_cache.Mirror.SetCachePath(self.cache_dir)
  29. def git(self, cmd, cwd=None):
  30. cwd = cwd or self.origin_dir
  31. git = 'git.bat' if sys.platform == 'win32' else 'git'
  32. subprocess.check_call([git] + cmd, cwd=cwd)
  33. def testParseFetchSpec(self):
  34. testData = [
  35. ([], []),
  36. (['master'], [('+refs/heads/master:refs/heads/master',
  37. r'\+refs/heads/master:.*')]),
  38. (['master/'], [('+refs/heads/master:refs/heads/master',
  39. r'\+refs/heads/master:.*')]),
  40. (['+master'], [('+refs/heads/master:refs/heads/master',
  41. r'\+refs/heads/master:.*')]),
  42. (['refs/heads/*'], [('+refs/heads/*:refs/heads/*',
  43. r'\+refs/heads/\*:.*')]),
  44. (['foo/bar/*', 'baz'], [('+refs/heads/foo/bar/*:refs/heads/foo/bar/*',
  45. r'\+refs/heads/foo/bar/\*:.*'),
  46. ('+refs/heads/baz:refs/heads/baz',
  47. r'\+refs/heads/baz:.*')]),
  48. (['refs/foo/*:refs/bar/*'], [('+refs/foo/*:refs/bar/*',
  49. r'\+refs/foo/\*:.*')])
  50. ]
  51. mirror = git_cache.Mirror('test://phony.example.biz')
  52. for fetch_specs, expected in testData:
  53. mirror = git_cache.Mirror('test://phony.example.biz', refs=fetch_specs)
  54. self.assertEqual(mirror.fetch_specs, set(expected))
  55. def testPopulate(self):
  56. self.git(['init', '-q'])
  57. with open(os.path.join(self.origin_dir, 'foo'), 'w') as f:
  58. f.write('touched\n')
  59. self.git(['add', 'foo'])
  60. self.git(['commit', '-m', 'foo'])
  61. mirror = git_cache.Mirror(self.origin_dir)
  62. mirror.populate()
  63. def testPopulateResetFetchConfig(self):
  64. self.git(['init', '-q'])
  65. with open(os.path.join(self.origin_dir, 'foo'), 'w') as f:
  66. f.write('touched\n')
  67. self.git(['add', 'foo'])
  68. self.git(['commit', '-m', 'foo'])
  69. mirror = git_cache.Mirror(self.origin_dir)
  70. mirror.populate()
  71. # Add a bad refspec to the cache's fetch config.
  72. cache_dir = os.path.join(
  73. self.cache_dir, mirror.UrlToCacheDir(self.origin_dir))
  74. self.git(['config', '--add', 'remote.origin.fetch',
  75. '+refs/heads/foo:refs/heads/foo'],
  76. cwd=cache_dir)
  77. mirror.populate(reset_fetch_config=True)
  78. def testPopulateTwice(self):
  79. self.git(['init', '-q'])
  80. with open(os.path.join(self.origin_dir, 'foo'), 'w') as f:
  81. f.write('touched\n')
  82. self.git(['add', 'foo'])
  83. self.git(['commit', '-m', 'foo'])
  84. mirror = git_cache.Mirror(self.origin_dir)
  85. mirror.populate()
  86. mirror.populate()
  87. @mock.patch('sys.stdout', StringIO())
  88. def testPruneRequired(self):
  89. self.git(['init', '-q'])
  90. with open(os.path.join(self.origin_dir, 'foo'), 'w') as f:
  91. f.write('touched\n')
  92. self.git(['checkout', '-b', 'foo'])
  93. self.git(['add', 'foo'])
  94. self.git(['commit', '-m', 'foo'])
  95. mirror = git_cache.Mirror(self.origin_dir)
  96. mirror.populate()
  97. self.git(['checkout', '-b', 'foo_tmp', 'foo'])
  98. self.git(['branch', '-D', 'foo'])
  99. self.git(['checkout', '-b', 'foo/bar', 'foo_tmp'])
  100. mirror.populate()
  101. self.assertNotIn(git_cache.GIT_CACHE_CORRUPT_MESSAGE, sys.stdout.getvalue())
  102. def _makeGitRepoWithTag(self):
  103. self.git(['init', '-q'])
  104. with open(os.path.join(self.origin_dir, 'foo'), 'w') as f:
  105. f.write('touched\n')
  106. self.git(['add', 'foo'])
  107. self.git(['commit', '-m', 'foo'])
  108. self.git(['tag', 'TAG'])
  109. self.git(['pack-refs'])
  110. def testPopulateFetchTagsByDefault(self):
  111. self._makeGitRepoWithTag()
  112. # Default behaviour includes tags.
  113. mirror = git_cache.Mirror(self.origin_dir)
  114. mirror.populate()
  115. cache_dir = os.path.join(self.cache_dir,
  116. mirror.UrlToCacheDir(self.origin_dir))
  117. self.assertTrue(os.path.exists(cache_dir + '/refs/tags/TAG'))
  118. def testPopulateFetchWithoutTags(self):
  119. self._makeGitRepoWithTag()
  120. # Ask to not include tags.
  121. mirror = git_cache.Mirror(self.origin_dir)
  122. mirror.populate(no_fetch_tags=True)
  123. cache_dir = os.path.join(self.cache_dir,
  124. mirror.UrlToCacheDir(self.origin_dir))
  125. self.assertFalse(os.path.exists(cache_dir + '/refs/tags/TAG'))
  126. def testPopulateResetFetchConfigEmptyFetchConfig(self):
  127. self.git(['init', '-q'])
  128. with open(os.path.join(self.origin_dir, 'foo'), 'w') as f:
  129. f.write('touched\n')
  130. self.git(['add', 'foo'])
  131. self.git(['commit', '-m', 'foo'])
  132. mirror = git_cache.Mirror(self.origin_dir)
  133. mirror.populate(reset_fetch_config=True)
  134. class GitCacheDirTest(unittest.TestCase):
  135. def setUp(self):
  136. try:
  137. delattr(git_cache.Mirror, 'cachepath')
  138. except AttributeError:
  139. pass
  140. super(GitCacheDirTest, self).setUp()
  141. def tearDown(self):
  142. try:
  143. delattr(git_cache.Mirror, 'cachepath')
  144. except AttributeError:
  145. pass
  146. super(GitCacheDirTest, self).tearDown()
  147. def test_git_config_read(self):
  148. (fd, tmpFile) = tempfile.mkstemp()
  149. old = git_cache.Mirror._GIT_CONFIG_LOCATION
  150. try:
  151. try:
  152. os.write(fd, b'[cache]\n cachepath="hello world"\n')
  153. finally:
  154. os.close(fd)
  155. git_cache.Mirror._GIT_CONFIG_LOCATION = ['-f', tmpFile]
  156. self.assertEqual(git_cache.Mirror.GetCachePath(), 'hello world')
  157. finally:
  158. git_cache.Mirror._GIT_CONFIG_LOCATION = old
  159. os.remove(tmpFile)
  160. def test_environ_read(self):
  161. path = os.environ.get('GIT_CACHE_PATH')
  162. config = os.environ.get('GIT_CONFIG')
  163. try:
  164. os.environ['GIT_CACHE_PATH'] = 'hello world'
  165. os.environ['GIT_CONFIG'] = 'disabled'
  166. self.assertEqual(git_cache.Mirror.GetCachePath(), 'hello world')
  167. finally:
  168. for name, val in zip(('GIT_CACHE_PATH', 'GIT_CONFIG'), (path, config)):
  169. if val is None:
  170. os.environ.pop(name, None)
  171. else:
  172. os.environ[name] = val
  173. def test_manual_set(self):
  174. git_cache.Mirror.SetCachePath('hello world')
  175. self.assertEqual(git_cache.Mirror.GetCachePath(), 'hello world')
  176. def test_unconfigured(self):
  177. path = os.environ.get('GIT_CACHE_PATH')
  178. config = os.environ.get('GIT_CONFIG')
  179. try:
  180. os.environ.pop('GIT_CACHE_PATH', None)
  181. os.environ['GIT_CONFIG'] = 'disabled'
  182. with self.assertRaisesRegexp(RuntimeError, 'cache\.cachepath'):
  183. git_cache.Mirror.GetCachePath()
  184. # negatively cached value still raises
  185. with self.assertRaisesRegexp(RuntimeError, 'cache\.cachepath'):
  186. git_cache.Mirror.GetCachePath()
  187. finally:
  188. for name, val in zip(('GIT_CACHE_PATH', 'GIT_CONFIG'), (path, config)):
  189. if val is None:
  190. os.environ.pop(name, None)
  191. else:
  192. os.environ[name] = val
  193. class MirrorTest(unittest.TestCase):
  194. def test_same_cache_for_authenticated_and_unauthenticated_urls(self):
  195. # GoB can fetch a repo via two different URLs; if the url contains '/a/'
  196. # it forces authenticated access instead of allowing anonymous access,
  197. # even in the case where a repo is public. We want this in order to make
  198. # sure bots are authenticated and get the right quotas. However, we
  199. # only want to maintain a single cache for the repo.
  200. self.assertEqual(git_cache.Mirror.UrlToCacheDir(
  201. 'https://chromium.googlesource.com/a/chromium/src.git'),
  202. 'chromium.googlesource.com-chromium-src')
  203. if __name__ == '__main__':
  204. sys.exit(coverage_utils.covered_main((
  205. os.path.join(DEPOT_TOOLS_ROOT, 'git_cache.py')
  206. ), required_percentage=0))