blob: 83b1bb5ddfc80f6235bb95bbfb32c74b04447098 [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))
95 self.git(['config', '--add', 'remote.origin.fetch',
96 '+refs/heads/foo:refs/heads/foo'],
97 cwd=cache_dir)
98
99 mirror.populate(reset_fetch_config=True)
100
Edward Lesmes34f71ab2020-03-25 21:24:00 +0000101 def testPopulateTwice(self):
102 self.git(['init', '-q'])
103 with open(os.path.join(self.origin_dir, 'foo'), 'w') as f:
104 f.write('touched\n')
105 self.git(['add', 'foo'])
106 self.git(['commit', '-m', 'foo'])
107
108 mirror = git_cache.Mirror(self.origin_dir)
109 mirror.populate()
110
111 mirror.populate()
112
Josip Sokcevic6afaa6c2020-05-08 18:20:17 +0000113 @mock.patch('sys.stdout', StringIO())
114 def testPruneRequired(self):
115 self.git(['init', '-q'])
116 with open(os.path.join(self.origin_dir, 'foo'), 'w') as f:
117 f.write('touched\n')
118 self.git(['checkout', '-b', 'foo'])
119 self.git(['add', 'foo'])
120 self.git(['commit', '-m', 'foo'])
121 mirror = git_cache.Mirror(self.origin_dir)
122 mirror.populate()
123 self.git(['checkout', '-b', 'foo_tmp', 'foo'])
124 self.git(['branch', '-D', 'foo'])
125 self.git(['checkout', '-b', 'foo/bar', 'foo_tmp'])
126 mirror.populate()
127 self.assertNotIn(git_cache.GIT_CACHE_CORRUPT_MESSAGE, sys.stdout.getvalue())
128
danakjc41f72c2019-11-05 17:12:01 +0000129 def _makeGitRepoWithTag(self):
130 self.git(['init', '-q'])
131 with open(os.path.join(self.origin_dir, 'foo'), 'w') as f:
132 f.write('touched\n')
133 self.git(['add', 'foo'])
134 self.git(['commit', '-m', 'foo'])
135 self.git(['tag', 'TAG'])
136 self.git(['pack-refs'])
137
138 def testPopulateFetchTagsByDefault(self):
139 self._makeGitRepoWithTag()
140
141 # Default behaviour includes tags.
142 mirror = git_cache.Mirror(self.origin_dir)
143 mirror.populate()
144
145 cache_dir = os.path.join(self.cache_dir,
146 mirror.UrlToCacheDir(self.origin_dir))
147 self.assertTrue(os.path.exists(cache_dir + '/refs/tags/TAG'))
148
149 def testPopulateFetchWithoutTags(self):
150 self._makeGitRepoWithTag()
151
152 # Ask to not include tags.
153 mirror = git_cache.Mirror(self.origin_dir)
154 mirror.populate(no_fetch_tags=True)
155
156 cache_dir = os.path.join(self.cache_dir,
157 mirror.UrlToCacheDir(self.origin_dir))
158 self.assertFalse(os.path.exists(cache_dir + '/refs/tags/TAG'))
Edward Lemura11fc9b2018-07-17 22:35:47 +0000159
160 def testPopulateResetFetchConfigEmptyFetchConfig(self):
161 self.git(['init', '-q'])
162 with open(os.path.join(self.origin_dir, 'foo'), 'w') as f:
163 f.write('touched\n')
164 self.git(['add', 'foo'])
165 self.git(['commit', '-m', 'foo'])
166
167 mirror = git_cache.Mirror(self.origin_dir)
168 mirror.populate(reset_fetch_config=True)
169
Robert Iannuccia19649b2018-06-29 16:31:45 +0000170
171class GitCacheDirTest(unittest.TestCase):
172 def setUp(self):
173 try:
174 delattr(git_cache.Mirror, 'cachepath')
175 except AttributeError:
176 pass
177 super(GitCacheDirTest, self).setUp()
178
179 def tearDown(self):
180 try:
181 delattr(git_cache.Mirror, 'cachepath')
182 except AttributeError:
183 pass
184 super(GitCacheDirTest, self).tearDown()
185
186 def test_git_config_read(self):
187 (fd, tmpFile) = tempfile.mkstemp()
188 old = git_cache.Mirror._GIT_CONFIG_LOCATION
189 try:
190 try:
Edward Lemurdf746d02019-07-27 00:42:46 +0000191 os.write(fd, b'[cache]\n cachepath="hello world"\n')
Robert Iannuccia19649b2018-06-29 16:31:45 +0000192 finally:
193 os.close(fd)
194
195 git_cache.Mirror._GIT_CONFIG_LOCATION = ['-f', tmpFile]
196
Edward Lesmes4c3eb702020-03-25 21:09:30 +0000197 self.assertEqual(git_cache.Mirror.GetCachePath(), 'hello world')
Robert Iannuccia19649b2018-06-29 16:31:45 +0000198 finally:
199 git_cache.Mirror._GIT_CONFIG_LOCATION = old
200 os.remove(tmpFile)
201
202 def test_environ_read(self):
203 path = os.environ.get('GIT_CACHE_PATH')
204 config = os.environ.get('GIT_CONFIG')
205 try:
206 os.environ['GIT_CACHE_PATH'] = 'hello world'
207 os.environ['GIT_CONFIG'] = 'disabled'
208
209 self.assertEqual(git_cache.Mirror.GetCachePath(), 'hello world')
210 finally:
211 for name, val in zip(('GIT_CACHE_PATH', 'GIT_CONFIG'), (path, config)):
212 if val is None:
213 os.environ.pop(name, None)
214 else:
215 os.environ[name] = val
216
217 def test_manual_set(self):
218 git_cache.Mirror.SetCachePath('hello world')
219 self.assertEqual(git_cache.Mirror.GetCachePath(), 'hello world')
220
221 def test_unconfigured(self):
222 path = os.environ.get('GIT_CACHE_PATH')
223 config = os.environ.get('GIT_CONFIG')
224 try:
225 os.environ.pop('GIT_CACHE_PATH', None)
226 os.environ['GIT_CONFIG'] = 'disabled'
227
228 with self.assertRaisesRegexp(RuntimeError, 'cache\.cachepath'):
229 git_cache.Mirror.GetCachePath()
230
231 # negatively cached value still raises
232 with self.assertRaisesRegexp(RuntimeError, 'cache\.cachepath'):
233 git_cache.Mirror.GetCachePath()
234 finally:
235 for name, val in zip(('GIT_CACHE_PATH', 'GIT_CONFIG'), (path, config)):
236 if val is None:
237 os.environ.pop(name, None)
238 else:
239 os.environ[name] = val
240
241
Dirk Prankedb589542019-04-12 21:07:01 +0000242class MirrorTest(unittest.TestCase):
243 def test_same_cache_for_authenticated_and_unauthenticated_urls(self):
244 # GoB can fetch a repo via two different URLs; if the url contains '/a/'
245 # it forces authenticated access instead of allowing anonymous access,
246 # even in the case where a repo is public. We want this in order to make
247 # sure bots are authenticated and get the right quotas. However, we
248 # only want to maintain a single cache for the repo.
249 self.assertEqual(git_cache.Mirror.UrlToCacheDir(
250 'https://chromium.googlesource.com/a/chromium/src.git'),
251 'chromium.googlesource.com-chromium-src')
252
253
szager@chromium.org66c8b852015-09-22 23:19:07 +0000254if __name__ == '__main__':
Josip Sokcevic14a83ae2020-05-21 01:36:34 +0000255 logging.basicConfig(
256 level=logging.DEBUG if '-v' in sys.argv else logging.ERROR)
szager@chromium.org66c8b852015-09-22 23:19:07 +0000257 sys.exit(coverage_utils.covered_main((
258 os.path.join(DEPOT_TOOLS_ROOT, 'git_cache.py')
259 ), required_percentage=0))