blob: c1f708f5d720d9932e4c9388aec5cd068584610f [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 ([], []),
Anthony Polito90b4c0f2020-11-17 18:09:21 +000045 (['main'], [('+refs/heads/main:refs/heads/main',
46 r'\+refs/heads/main:.*')]),
47 (['main/'], [('+refs/heads/main:refs/heads/main',
48 r'\+refs/heads/main:.*')]),
49 (['+main'], [('+refs/heads/main:refs/heads/main',
50 r'\+refs/heads/main:.*')]),
szager@chromium.org66c8b852015-09-22 23:19:07 +000051 (['master'], [('+refs/heads/master:refs/heads/master',
52 r'\+refs/heads/master:.*')]),
53 (['master/'], [('+refs/heads/master:refs/heads/master',
54 r'\+refs/heads/master:.*')]),
55 (['+master'], [('+refs/heads/master:refs/heads/master',
56 r'\+refs/heads/master:.*')]),
57 (['refs/heads/*'], [('+refs/heads/*:refs/heads/*',
58 r'\+refs/heads/\*:.*')]),
59 (['foo/bar/*', 'baz'], [('+refs/heads/foo/bar/*:refs/heads/foo/bar/*',
60 r'\+refs/heads/foo/bar/\*:.*'),
61 ('+refs/heads/baz:refs/heads/baz',
62 r'\+refs/heads/baz:.*')]),
63 (['refs/foo/*:refs/bar/*'], [('+refs/foo/*:refs/bar/*',
64 r'\+refs/foo/\*:.*')])
65 ]
66
67 mirror = git_cache.Mirror('test://phony.example.biz')
68 for fetch_specs, expected in testData:
69 mirror = git_cache.Mirror('test://phony.example.biz', refs=fetch_specs)
Edward Lemurdf746d02019-07-27 00:42:46 +000070 self.assertEqual(mirror.fetch_specs, set(expected))
szager@chromium.org66c8b852015-09-22 23:19:07 +000071
Edward Lemura11fc9b2018-07-17 22:35:47 +000072 def testPopulate(self):
73 self.git(['init', '-q'])
74 with open(os.path.join(self.origin_dir, 'foo'), 'w') as f:
75 f.write('touched\n')
76 self.git(['add', 'foo'])
77 self.git(['commit', '-m', 'foo'])
78
79 mirror = git_cache.Mirror(self.origin_dir)
80 mirror.populate()
81
82 def testPopulateResetFetchConfig(self):
83 self.git(['init', '-q'])
84 with open(os.path.join(self.origin_dir, 'foo'), 'w') as f:
85 f.write('touched\n')
86 self.git(['add', 'foo'])
87 self.git(['commit', '-m', 'foo'])
88
89 mirror = git_cache.Mirror(self.origin_dir)
90 mirror.populate()
91
92 # Add a bad refspec to the cache's fetch config.
93 cache_dir = os.path.join(
94 self.cache_dir, mirror.UrlToCacheDir(self.origin_dir))
Joanna Wangd9011c52023-08-15 12:30:06 +000095 self.git([
96 '--git-dir', cache_dir, 'config', '--add', 'remote.origin.fetch',
97 '+refs/heads/foo:refs/heads/foo'
98 ],
Edward Lemura11fc9b2018-07-17 22:35:47 +000099 cwd=cache_dir)
100
101 mirror.populate(reset_fetch_config=True)
102
Edward Lesmes34f71ab2020-03-25 21:24:00 +0000103 def testPopulateTwice(self):
104 self.git(['init', '-q'])
105 with open(os.path.join(self.origin_dir, 'foo'), 'w') as f:
106 f.write('touched\n')
107 self.git(['add', 'foo'])
108 self.git(['commit', '-m', 'foo'])
109
110 mirror = git_cache.Mirror(self.origin_dir)
111 mirror.populate()
112
113 mirror.populate()
114
Josip Sokcevic6afaa6c2020-05-08 18:20:17 +0000115 @mock.patch('sys.stdout', StringIO())
116 def testPruneRequired(self):
117 self.git(['init', '-q'])
118 with open(os.path.join(self.origin_dir, 'foo'), 'w') as f:
119 f.write('touched\n')
120 self.git(['checkout', '-b', 'foo'])
121 self.git(['add', 'foo'])
122 self.git(['commit', '-m', 'foo'])
123 mirror = git_cache.Mirror(self.origin_dir)
124 mirror.populate()
125 self.git(['checkout', '-b', 'foo_tmp', 'foo'])
126 self.git(['branch', '-D', 'foo'])
127 self.git(['checkout', '-b', 'foo/bar', 'foo_tmp'])
128 mirror.populate()
129 self.assertNotIn(git_cache.GIT_CACHE_CORRUPT_MESSAGE, sys.stdout.getvalue())
130
danakjc41f72c2019-11-05 17:12:01 +0000131 def _makeGitRepoWithTag(self):
132 self.git(['init', '-q'])
133 with open(os.path.join(self.origin_dir, 'foo'), 'w') as f:
134 f.write('touched\n')
135 self.git(['add', 'foo'])
136 self.git(['commit', '-m', 'foo'])
137 self.git(['tag', 'TAG'])
138 self.git(['pack-refs'])
139
140 def testPopulateFetchTagsByDefault(self):
141 self._makeGitRepoWithTag()
142
143 # Default behaviour includes tags.
144 mirror = git_cache.Mirror(self.origin_dir)
145 mirror.populate()
146
147 cache_dir = os.path.join(self.cache_dir,
148 mirror.UrlToCacheDir(self.origin_dir))
149 self.assertTrue(os.path.exists(cache_dir + '/refs/tags/TAG'))
150
151 def testPopulateFetchWithoutTags(self):
152 self._makeGitRepoWithTag()
153
154 # Ask to not include tags.
155 mirror = git_cache.Mirror(self.origin_dir)
156 mirror.populate(no_fetch_tags=True)
157
158 cache_dir = os.path.join(self.cache_dir,
159 mirror.UrlToCacheDir(self.origin_dir))
160 self.assertFalse(os.path.exists(cache_dir + '/refs/tags/TAG'))
Edward Lemura11fc9b2018-07-17 22:35:47 +0000161
162 def testPopulateResetFetchConfigEmptyFetchConfig(self):
163 self.git(['init', '-q'])
164 with open(os.path.join(self.origin_dir, 'foo'), 'w') as f:
165 f.write('touched\n')
166 self.git(['add', 'foo'])
167 self.git(['commit', '-m', 'foo'])
168
169 mirror = git_cache.Mirror(self.origin_dir)
170 mirror.populate(reset_fetch_config=True)
171
Robert Iannuccia19649b2018-06-29 16:31:45 +0000172
173class GitCacheDirTest(unittest.TestCase):
174 def setUp(self):
175 try:
176 delattr(git_cache.Mirror, 'cachepath')
177 except AttributeError:
178 pass
179 super(GitCacheDirTest, self).setUp()
180
181 def tearDown(self):
182 try:
183 delattr(git_cache.Mirror, 'cachepath')
184 except AttributeError:
185 pass
186 super(GitCacheDirTest, self).tearDown()
187
188 def test_git_config_read(self):
189 (fd, tmpFile) = tempfile.mkstemp()
190 old = git_cache.Mirror._GIT_CONFIG_LOCATION
191 try:
192 try:
Edward Lemurdf746d02019-07-27 00:42:46 +0000193 os.write(fd, b'[cache]\n cachepath="hello world"\n')
Robert Iannuccia19649b2018-06-29 16:31:45 +0000194 finally:
195 os.close(fd)
196
197 git_cache.Mirror._GIT_CONFIG_LOCATION = ['-f', tmpFile]
198
Edward Lesmes4c3eb702020-03-25 21:09:30 +0000199 self.assertEqual(git_cache.Mirror.GetCachePath(), 'hello world')
Robert Iannuccia19649b2018-06-29 16:31:45 +0000200 finally:
201 git_cache.Mirror._GIT_CONFIG_LOCATION = old
202 os.remove(tmpFile)
203
204 def test_environ_read(self):
205 path = os.environ.get('GIT_CACHE_PATH')
206 config = os.environ.get('GIT_CONFIG')
207 try:
208 os.environ['GIT_CACHE_PATH'] = 'hello world'
209 os.environ['GIT_CONFIG'] = 'disabled'
210
211 self.assertEqual(git_cache.Mirror.GetCachePath(), 'hello world')
212 finally:
213 for name, val in zip(('GIT_CACHE_PATH', 'GIT_CONFIG'), (path, config)):
214 if val is None:
215 os.environ.pop(name, None)
216 else:
217 os.environ[name] = val
218
219 def test_manual_set(self):
220 git_cache.Mirror.SetCachePath('hello world')
221 self.assertEqual(git_cache.Mirror.GetCachePath(), 'hello world')
222
223 def test_unconfigured(self):
224 path = os.environ.get('GIT_CACHE_PATH')
225 config = os.environ.get('GIT_CONFIG')
226 try:
227 os.environ.pop('GIT_CACHE_PATH', None)
228 os.environ['GIT_CONFIG'] = 'disabled'
229
230 with self.assertRaisesRegexp(RuntimeError, 'cache\.cachepath'):
231 git_cache.Mirror.GetCachePath()
232
233 # negatively cached value still raises
234 with self.assertRaisesRegexp(RuntimeError, 'cache\.cachepath'):
235 git_cache.Mirror.GetCachePath()
236 finally:
237 for name, val in zip(('GIT_CACHE_PATH', 'GIT_CONFIG'), (path, config)):
238 if val is None:
239 os.environ.pop(name, None)
240 else:
241 os.environ[name] = val
242
243
Dirk Prankedb589542019-04-12 21:07:01 +0000244class MirrorTest(unittest.TestCase):
245 def test_same_cache_for_authenticated_and_unauthenticated_urls(self):
246 # GoB can fetch a repo via two different URLs; if the url contains '/a/'
247 # it forces authenticated access instead of allowing anonymous access,
248 # even in the case where a repo is public. We want this in order to make
249 # sure bots are authenticated and get the right quotas. However, we
250 # only want to maintain a single cache for the repo.
251 self.assertEqual(git_cache.Mirror.UrlToCacheDir(
252 'https://chromium.googlesource.com/a/chromium/src.git'),
253 'chromium.googlesource.com-chromium-src')
254
255
szager@chromium.org66c8b852015-09-22 23:19:07 +0000256if __name__ == '__main__':
Josip Sokcevic14a83ae2020-05-21 01:36:34 +0000257 logging.basicConfig(
258 level=logging.DEBUG if '-v' in sys.argv else logging.ERROR)
szager@chromium.org66c8b852015-09-22 23:19:07 +0000259 sys.exit(coverage_utils.covered_main((
260 os.path.join(DEPOT_TOOLS_ROOT, 'git_cache.py')
261 ), required_percentage=0))