blob: 5ffa7b5e90c3a76ac4e32aaf019b07a38a0a8e59 [file] [log] [blame]
msb@chromium.orge28e4982009-09-25 20:51:45 +00001#!/usr/bin/python
2#
3# Copyright 2008-2009 Google Inc. All Rights Reserved.
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16
17"""Unit tests for gclient_scm.py."""
18
19import os
20import shutil
21import subprocess
22import tempfile
23import unittest
24
25import gclient
26import gclient_scm
27import gclient_test
28import gclient_utils
29from super_mox import mox
30
31
32class SVNWrapperTestCase(gclient_test.GClientBaseTestCase):
33 class OptionsObject(object):
34 def __init__(self, test_case, verbose=False, revision=None):
35 self.verbose = verbose
36 self.revision = revision
37 self.manually_grab_svn_rev = True
38 self.deps_os = None
39 self.force = False
40 self.nohooks = False
41
42 def setUp(self):
43 gclient_test.GClientBaseTestCase.setUp(self)
44 self.root_dir = self.Dir()
45 self.args = self.Args()
46 self.url = self.Url()
47 self.relpath = 'asf'
48
49 def testDir(self):
50 members = [
51 'FullUrlForRelativeUrl', 'RunCommand', 'cleanup', 'diff', 'export',
52 'pack', 'relpath', 'revert', 'runhooks', 'scm_name', 'status',
53 'update', 'url',
54 ]
55
56 # If you add a member, be sure to add the relevant test!
57 self.compareMembers(self._scm_wrapper(), members)
58
59 def testUnsupportedSCM(self):
60 args = [self.url, self.root_dir, self.relpath]
61 kwargs = {'scm_name' : 'foo'}
62 exception_msg = 'Unsupported scm %(scm_name)s' % kwargs
63 self.assertRaisesError(exception_msg, self._scm_wrapper, *args, **kwargs)
64
65 def testFullUrlForRelativeUrl(self):
66 self.url = 'svn://a/b/c/d'
67
68 self.mox.ReplayAll()
69 scm = self._scm_wrapper(url=self.url, root_dir=self.root_dir,
70 relpath=self.relpath)
71 self.assertEqual(scm.FullUrlForRelativeUrl('/crap'), 'svn://a/b/crap')
72
73 def testRunCommandException(self):
74 options = self.Options(verbose=False)
75 file_path = os.path.join(self.root_dir, self.relpath, '.git')
76 gclient.os.path.exists(file_path).AndReturn(False)
77
78 self.mox.ReplayAll()
79 scm = self._scm_wrapper(url=self.url, root_dir=self.root_dir,
80 relpath=self.relpath)
81 exception = "Unsupported argument(s): %s" % ','.join(self.args)
82 self.assertRaisesError(exception, scm.RunCommand,
83 'update', options, self.args)
84
85 def testRunCommandUnknown(self):
86 # TODO(maruel): if ever used.
87 pass
88
89 def testRevertMissing(self):
90 options = self.Options(verbose=True)
91 base_path = os.path.join(self.root_dir, self.relpath)
92 gclient.os.path.isdir(base_path).AndReturn(False)
93 # It'll to a checkout instead.
94 gclient.os.path.exists(os.path.join(base_path, '.git')).AndReturn(False)
95 print("\n_____ %s is missing, synching instead" % self.relpath)
96 # Checkout.
97 gclient.os.path.exists(base_path).AndReturn(False)
98 files_list = self.mox.CreateMockAnything()
maruel@chromium.org7753d242009-10-07 17:40:24 +000099 gclient_scm.RunSVNAndGetFileList(['checkout', self.url, base_path],
msb@chromium.orge28e4982009-09-25 20:51:45 +0000100 self.root_dir, files_list)
101
102 self.mox.ReplayAll()
103 scm = self._scm_wrapper(url=self.url, root_dir=self.root_dir,
104 relpath=self.relpath)
105 scm.revert(options, self.args, files_list)
106
107 def testRevertNone(self):
108 options = self.Options(verbose=True)
109 base_path = os.path.join(self.root_dir, self.relpath)
110 gclient.os.path.isdir(base_path).AndReturn(True)
111 gclient_scm.CaptureSVNStatus(base_path).AndReturn([])
maruel@chromium.org7753d242009-10-07 17:40:24 +0000112 gclient_scm.RunSVNAndGetFileList(['update', '--revision', 'BASE'],
msb@chromium.orge28e4982009-09-25 20:51:45 +0000113 base_path, mox.IgnoreArg())
114
115 self.mox.ReplayAll()
116 scm = self._scm_wrapper(url=self.url, root_dir=self.root_dir,
117 relpath=self.relpath)
118 file_list = []
119 scm.revert(options, self.args, file_list)
120
121 def testRevert2Files(self):
122 options = self.Options(verbose=True)
123 base_path = os.path.join(self.root_dir, self.relpath)
124 gclient.os.path.isdir(base_path).AndReturn(True)
125 items = [
126 ('M ', 'a'),
127 ('A ', 'b'),
128 ]
129 file_path1 = os.path.join(base_path, 'a')
130 file_path2 = os.path.join(base_path, 'b')
131 gclient_scm.CaptureSVNStatus(base_path).AndReturn(items)
132 gclient_scm.os.path.exists(file_path1).AndReturn(True)
133 gclient_scm.os.path.isfile(file_path1).AndReturn(True)
134 gclient_scm.os.remove(file_path1)
135 gclient_scm.os.path.exists(file_path2).AndReturn(True)
136 gclient_scm.os.path.isfile(file_path2).AndReturn(True)
137 gclient_scm.os.remove(file_path2)
maruel@chromium.org7753d242009-10-07 17:40:24 +0000138 gclient_scm.RunSVNAndGetFileList(['update', '--revision', 'BASE'],
msb@chromium.orge28e4982009-09-25 20:51:45 +0000139 base_path, mox.IgnoreArg())
140 print(os.path.join(base_path, 'a'))
141 print(os.path.join(base_path, 'b'))
142
143 self.mox.ReplayAll()
144 scm = self._scm_wrapper(url=self.url, root_dir=self.root_dir,
145 relpath=self.relpath)
146 file_list = []
147 scm.revert(options, self.args, file_list)
148
149 def testRevertDirectory(self):
150 options = self.Options(verbose=True)
151 base_path = os.path.join(self.root_dir, self.relpath)
152 gclient.os.path.isdir(base_path).AndReturn(True)
153 items = [
154 ('~ ', 'a'),
155 ]
156 gclient_scm.CaptureSVNStatus(base_path).AndReturn(items)
157 file_path = os.path.join(base_path, 'a')
158 print(file_path)
159 gclient_scm.os.path.exists(file_path).AndReturn(True)
160 gclient_scm.os.path.isfile(file_path).AndReturn(False)
161 gclient_scm.os.path.isdir(file_path).AndReturn(True)
162 gclient_utils.RemoveDirectory(file_path)
163 file_list1 = []
maruel@chromium.org7753d242009-10-07 17:40:24 +0000164 gclient_scm.RunSVNAndGetFileList(['update', '--revision', 'BASE'],
msb@chromium.orge28e4982009-09-25 20:51:45 +0000165 base_path, mox.IgnoreArg())
166
167 self.mox.ReplayAll()
168 scm = self._scm_wrapper(url=self.url, root_dir=self.root_dir,
169 relpath=self.relpath)
170 file_list2 = []
171 scm.revert(options, self.args, file_list2)
172
173 def testStatus(self):
174 options = self.Options(verbose=True)
175 base_path = os.path.join(self.root_dir, self.relpath)
176 gclient.os.path.isdir(base_path).AndReturn(True)
maruel@chromium.org7753d242009-10-07 17:40:24 +0000177 gclient_scm.RunSVNAndGetFileList(['status'] + self.args, base_path,
msb@chromium.orge28e4982009-09-25 20:51:45 +0000178 []).AndReturn(None)
179
180 self.mox.ReplayAll()
181 scm = self._scm_wrapper(url=self.url, root_dir=self.root_dir,
182 relpath=self.relpath)
183 file_list = []
184 self.assertEqual(scm.status(options, self.args, file_list), None)
185
186
187 # TODO(maruel): TEST REVISIONS!!!
188 # TODO(maruel): TEST RELOCATE!!!
189 def testUpdateCheckout(self):
190 options = self.Options(verbose=True)
191 base_path = os.path.join(self.root_dir, self.relpath)
192 file_info = gclient_utils.PrintableObject()
193 file_info.root = 'blah'
194 file_info.url = self.url
195 file_info.uuid = 'ABC'
196 file_info.revision = 42
197 gclient.os.path.exists(os.path.join(base_path, '.git')).AndReturn(False)
198 # Checkout.
199 gclient.os.path.exists(base_path).AndReturn(False)
200 files_list = self.mox.CreateMockAnything()
maruel@chromium.org7753d242009-10-07 17:40:24 +0000201 gclient_scm.RunSVNAndGetFileList(['checkout', self.url, base_path],
msb@chromium.orge28e4982009-09-25 20:51:45 +0000202 self.root_dir, files_list)
203 self.mox.ReplayAll()
204 scm = self._scm_wrapper(url=self.url, root_dir=self.root_dir,
205 relpath=self.relpath)
206 scm.update(options, (), files_list)
207
208 def testUpdateUpdate(self):
209 options = self.Options(verbose=True)
210 base_path = os.path.join(self.root_dir, self.relpath)
211 options.force = True
212 options.nohooks = False
213 file_info = {
214 'Repository Root': 'blah',
215 'URL': self.url,
216 'UUID': 'ABC',
217 'Revision': 42,
218 }
219 gclient.os.path.exists(os.path.join(base_path, '.git')).AndReturn(False)
220 # Checkout or update.
221 gclient.os.path.exists(base_path).AndReturn(True)
222 gclient_scm.CaptureSVNInfo(os.path.join(base_path, "."), '.'
223 ).AndReturn(file_info)
224 # Cheat a bit here.
225 gclient_scm.CaptureSVNInfo(file_info['URL'], '.').AndReturn(file_info)
226 additional_args = []
227 if options.manually_grab_svn_rev:
228 additional_args = ['--revision', str(file_info['Revision'])]
229 files_list = []
maruel@chromium.org7753d242009-10-07 17:40:24 +0000230 gclient_scm.RunSVNAndGetFileList(['update', base_path] + additional_args,
231 self.root_dir, files_list)
msb@chromium.orge28e4982009-09-25 20:51:45 +0000232
233 self.mox.ReplayAll()
234 scm = self._scm_wrapper(url=self.url, root_dir=self.root_dir,
235 relpath=self.relpath)
236 scm.update(options, (), files_list)
237
238 def testUpdateGit(self):
239 options = self.Options(verbose=True)
240 file_path = os.path.join(self.root_dir, self.relpath, '.git')
241 gclient.os.path.exists(file_path).AndReturn(True)
242 print("________ found .git directory; skipping %s" % self.relpath)
243
244 self.mox.ReplayAll()
245 scm = self._scm_wrapper(url=self.url, root_dir=self.root_dir,
246 relpath=self.relpath)
247 file_list = []
248 scm.update(options, self.args, file_list)
249
250 def testGetSVNFileInfo(self):
251 xml_text = r"""<?xml version="1.0"?>
252<info>
253<entry kind="file" path="%s" revision="14628">
254<url>http://src.chromium.org/svn/trunk/src/chrome/app/d</url>
255<repository><root>http://src.chromium.org/svn</root></repository>
256<wc-info>
257<schedule>add</schedule>
258<depth>infinity</depth>
259<copy-from-url>http://src.chromium.org/svn/trunk/src/chrome/app/DEPS</copy-from-url>
260<copy-from-rev>14628</copy-from-rev>
261<checksum>369f59057ba0e6d9017e28f8bdfb1f43</checksum>
262</wc-info>
263</entry>
264</info>
265""" % self.url
266 gclient_scm.CaptureSVN(['info', '--xml', self.url],
267 '.', True).AndReturn(xml_text)
268 expected = {
269 'URL': 'http://src.chromium.org/svn/trunk/src/chrome/app/d',
270 'UUID': None,
271 'Repository Root': 'http://src.chromium.org/svn',
272 'Schedule': 'add',
273 'Copied From URL':
274 'http://src.chromium.org/svn/trunk/src/chrome/app/DEPS',
275 'Copied From Rev': '14628',
276 'Path': self.url,
277 'Revision': 14628,
278 'Node Kind': 'file',
279 }
280 self.mox.ReplayAll()
281 file_info = self._CaptureSVNInfo(self.url, '.', True)
282 self.assertEquals(sorted(file_info.items()), sorted(expected.items()))
283
284 def testCaptureSvnInfo(self):
285 xml_text = """<?xml version="1.0"?>
286<info>
287<entry
288 kind="dir"
289 path="."
290 revision="35">
291<url>%s</url>
292<repository>
293<root>%s</root>
294<uuid>7b9385f5-0452-0410-af26-ad4892b7a1fb</uuid>
295</repository>
296<wc-info>
297<schedule>normal</schedule>
298<depth>infinity</depth>
299</wc-info>
300<commit
301 revision="35">
302<author>maruel</author>
303<date>2008-12-04T20:12:19.685120Z</date>
304</commit>
305</entry>
306</info>
307""" % (self.url, self.root_dir)
308 gclient_scm.CaptureSVN(['info', '--xml',
309 self.url], '.', True).AndReturn(xml_text)
310 self.mox.ReplayAll()
311 file_info = self._CaptureSVNInfo(self.url, '.', True)
312 expected = {
313 'URL': self.url,
314 'UUID': '7b9385f5-0452-0410-af26-ad4892b7a1fb',
315 'Revision': 35,
316 'Repository Root': self.root_dir,
317 'Schedule': 'normal',
318 'Copied From URL': None,
319 'Copied From Rev': None,
320 'Path': '.',
321 'Node Kind': 'dir',
322 }
323 self.assertEqual(file_info, expected)
324
325
326class GitWrapperTestCase(gclient_test.GClientBaseTestCase):
327 class OptionsObject(object):
328 def __init__(self, test_case, verbose=False, revision=None):
329 self.verbose = verbose
330 self.revision = revision
331 self.manually_grab_svn_rev = True
332 self.deps_os = None
333 self.force = False
334 self.nohooks = False
335
336 sample_git_import = """blob
337mark :1
338data 6
339Hello
340
341blob
342mark :2
343data 4
344Bye
345
346reset refs/heads/master
347commit refs/heads/master
348mark :3
349author Bob <bob@example.com> 1253744361 -0700
350committer Bob <bob@example.com> 1253744361 -0700
351data 8
352A and B
353M 100644 :1 a
354M 100644 :2 b
355
356blob
357mark :4
358data 10
359Hello
360You
361
362blob
363mark :5
364data 8
365Bye
366You
367
368commit refs/heads/origin
369mark :6
370author Alice <alice@example.com> 1253744424 -0700
371committer Alice <alice@example.com> 1253744424 -0700
372data 13
373Personalized
374from :3
375M 100644 :4 a
376M 100644 :5 b
377
378reset refs/heads/master
379from :3
380"""
msb@chromium.orge28e4982009-09-25 20:51:45 +0000381 def Options(self, *args, **kwargs):
382 return self.OptionsObject(self, *args, **kwargs)
383
384 def CreateGitRepo(self, git_import, path):
maruel@chromium.orgea6c2c52009-10-09 20:38:14 +0000385 try:
386 subprocess.Popen(['git', 'init'], stdout=subprocess.PIPE,
387 stderr=subprocess.STDOUT, cwd=path).communicate()
388 except WindowsError:
389 # git is not available, skip this test.
390 return False
msb@chromium.orge28e4982009-09-25 20:51:45 +0000391 subprocess.Popen(['git', 'fast-import'], stdin=subprocess.PIPE,
392 stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
393 cwd=path).communicate(input=git_import)
394 subprocess.Popen(['git', 'checkout'], stdout=subprocess.PIPE,
395 stderr=subprocess.STDOUT, cwd=path).communicate()
maruel@chromium.orgea6c2c52009-10-09 20:38:14 +0000396 return True
msb@chromium.orge28e4982009-09-25 20:51:45 +0000397
398 def GetGitRev(self, path):
399 return subprocess.Popen(['git', 'rev-parse', 'HEAD'],
400 stdout=subprocess.PIPE,
401 stderr=subprocess.STDOUT,
402 cwd=path).communicate()[0].strip()
403
404 def setUp(self):
405 gclient_test.BaseTestCase.setUp(self)
406 self.args = self.Args()
407 self.url = 'git://foo'
408 self.root_dir = tempfile.mkdtemp()
409 self.relpath = '.'
410 self.base_path = os.path.join(self.root_dir, self.relpath)
maruel@chromium.orgea6c2c52009-10-09 20:38:14 +0000411 self.enabled = self.CreateGitRepo(self.sample_git_import, self.base_path)
msb@chromium.orge28e4982009-09-25 20:51:45 +0000412
413 def tearDown(self):
414 shutil.rmtree(self.root_dir)
415 gclient_test.BaseTestCase.tearDown(self)
416
417 def testDir(self):
418 members = [
419 'FullUrlForRelativeUrl', 'RunCommand', 'cleanup', 'diff', 'export',
420 'relpath', 'revert', 'runhooks', 'scm_name', 'status', 'update', 'url',
421 ]
422
423 # If you add a member, be sure to add the relevant test!
424 self.compareMembers(gclient_scm.CreateSCM(url=self.url), members)
425
426 def testRevertMissing(self):
maruel@chromium.orgea6c2c52009-10-09 20:38:14 +0000427 if not self.enabled:
428 return
msb@chromium.orge28e4982009-09-25 20:51:45 +0000429 options = self.Options()
430 file_path = os.path.join(self.base_path, 'a')
431 os.remove(file_path)
432 scm = gclient_scm.CreateSCM(url=self.url, root_dir=self.root_dir,
433 relpath=self.relpath)
434 file_list = []
435 scm.revert(options, self.args, file_list)
436 self.assertEquals(file_list, [file_path])
437 file_list = []
438 scm.diff(options, self.args, file_list)
439 self.assertEquals(file_list, [])
440
441 def testRevertNone(self):
maruel@chromium.orgea6c2c52009-10-09 20:38:14 +0000442 if not self.enabled:
443 return
msb@chromium.orge28e4982009-09-25 20:51:45 +0000444 options = self.Options()
445 scm = gclient_scm.CreateSCM(url=self.url, root_dir=self.root_dir,
446 relpath=self.relpath)
447 file_list = []
448 scm.revert(options, self.args, file_list)
449 self.assertEquals(file_list, [])
450 self.assertEquals(self.GetGitRev(self.base_path),
451 '069c602044c5388d2d15c3f875b057c852003458')
452
453
454 def testRevertModified(self):
maruel@chromium.orgea6c2c52009-10-09 20:38:14 +0000455 if not self.enabled:
456 return
msb@chromium.orge28e4982009-09-25 20:51:45 +0000457 options = self.Options()
458 file_path = os.path.join(self.base_path, 'a')
459 open(file_path, 'a').writelines('touched\n')
460 scm = gclient_scm.CreateSCM(url=self.url, root_dir=self.root_dir,
461 relpath=self.relpath)
462 file_list = []
463 scm.revert(options, self.args, file_list)
464 self.assertEquals(file_list, [file_path])
465 file_list = []
466 scm.diff(options, self.args, file_list)
467 self.assertEquals(file_list, [])
468 self.assertEquals(self.GetGitRev(self.base_path),
469 '069c602044c5388d2d15c3f875b057c852003458')
470
471 def testRevertNew(self):
maruel@chromium.orgea6c2c52009-10-09 20:38:14 +0000472 if not self.enabled:
473 return
msb@chromium.orge28e4982009-09-25 20:51:45 +0000474 options = self.Options()
475 file_path = os.path.join(self.base_path, 'c')
476 f = open(file_path, 'w')
477 f.writelines('new\n')
478 f.close()
479 subprocess.Popen(['git', 'add', 'c'], stdout=subprocess.PIPE,
480 stderr=subprocess.STDOUT, cwd=self.base_path).communicate()
481 scm = gclient_scm.CreateSCM(url=self.url, root_dir=self.root_dir,
482 relpath=self.relpath)
483 file_list = []
484 scm.revert(options, self.args, file_list)
485 self.assertEquals(file_list, [file_path])
486 file_list = []
487 scm.diff(options, self.args, file_list)
488 self.assertEquals(file_list, [])
489 self.assertEquals(self.GetGitRev(self.base_path),
490 '069c602044c5388d2d15c3f875b057c852003458')
491
492 def testStatusNew(self):
maruel@chromium.orgea6c2c52009-10-09 20:38:14 +0000493 if not self.enabled:
494 return
msb@chromium.orge28e4982009-09-25 20:51:45 +0000495 options = self.Options()
496 file_path = os.path.join(self.base_path, 'a')
497 open(file_path, 'a').writelines('touched\n')
498 scm = gclient_scm.CreateSCM(url=self.url, root_dir=self.root_dir,
499 relpath=self.relpath)
500 file_list = []
501 scm.status(options, self.args, file_list)
502 self.assertEquals(file_list, [file_path])
503
504 def testStatus2New(self):
maruel@chromium.orgea6c2c52009-10-09 20:38:14 +0000505 if not self.enabled:
506 return
msb@chromium.orge28e4982009-09-25 20:51:45 +0000507 options = self.Options()
508 expected_file_list = []
509 for f in ['a', 'b']:
510 file_path = os.path.join(self.base_path, f)
511 open(file_path, 'a').writelines('touched\n')
512 expected_file_list.extend([file_path])
513 scm = gclient_scm.CreateSCM(url=self.url, root_dir=self.root_dir,
514 relpath=self.relpath)
515 file_list = []
516 scm.status(options, self.args, file_list)
517 expected_file_list = [os.path.join(self.base_path, x) for x in ['a', 'b']]
518 self.assertEquals(sorted(file_list), expected_file_list)
519
520 def testUpdateCheckout(self):
maruel@chromium.orgea6c2c52009-10-09 20:38:14 +0000521 if not self.enabled:
522 return
msb@chromium.orge28e4982009-09-25 20:51:45 +0000523 options = self.Options(verbose=True)
524 root_dir = tempfile.mkdtemp()
525 relpath = 'foo'
526 base_path = os.path.join(root_dir, relpath)
527 url = os.path.join(self.root_dir, self.relpath, '.git')
528 try:
529 scm = gclient_scm.CreateSCM(url=url, root_dir=root_dir,
530 relpath=relpath)
531 file_list = []
532 scm.update(options, (), file_list)
533 self.assertEquals(len(file_list), 2)
534 self.assert_(os.path.isfile(os.path.join(base_path, 'a')))
535 self.assertEquals(self.GetGitRev(base_path),
536 '069c602044c5388d2d15c3f875b057c852003458')
537 finally:
538 shutil.rmtree(root_dir)
539
540 def testUpdateUpdate(self):
maruel@chromium.orgea6c2c52009-10-09 20:38:14 +0000541 if not self.enabled:
542 return
msb@chromium.orge28e4982009-09-25 20:51:45 +0000543 options = self.Options()
544 expected_file_list = [os.path.join(self.base_path, x) for x in ['a', 'b']]
545 scm = gclient_scm.CreateSCM(url=self.url, root_dir=self.root_dir,
546 relpath=self.relpath)
547 file_list = []
548 scm.update(options, (), file_list)
549 self.assertEquals(self.GetGitRev(self.base_path),
550 'a7142dc9f0009350b96a11f372b6ea658592aa95')
551
552
553class RunSVNTestCase(gclient_test.BaseTestCase):
554 def testRunSVN(self):
555 param2 = 'bleh'
556 self.mox.StubOutWithMock(gclient_utils, 'SubprocessCall')
557 gclient_utils.SubprocessCall(['svn', 'foo', 'bar'], param2).AndReturn(None)
558 self.mox.ReplayAll()
559 gclient_scm.RunSVN(['foo', 'bar'], param2)
560
561
562if __name__ == '__main__':
563 unittest.main()
564
565# vim: ts=2:sw=2:tw=80:et: