blob: 6f5cc04117934d7826fac84e1223b87920a8c9cd [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()
dpranke@google.com22e29d42009-10-28 00:48:26 +000099 gclient_scm.RunSVNAndGetFileList(options, ['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([])
dpranke@google.com22e29d42009-10-28 00:48:26 +0000112 gclient_scm.RunSVNAndGetFileList(options, ['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)
dpranke@google.com22e29d42009-10-28 00:48:26 +0000138 gclient_scm.RunSVNAndGetFileList(options, ['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 = []
dpranke@google.com22e29d42009-10-28 00:48:26 +0000164 gclient_scm.RunSVNAndGetFileList(options, ['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)
dpranke@google.com22e29d42009-10-28 00:48:26 +0000177 gclient_scm.RunSVNAndGetFileList(options, ['status'] + self.args,
178 base_path, []).AndReturn(None)
msb@chromium.orge28e4982009-09-25 20:51:45 +0000179
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()
dpranke@google.com22e29d42009-10-28 00:48:26 +0000201 gclient_scm.RunSVNAndGetFileList(options, ['checkout', self.url,
202 base_path], self.root_dir, files_list)
msb@chromium.orge28e4982009-09-25 20:51:45 +0000203 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 = []
dpranke@google.com22e29d42009-10-28 00:48:26 +0000230 gclient_scm.RunSVNAndGetFileList(options,
231 ['update', base_path] + additional_args,
maruel@chromium.org7753d242009-10-07 17:40:24 +0000232 self.root_dir, files_list)
msb@chromium.orge28e4982009-09-25 20:51:45 +0000233
234 self.mox.ReplayAll()
235 scm = self._scm_wrapper(url=self.url, root_dir=self.root_dir,
236 relpath=self.relpath)
237 scm.update(options, (), files_list)
238
239 def testUpdateGit(self):
240 options = self.Options(verbose=True)
241 file_path = os.path.join(self.root_dir, self.relpath, '.git')
242 gclient.os.path.exists(file_path).AndReturn(True)
243 print("________ found .git directory; skipping %s" % self.relpath)
244
245 self.mox.ReplayAll()
246 scm = self._scm_wrapper(url=self.url, root_dir=self.root_dir,
247 relpath=self.relpath)
248 file_list = []
249 scm.update(options, self.args, file_list)
250
251 def testGetSVNFileInfo(self):
252 xml_text = r"""<?xml version="1.0"?>
253<info>
254<entry kind="file" path="%s" revision="14628">
255<url>http://src.chromium.org/svn/trunk/src/chrome/app/d</url>
256<repository><root>http://src.chromium.org/svn</root></repository>
257<wc-info>
258<schedule>add</schedule>
259<depth>infinity</depth>
260<copy-from-url>http://src.chromium.org/svn/trunk/src/chrome/app/DEPS</copy-from-url>
261<copy-from-rev>14628</copy-from-rev>
262<checksum>369f59057ba0e6d9017e28f8bdfb1f43</checksum>
263</wc-info>
264</entry>
265</info>
266""" % self.url
267 gclient_scm.CaptureSVN(['info', '--xml', self.url],
268 '.', True).AndReturn(xml_text)
269 expected = {
270 'URL': 'http://src.chromium.org/svn/trunk/src/chrome/app/d',
271 'UUID': None,
272 'Repository Root': 'http://src.chromium.org/svn',
273 'Schedule': 'add',
274 'Copied From URL':
275 'http://src.chromium.org/svn/trunk/src/chrome/app/DEPS',
276 'Copied From Rev': '14628',
277 'Path': self.url,
278 'Revision': 14628,
279 'Node Kind': 'file',
280 }
281 self.mox.ReplayAll()
282 file_info = self._CaptureSVNInfo(self.url, '.', True)
283 self.assertEquals(sorted(file_info.items()), sorted(expected.items()))
284
285 def testCaptureSvnInfo(self):
286 xml_text = """<?xml version="1.0"?>
287<info>
288<entry
289 kind="dir"
290 path="."
291 revision="35">
292<url>%s</url>
293<repository>
294<root>%s</root>
295<uuid>7b9385f5-0452-0410-af26-ad4892b7a1fb</uuid>
296</repository>
297<wc-info>
298<schedule>normal</schedule>
299<depth>infinity</depth>
300</wc-info>
301<commit
302 revision="35">
303<author>maruel</author>
304<date>2008-12-04T20:12:19.685120Z</date>
305</commit>
306</entry>
307</info>
308""" % (self.url, self.root_dir)
309 gclient_scm.CaptureSVN(['info', '--xml',
310 self.url], '.', True).AndReturn(xml_text)
311 self.mox.ReplayAll()
312 file_info = self._CaptureSVNInfo(self.url, '.', True)
313 expected = {
314 'URL': self.url,
315 'UUID': '7b9385f5-0452-0410-af26-ad4892b7a1fb',
316 'Revision': 35,
317 'Repository Root': self.root_dir,
318 'Schedule': 'normal',
319 'Copied From URL': None,
320 'Copied From Rev': None,
321 'Path': '.',
322 'Node Kind': 'dir',
323 }
324 self.assertEqual(file_info, expected)
325
326
327class GitWrapperTestCase(gclient_test.GClientBaseTestCase):
328 class OptionsObject(object):
329 def __init__(self, test_case, verbose=False, revision=None):
330 self.verbose = verbose
331 self.revision = revision
332 self.manually_grab_svn_rev = True
333 self.deps_os = None
334 self.force = False
335 self.nohooks = False
336
337 sample_git_import = """blob
338mark :1
339data 6
340Hello
341
342blob
343mark :2
344data 4
345Bye
346
347reset refs/heads/master
348commit refs/heads/master
349mark :3
350author Bob <bob@example.com> 1253744361 -0700
351committer Bob <bob@example.com> 1253744361 -0700
352data 8
353A and B
354M 100644 :1 a
355M 100644 :2 b
356
357blob
358mark :4
359data 10
360Hello
361You
362
363blob
364mark :5
365data 8
366Bye
367You
368
369commit refs/heads/origin
370mark :6
371author Alice <alice@example.com> 1253744424 -0700
372committer Alice <alice@example.com> 1253744424 -0700
373data 13
374Personalized
375from :3
376M 100644 :4 a
377M 100644 :5 b
378
379reset refs/heads/master
380from :3
381"""
msb@chromium.orge28e4982009-09-25 20:51:45 +0000382 def Options(self, *args, **kwargs):
383 return self.OptionsObject(self, *args, **kwargs)
384
385 def CreateGitRepo(self, git_import, path):
maruel@chromium.orgea6c2c52009-10-09 20:38:14 +0000386 try:
387 subprocess.Popen(['git', 'init'], stdout=subprocess.PIPE,
388 stderr=subprocess.STDOUT, cwd=path).communicate()
389 except WindowsError:
390 # git is not available, skip this test.
391 return False
msb@chromium.orge28e4982009-09-25 20:51:45 +0000392 subprocess.Popen(['git', 'fast-import'], stdin=subprocess.PIPE,
393 stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
394 cwd=path).communicate(input=git_import)
395 subprocess.Popen(['git', 'checkout'], stdout=subprocess.PIPE,
396 stderr=subprocess.STDOUT, cwd=path).communicate()
maruel@chromium.orgea6c2c52009-10-09 20:38:14 +0000397 return True
msb@chromium.orge28e4982009-09-25 20:51:45 +0000398
399 def GetGitRev(self, path):
400 return subprocess.Popen(['git', 'rev-parse', 'HEAD'],
401 stdout=subprocess.PIPE,
402 stderr=subprocess.STDOUT,
403 cwd=path).communicate()[0].strip()
404
405 def setUp(self):
406 gclient_test.BaseTestCase.setUp(self)
407 self.args = self.Args()
408 self.url = 'git://foo'
409 self.root_dir = tempfile.mkdtemp()
410 self.relpath = '.'
411 self.base_path = os.path.join(self.root_dir, self.relpath)
maruel@chromium.orgea6c2c52009-10-09 20:38:14 +0000412 self.enabled = self.CreateGitRepo(self.sample_git_import, self.base_path)
msb@chromium.orge28e4982009-09-25 20:51:45 +0000413
414 def tearDown(self):
415 shutil.rmtree(self.root_dir)
416 gclient_test.BaseTestCase.tearDown(self)
417
418 def testDir(self):
419 members = [
420 'FullUrlForRelativeUrl', 'RunCommand', 'cleanup', 'diff', 'export',
421 'relpath', 'revert', 'runhooks', 'scm_name', 'status', 'update', 'url',
422 ]
423
424 # If you add a member, be sure to add the relevant test!
425 self.compareMembers(gclient_scm.CreateSCM(url=self.url), members)
426
427 def testRevertMissing(self):
maruel@chromium.orgea6c2c52009-10-09 20:38:14 +0000428 if not self.enabled:
429 return
msb@chromium.orge28e4982009-09-25 20:51:45 +0000430 options = self.Options()
431 file_path = os.path.join(self.base_path, 'a')
432 os.remove(file_path)
433 scm = gclient_scm.CreateSCM(url=self.url, root_dir=self.root_dir,
434 relpath=self.relpath)
435 file_list = []
436 scm.revert(options, self.args, file_list)
437 self.assertEquals(file_list, [file_path])
438 file_list = []
439 scm.diff(options, self.args, file_list)
440 self.assertEquals(file_list, [])
441
442 def testRevertNone(self):
maruel@chromium.orgea6c2c52009-10-09 20:38:14 +0000443 if not self.enabled:
444 return
msb@chromium.orge28e4982009-09-25 20:51:45 +0000445 options = self.Options()
446 scm = gclient_scm.CreateSCM(url=self.url, root_dir=self.root_dir,
447 relpath=self.relpath)
448 file_list = []
449 scm.revert(options, self.args, file_list)
450 self.assertEquals(file_list, [])
451 self.assertEquals(self.GetGitRev(self.base_path),
452 '069c602044c5388d2d15c3f875b057c852003458')
453
454
455 def testRevertModified(self):
maruel@chromium.orgea6c2c52009-10-09 20:38:14 +0000456 if not self.enabled:
457 return
msb@chromium.orge28e4982009-09-25 20:51:45 +0000458 options = self.Options()
459 file_path = os.path.join(self.base_path, 'a')
460 open(file_path, 'a').writelines('touched\n')
461 scm = gclient_scm.CreateSCM(url=self.url, root_dir=self.root_dir,
462 relpath=self.relpath)
463 file_list = []
464 scm.revert(options, self.args, file_list)
465 self.assertEquals(file_list, [file_path])
466 file_list = []
467 scm.diff(options, self.args, file_list)
468 self.assertEquals(file_list, [])
469 self.assertEquals(self.GetGitRev(self.base_path),
470 '069c602044c5388d2d15c3f875b057c852003458')
471
472 def testRevertNew(self):
maruel@chromium.orgea6c2c52009-10-09 20:38:14 +0000473 if not self.enabled:
474 return
msb@chromium.orge28e4982009-09-25 20:51:45 +0000475 options = self.Options()
476 file_path = os.path.join(self.base_path, 'c')
477 f = open(file_path, 'w')
478 f.writelines('new\n')
479 f.close()
480 subprocess.Popen(['git', 'add', 'c'], stdout=subprocess.PIPE,
481 stderr=subprocess.STDOUT, cwd=self.base_path).communicate()
482 scm = gclient_scm.CreateSCM(url=self.url, root_dir=self.root_dir,
483 relpath=self.relpath)
484 file_list = []
485 scm.revert(options, self.args, file_list)
486 self.assertEquals(file_list, [file_path])
487 file_list = []
488 scm.diff(options, self.args, file_list)
489 self.assertEquals(file_list, [])
490 self.assertEquals(self.GetGitRev(self.base_path),
491 '069c602044c5388d2d15c3f875b057c852003458')
492
493 def testStatusNew(self):
maruel@chromium.orgea6c2c52009-10-09 20:38:14 +0000494 if not self.enabled:
495 return
msb@chromium.orge28e4982009-09-25 20:51:45 +0000496 options = self.Options()
497 file_path = os.path.join(self.base_path, 'a')
498 open(file_path, 'a').writelines('touched\n')
499 scm = gclient_scm.CreateSCM(url=self.url, root_dir=self.root_dir,
500 relpath=self.relpath)
501 file_list = []
502 scm.status(options, self.args, file_list)
503 self.assertEquals(file_list, [file_path])
504
505 def testStatus2New(self):
maruel@chromium.orgea6c2c52009-10-09 20:38:14 +0000506 if not self.enabled:
507 return
msb@chromium.orge28e4982009-09-25 20:51:45 +0000508 options = self.Options()
509 expected_file_list = []
510 for f in ['a', 'b']:
511 file_path = os.path.join(self.base_path, f)
512 open(file_path, 'a').writelines('touched\n')
513 expected_file_list.extend([file_path])
514 scm = gclient_scm.CreateSCM(url=self.url, root_dir=self.root_dir,
515 relpath=self.relpath)
516 file_list = []
517 scm.status(options, self.args, file_list)
518 expected_file_list = [os.path.join(self.base_path, x) for x in ['a', 'b']]
519 self.assertEquals(sorted(file_list), expected_file_list)
520
521 def testUpdateCheckout(self):
maruel@chromium.orgea6c2c52009-10-09 20:38:14 +0000522 if not self.enabled:
523 return
msb@chromium.orge28e4982009-09-25 20:51:45 +0000524 options = self.Options(verbose=True)
525 root_dir = tempfile.mkdtemp()
526 relpath = 'foo'
527 base_path = os.path.join(root_dir, relpath)
528 url = os.path.join(self.root_dir, self.relpath, '.git')
529 try:
530 scm = gclient_scm.CreateSCM(url=url, root_dir=root_dir,
531 relpath=relpath)
532 file_list = []
533 scm.update(options, (), file_list)
534 self.assertEquals(len(file_list), 2)
535 self.assert_(os.path.isfile(os.path.join(base_path, 'a')))
536 self.assertEquals(self.GetGitRev(base_path),
537 '069c602044c5388d2d15c3f875b057c852003458')
538 finally:
539 shutil.rmtree(root_dir)
540
541 def testUpdateUpdate(self):
maruel@chromium.orgea6c2c52009-10-09 20:38:14 +0000542 if not self.enabled:
543 return
msb@chromium.orge28e4982009-09-25 20:51:45 +0000544 options = self.Options()
545 expected_file_list = [os.path.join(self.base_path, x) for x in ['a', 'b']]
546 scm = gclient_scm.CreateSCM(url=self.url, root_dir=self.root_dir,
547 relpath=self.relpath)
548 file_list = []
549 scm.update(options, (), file_list)
550 self.assertEquals(self.GetGitRev(self.base_path),
551 'a7142dc9f0009350b96a11f372b6ea658592aa95')
552
553
554class RunSVNTestCase(gclient_test.BaseTestCase):
555 def testRunSVN(self):
556 param2 = 'bleh'
557 self.mox.StubOutWithMock(gclient_utils, 'SubprocessCall')
558 gclient_utils.SubprocessCall(['svn', 'foo', 'bar'], param2).AndReturn(None)
559 self.mox.ReplayAll()
560 gclient_scm.RunSVN(['foo', 'bar'], param2)
561
562
563if __name__ == '__main__':
564 unittest.main()
565
566# vim: ts=2:sw=2:tw=80:et: