blob: 8cd95aedd06be1f01084c44062d0ed995049e242 [file] [log] [blame]
Edward Lemurf417d3a2019-10-02 20:28:59 +00001#!/usr/bin/env vpython3
szager@chromium.org66c8b852015-09-22 23:19:07 +00002# 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
6"""Unit tests for git_cache.py"""
7
Josip Sokcevic14a83ae2020-05-21 01:36:34 +00008import logging
szager@chromium.org66c8b852015-09-22 23:19:07 +00009import os
10import shutil
Edward Lemura11fc9b2018-07-17 22:35:47 +000011import subprocess
szager@chromium.org66c8b852015-09-22 23:19:07 +000012import sys
13import tempfile
14import unittest
15
Josip Sokcevic6afaa6c2020-05-08 18:20:17 +000016if sys.version_info.major == 2:
17 from StringIO import StringIO
18 import mock
19else:
20 from io import StringIO
21 from unittest import mock
22
szager@chromium.org66c8b852015-09-22 23:19:07 +000023DEPOT_TOOLS_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
24sys.path.insert(0, DEPOT_TOOLS_ROOT)
25
26from testing_support import coverage_utils
27import git_cache
28
29class GitCacheTest(unittest.TestCase):
Edward Lemura11fc9b2018-07-17 22:35:47 +000030 def setUp(self):
31 self.cache_dir = tempfile.mkdtemp(prefix='git_cache_test_')
32 self.addCleanup(shutil.rmtree, self.cache_dir, ignore_errors=True)
33 self.origin_dir = tempfile.mkdtemp(suffix='origin.git')
34 self.addCleanup(shutil.rmtree, self.origin_dir, ignore_errors=True)
35 git_cache.Mirror.SetCachePath(self.cache_dir)
szager@chromium.org66c8b852015-09-22 23:19:07 +000036
Edward Lemura11fc9b2018-07-17 22:35:47 +000037 def git(self, cmd, cwd=None):
38 cwd = cwd or self.origin_dir
Edward Lesmesab517542019-10-07 23:16:21 +000039 git = 'git.bat' if sys.platform == 'win32' else 'git'
40 subprocess.check_call([git] + cmd, cwd=cwd)
szager@chromium.org66c8b852015-09-22 23:19:07 +000041
42 def testParseFetchSpec(self):
43 testData = [
44 ([], []),
45 (['master'], [('+refs/heads/master:refs/heads/master',
46 r'\+refs/heads/master:.*')]),
47 (['master/'], [('+refs/heads/master:refs/heads/master',
48 r'\+refs/heads/master:.*')]),
49 (['+master'], [('+refs/heads/master:refs/heads/master',
50 r'\+refs/heads/master:.*')]),
51 (['refs/heads/*'], [('+refs/heads/*:refs/heads/*',
52 r'\+refs/heads/\*:.*')]),
53 (['foo/bar/*', 'baz'], [('+refs/heads/foo/bar/*:refs/heads/foo/bar/*',
54 r'\+refs/heads/foo/bar/\*:.*'),
55 ('+refs/heads/baz:refs/heads/baz',
56 r'\+refs/heads/baz:.*')]),
57 (['refs/foo/*:refs/bar/*'], [('+refs/foo/*:refs/bar/*',
58 r'\+refs/foo/\*:.*')])
59 ]
60
61 mirror = git_cache.Mirror('test://phony.example.biz')
62 for fetch_specs, expected in testData:
63 mirror = git_cache.Mirror('test://phony.example.biz', refs=fetch_specs)
Edward Lemurdf746d02019-07-27 00:42:46 +000064 self.assertEqual(mirror.fetch_specs, set(expected))
szager@chromium.org66c8b852015-09-22 23:19:07 +000065
Edward Lemura11fc9b2018-07-17 22:35:47 +000066 def testPopulate(self):
67 self.git(['init', '-q'])
68 with open(os.path.join(self.origin_dir, 'foo'), 'w') as f:
69 f.write('touched\n')
70 self.git(['add', 'foo'])
71 self.git(['commit', '-m', 'foo'])
72
73 mirror = git_cache.Mirror(self.origin_dir)
74 mirror.populate()
75
76 def testPopulateResetFetchConfig(self):
77 self.git(['init', '-q'])
78 with open(os.path.join(self.origin_dir, 'foo'), 'w') as f:
79 f.write('touched\n')
80 self.git(['add', 'foo'])
81 self.git(['commit', '-m', 'foo'])
82
83 mirror = git_cache.Mirror(self.origin_dir)
84 mirror.populate()
85
86 # Add a bad refspec to the cache's fetch config.
87 cache_dir = os.path.join(
88 self.cache_dir, mirror.UrlToCacheDir(self.origin_dir))
89 self.git(['config', '--add', 'remote.origin.fetch',
90 '+refs/heads/foo:refs/heads/foo'],
91 cwd=cache_dir)
92
93 mirror.populate(reset_fetch_config=True)
94
Edward Lesmes34f71ab2020-03-25 21:24:00 +000095 def testPopulateTwice(self):
96 self.git(['init', '-q'])
97 with open(os.path.join(self.origin_dir, 'foo'), 'w') as f:
98 f.write('touched\n')
99 self.git(['add', 'foo'])
100 self.git(['commit', '-m', 'foo'])
101
102 mirror = git_cache.Mirror(self.origin_dir)
103 mirror.populate()
104
105 mirror.populate()
106
Josip Sokcevic6afaa6c2020-05-08 18:20:17 +0000107 @mock.patch('sys.stdout', StringIO())
108 def testPruneRequired(self):
109 self.git(['init', '-q'])
110 with open(os.path.join(self.origin_dir, 'foo'), 'w') as f:
111 f.write('touched\n')
112 self.git(['checkout', '-b', 'foo'])
113 self.git(['add', 'foo'])
114 self.git(['commit', '-m', 'foo'])
115 mirror = git_cache.Mirror(self.origin_dir)
116 mirror.populate()
117 self.git(['checkout', '-b', 'foo_tmp', 'foo'])
118 self.git(['branch', '-D', 'foo'])
119 self.git(['checkout', '-b', 'foo/bar', 'foo_tmp'])
120 mirror.populate()
121 self.assertNotIn(git_cache.GIT_CACHE_CORRUPT_MESSAGE, sys.stdout.getvalue())
122
danakjc41f72c2019-11-05 17:12:01 +0000123 def _makeGitRepoWithTag(self):
124 self.git(['init', '-q'])
125 with open(os.path.join(self.origin_dir, 'foo'), 'w') as f:
126 f.write('touched\n')
127 self.git(['add', 'foo'])
128 self.git(['commit', '-m', 'foo'])
129 self.git(['tag', 'TAG'])
130 self.git(['pack-refs'])
131
132 def testPopulateFetchTagsByDefault(self):
133 self._makeGitRepoWithTag()
134
135 # Default behaviour includes tags.
136 mirror = git_cache.Mirror(self.origin_dir)
137 mirror.populate()
138
139 cache_dir = os.path.join(self.cache_dir,
140 mirror.UrlToCacheDir(self.origin_dir))
141 self.assertTrue(os.path.exists(cache_dir + '/refs/tags/TAG'))
142
143 def testPopulateFetchWithoutTags(self):
144 self._makeGitRepoWithTag()
145
146 # Ask to not include tags.
147 mirror = git_cache.Mirror(self.origin_dir)
148 mirror.populate(no_fetch_tags=True)
149
150 cache_dir = os.path.join(self.cache_dir,
151 mirror.UrlToCacheDir(self.origin_dir))
152 self.assertFalse(os.path.exists(cache_dir + '/refs/tags/TAG'))
Edward Lemura11fc9b2018-07-17 22:35:47 +0000153
154 def testPopulateResetFetchConfigEmptyFetchConfig(self):
155 self.git(['init', '-q'])
156 with open(os.path.join(self.origin_dir, 'foo'), 'w') as f:
157 f.write('touched\n')
158 self.git(['add', 'foo'])
159 self.git(['commit', '-m', 'foo'])
160
161 mirror = git_cache.Mirror(self.origin_dir)
162 mirror.populate(reset_fetch_config=True)
163
Robert Iannuccia19649b2018-06-29 16:31:45 +0000164
165class GitCacheDirTest(unittest.TestCase):
166 def setUp(self):
167 try:
168 delattr(git_cache.Mirror, 'cachepath')
169 except AttributeError:
170 pass
171 super(GitCacheDirTest, self).setUp()
172
173 def tearDown(self):
174 try:
175 delattr(git_cache.Mirror, 'cachepath')
176 except AttributeError:
177 pass
178 super(GitCacheDirTest, self).tearDown()
179
180 def test_git_config_read(self):
181 (fd, tmpFile) = tempfile.mkstemp()
182 old = git_cache.Mirror._GIT_CONFIG_LOCATION
183 try:
184 try:
Edward Lemurdf746d02019-07-27 00:42:46 +0000185 os.write(fd, b'[cache]\n cachepath="hello world"\n')
Robert Iannuccia19649b2018-06-29 16:31:45 +0000186 finally:
187 os.close(fd)
188
189 git_cache.Mirror._GIT_CONFIG_LOCATION = ['-f', tmpFile]
190
Edward Lesmes4c3eb702020-03-25 21:09:30 +0000191 self.assertEqual(git_cache.Mirror.GetCachePath(), 'hello world')
Robert Iannuccia19649b2018-06-29 16:31:45 +0000192 finally:
193 git_cache.Mirror._GIT_CONFIG_LOCATION = old
194 os.remove(tmpFile)
195
196 def test_environ_read(self):
197 path = os.environ.get('GIT_CACHE_PATH')
198 config = os.environ.get('GIT_CONFIG')
199 try:
200 os.environ['GIT_CACHE_PATH'] = 'hello world'
201 os.environ['GIT_CONFIG'] = 'disabled'
202
203 self.assertEqual(git_cache.Mirror.GetCachePath(), 'hello world')
204 finally:
205 for name, val in zip(('GIT_CACHE_PATH', 'GIT_CONFIG'), (path, config)):
206 if val is None:
207 os.environ.pop(name, None)
208 else:
209 os.environ[name] = val
210
211 def test_manual_set(self):
212 git_cache.Mirror.SetCachePath('hello world')
213 self.assertEqual(git_cache.Mirror.GetCachePath(), 'hello world')
214
215 def test_unconfigured(self):
216 path = os.environ.get('GIT_CACHE_PATH')
217 config = os.environ.get('GIT_CONFIG')
218 try:
219 os.environ.pop('GIT_CACHE_PATH', None)
220 os.environ['GIT_CONFIG'] = 'disabled'
221
222 with self.assertRaisesRegexp(RuntimeError, 'cache\.cachepath'):
223 git_cache.Mirror.GetCachePath()
224
225 # negatively cached value still raises
226 with self.assertRaisesRegexp(RuntimeError, 'cache\.cachepath'):
227 git_cache.Mirror.GetCachePath()
228 finally:
229 for name, val in zip(('GIT_CACHE_PATH', 'GIT_CONFIG'), (path, config)):
230 if val is None:
231 os.environ.pop(name, None)
232 else:
233 os.environ[name] = val
234
235
Dirk Prankedb589542019-04-12 21:07:01 +0000236class MirrorTest(unittest.TestCase):
237 def test_same_cache_for_authenticated_and_unauthenticated_urls(self):
238 # GoB can fetch a repo via two different URLs; if the url contains '/a/'
239 # it forces authenticated access instead of allowing anonymous access,
240 # even in the case where a repo is public. We want this in order to make
241 # sure bots are authenticated and get the right quotas. However, we
242 # only want to maintain a single cache for the repo.
243 self.assertEqual(git_cache.Mirror.UrlToCacheDir(
244 'https://chromium.googlesource.com/a/chromium/src.git'),
245 'chromium.googlesource.com-chromium-src')
246
247
szager@chromium.org66c8b852015-09-22 23:19:07 +0000248if __name__ == '__main__':
Josip Sokcevic14a83ae2020-05-21 01:36:34 +0000249 logging.basicConfig(
250 level=logging.DEBUG if '-v' in sys.argv else logging.ERROR)
szager@chromium.org66c8b852015-09-22 23:19:07 +0000251 sys.exit(coverage_utils.covered_main((
252 os.path.join(DEPOT_TOOLS_ROOT, 'git_cache.py')
253 ), required_percentage=0))