summaryrefslogtreecommitdiffstats
path: root/tests/test_project.py
diff options
context:
space:
mode:
Diffstat (limited to 'tests/test_project.py')
-rw-r--r--tests/test_project.py204
1 files changed, 204 insertions, 0 deletions
diff --git a/tests/test_project.py b/tests/test_project.py
index 77126dff..6d82da11 100644
--- a/tests/test_project.py
+++ b/tests/test_project.py
@@ -25,6 +25,7 @@ import subprocess
25import tempfile 25import tempfile
26import unittest 26import unittest
27 27
28import error
28import git_config 29import git_config
29import project 30import project
30 31
@@ -134,3 +135,206 @@ class ReviewableBranchTests(unittest.TestCase):
134 self.assertFalse(rb.base_exists) 135 self.assertFalse(rb.base_exists)
135 # Hard to assert anything useful about this. 136 # Hard to assert anything useful about this.
136 self.assertTrue(rb.date) 137 self.assertTrue(rb.date)
138
139
140class CopyLinkTestCase(unittest.TestCase):
141 """TestCase for stub repo client checkouts.
142
143 It'll have a layout like:
144 tempdir/ # self.tempdir
145 checkout/ # self.topdir
146 git-project/ # self.worktree
147
148 Attributes:
149 tempdir: A dedicated temporary directory.
150 worktree: The top of the repo client checkout.
151 topdir: The top of a project checkout.
152 """
153
154 def setUp(self):
155 self.tempdir = tempfile.mkdtemp(prefix='repo_tests')
156 self.topdir = os.path.join(self.tempdir, 'checkout')
157 self.worktree = os.path.join(self.topdir, 'git-project')
158 os.makedirs(self.topdir)
159 os.makedirs(self.worktree)
160
161 def tearDown(self):
162 shutil.rmtree(self.tempdir, ignore_errors=True)
163
164 @staticmethod
165 def touch(path):
166 with open(path, 'w') as f:
167 pass
168
169 def assertExists(self, path, msg=None):
170 """Make sure |path| exists."""
171 if os.path.exists(path):
172 return
173
174 if msg is None:
175 msg = ['path is missing: %s' % path]
176 while path != '/':
177 path = os.path.dirname(path)
178 if not path:
179 # If we're given something like "foo", abort once we get to "".
180 break
181 result = os.path.exists(path)
182 msg.append('\tos.path.exists(%s): %s' % (path, result))
183 if result:
184 msg.append('\tcontents: %r' % os.listdir(path))
185 break
186 msg = '\n'.join(msg)
187
188 raise self.failureException(msg)
189
190
191class CopyFile(CopyLinkTestCase):
192 """Check _CopyFile handling."""
193
194 def CopyFile(self, src, dest):
195 return project._CopyFile(self.worktree, src, self.topdir, dest)
196
197 def test_basic(self):
198 """Basic test of copying a file from a project to the toplevel."""
199 src = os.path.join(self.worktree, 'foo.txt')
200 self.touch(src)
201 cf = self.CopyFile('foo.txt', 'foo')
202 cf._Copy()
203 self.assertExists(os.path.join(self.topdir, 'foo'))
204
205 def test_src_subdir(self):
206 """Copy a file from a subdir of a project."""
207 src = os.path.join(self.worktree, 'bar', 'foo.txt')
208 os.makedirs(os.path.dirname(src))
209 self.touch(src)
210 cf = self.CopyFile('bar/foo.txt', 'new.txt')
211 cf._Copy()
212 self.assertExists(os.path.join(self.topdir, 'new.txt'))
213
214 def test_dest_subdir(self):
215 """Copy a file to a subdir of a checkout."""
216 src = os.path.join(self.worktree, 'foo.txt')
217 self.touch(src)
218 cf = self.CopyFile('foo.txt', 'sub/dir/new.txt')
219 self.assertFalse(os.path.exists(os.path.join(self.topdir, 'sub')))
220 cf._Copy()
221 self.assertExists(os.path.join(self.topdir, 'sub', 'dir', 'new.txt'))
222
223 def test_update(self):
224 """Make sure changed files get copied again."""
225 src = os.path.join(self.worktree, 'foo.txt')
226 dest = os.path.join(self.topdir, 'bar')
227 with open(src, 'w') as f:
228 f.write('1st')
229 cf = self.CopyFile('foo.txt', 'bar')
230 cf._Copy()
231 self.assertExists(dest)
232 with open(dest) as f:
233 self.assertEqual(f.read(), '1st')
234
235 with open(src, 'w') as f:
236 f.write('2nd!')
237 cf._Copy()
238 with open(dest) as f:
239 self.assertEqual(f.read(), '2nd!')
240
241 def test_src_block_symlink(self):
242 """Do not allow reading from a symlinked path."""
243 src = os.path.join(self.worktree, 'foo.txt')
244 sym = os.path.join(self.worktree, 'sym')
245 self.touch(src)
246 os.symlink('foo.txt', sym)
247 self.assertExists(sym)
248 cf = self.CopyFile('sym', 'foo')
249 self.assertRaises(error.ManifestInvalidPathError, cf._Copy)
250
251 def test_src_block_symlink_traversal(self):
252 """Do not allow reading through a symlink dir."""
253 src = os.path.join(self.worktree, 'bar', 'passwd')
254 os.symlink('/etc', os.path.join(self.worktree, 'bar'))
255 self.assertExists(src)
256 cf = self.CopyFile('bar/foo.txt', 'foo')
257 self.assertRaises(error.ManifestInvalidPathError, cf._Copy)
258
259 def test_src_block_dir(self):
260 """Do not allow copying from a directory."""
261 src = os.path.join(self.worktree, 'dir')
262 os.makedirs(src)
263 cf = self.CopyFile('dir', 'foo')
264 self.assertRaises(error.ManifestInvalidPathError, cf._Copy)
265
266 def test_dest_block_symlink(self):
267 """Do not allow writing to a symlink."""
268 src = os.path.join(self.worktree, 'foo.txt')
269 self.touch(src)
270 os.symlink('dest', os.path.join(self.topdir, 'sym'))
271 cf = self.CopyFile('foo.txt', 'sym')
272 self.assertRaises(error.ManifestInvalidPathError, cf._Copy)
273
274 def test_dest_block_symlink_traversal(self):
275 """Do not allow writing through a symlink dir."""
276 src = os.path.join(self.worktree, 'foo.txt')
277 self.touch(src)
278 os.symlink('/tmp', os.path.join(self.topdir, 'sym'))
279 cf = self.CopyFile('foo.txt', 'sym/foo.txt')
280 self.assertRaises(error.ManifestInvalidPathError, cf._Copy)
281
282 def test_src_block_dir(self):
283 """Do not allow copying to a directory."""
284 src = os.path.join(self.worktree, 'foo.txt')
285 self.touch(src)
286 os.makedirs(os.path.join(self.topdir, 'dir'))
287 cf = self.CopyFile('foo.txt', 'dir')
288 self.assertRaises(error.ManifestInvalidPathError, cf._Copy)
289
290
291class LinkFile(CopyLinkTestCase):
292 """Check _LinkFile handling."""
293
294 def LinkFile(self, src, dest):
295 return project._LinkFile(self.worktree, src, self.topdir, dest)
296
297 def test_basic(self):
298 """Basic test of linking a file from a project into the toplevel."""
299 src = os.path.join(self.worktree, 'foo.txt')
300 self.touch(src)
301 lf = self.LinkFile('foo.txt', 'foo')
302 lf._Link()
303 dest = os.path.join(self.topdir, 'foo')
304 self.assertExists(dest)
305 self.assertTrue(os.path.islink(dest))
306 self.assertEqual('git-project/foo.txt', os.readlink(dest))
307
308 def test_src_subdir(self):
309 """Link to a file in a subdir of a project."""
310 src = os.path.join(self.worktree, 'bar', 'foo.txt')
311 os.makedirs(os.path.dirname(src))
312 self.touch(src)
313 lf = self.LinkFile('bar/foo.txt', 'foo')
314 lf._Link()
315 self.assertExists(os.path.join(self.topdir, 'foo'))
316
317 def test_dest_subdir(self):
318 """Link a file to a subdir of a checkout."""
319 src = os.path.join(self.worktree, 'foo.txt')
320 self.touch(src)
321 lf = self.LinkFile('foo.txt', 'sub/dir/foo/bar')
322 self.assertFalse(os.path.exists(os.path.join(self.topdir, 'sub')))
323 lf._Link()
324 self.assertExists(os.path.join(self.topdir, 'sub', 'dir', 'foo', 'bar'))
325
326 def test_update(self):
327 """Make sure changed targets get updated."""
328 dest = os.path.join(self.topdir, 'sym')
329
330 src = os.path.join(self.worktree, 'foo.txt')
331 self.touch(src)
332 lf = self.LinkFile('foo.txt', 'sym')
333 lf._Link()
334 self.assertEqual('git-project/foo.txt', os.readlink(dest))
335
336 # Point the symlink somewhere else.
337 os.unlink(dest)
338 os.symlink('/', dest)
339 lf._Link()
340 self.assertEqual('git-project/foo.txt', os.readlink(dest))