Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
| 2 # Copyright (c) 2011 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| 3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
| 4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
| 5 | 5 |
| 6 """Generate fake repositories for testing.""" | 6 """Generate fake repositories for testing.""" |
| 7 | 7 |
| 8 import atexit | 8 import atexit |
| 9 import datetime | 9 import datetime |
| 10 import errno | 10 import errno |
| (...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 154 sock.connect((host, port)) | 154 sock.connect((host, port)) |
| 155 logging.debug('%d was bound, waiting to free' % port) | 155 logging.debug('%d was bound, waiting to free' % port) |
| 156 except (socket.error, EnvironmentError): | 156 except (socket.error, EnvironmentError): |
| 157 logging.debug('%d now free' % port) | 157 logging.debug('%d now free' % port) |
| 158 return | 158 return |
| 159 finally: | 159 finally: |
| 160 sock.close() | 160 sock.close() |
| 161 assert False, '%d is still bound' % port | 161 assert False, '%d is still bound' % port |
| 162 | 162 |
| 163 | 163 |
| 164 _FAKE_LOADED = False | |
| 165 | |
| 166 class FakeReposBase(object): | 164 class FakeReposBase(object): |
| 167 """Generate both svn and git repositories to test gclient functionality. | 165 """Generate both svn and git repositories to test gclient functionality. |
| 168 | 166 |
| 169 Many DEPS functionalities need to be tested: Var, File, From, deps_os, hooks, | 167 Many DEPS functionalities need to be tested: Var, File, From, deps_os, hooks, |
| 170 use_relative_paths. | 168 use_relative_paths. |
| 171 | 169 |
| 172 And types of dependencies: Relative urls, Full urls, both svn and git. | 170 And types of dependencies: Relative urls, Full urls, both svn and git. |
| 173 | 171 |
| 174 populateSvn() and populateGit() need to be implemented by the subclass. | 172 populateSvn() and populateGit() need to be implemented by the subclass. |
| 175 """ | 173 """ |
| 176 # Hostname | 174 # Hostname |
| 177 NB_GIT_REPOS = 1 | 175 NB_GIT_REPOS = 1 |
| 178 USERS = [ | 176 USERS = [ |
| 179 ('user1@example.com', 'foo'), | 177 ('user1@example.com', 'foo'), |
| 180 ('user2@example.com', 'bar'), | 178 ('user2@example.com', 'bar'), |
| 181 ] | 179 ] |
| 182 | 180 |
| 183 def __init__(self, host=None): | 181 def __init__(self, host=None): |
| 184 global _FAKE_LOADED | |
| 185 if _FAKE_LOADED: | |
| 186 raise Exception('You can only start one FakeRepos at a time.') | |
| 187 _FAKE_LOADED = True | |
| 188 | |
| 189 self.trial = trial_dir.TrialDir('repos') | 182 self.trial = trial_dir.TrialDir('repos') |
| 190 self.host = host or '127.0.0.1' | 183 self.host = host or '127.0.0.1' |
| 191 # Format is [ None, tree, tree, ...] | 184 # Format is [ None, tree, tree, ...] |
| 192 # i.e. revisions are 1-based. | 185 # i.e. revisions are 1-based. |
| 193 self.svn_revs = [None] | 186 self.svn_revs = [None] |
| 194 # Format is { repo: [ None, (hash, tree), (hash, tree), ... ], ... } | 187 # Format is { repo: [ None, (hash, tree), (hash, tree), ... ], ... } |
| 195 # so reference looks like self.git_hashes[repo][rev][0] for hash and | 188 # so reference looks like self.git_hashes[repo][rev][0] for hash and |
| 196 # self.git_hashes[repo][rev][1] for it's tree snapshot. | 189 # self.git_hashes[repo][rev][1] for it's tree snapshot. |
| 197 # For consistency with self.svn_revs, it is 1-based too. | 190 # For consistency with self.svn_revs, it is 1-based too. |
| 198 self.git_hashes = {} | 191 self.git_hashes = {} |
| (...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 314 return False | 307 return False |
| 315 write(join(self.svn_repo, 'conf', 'svnserve.conf'), | 308 write(join(self.svn_repo, 'conf', 'svnserve.conf'), |
| 316 '[general]\n' | 309 '[general]\n' |
| 317 'anon-access = read\n' | 310 'anon-access = read\n' |
| 318 'auth-access = write\n' | 311 'auth-access = write\n' |
| 319 'password-db = passwd\n') | 312 'password-db = passwd\n') |
| 320 text = '[users]\n' | 313 text = '[users]\n' |
| 321 text += ''.join('%s = %s\n' % (usr, pwd) for usr, pwd in self.USERS) | 314 text += ''.join('%s = %s\n' % (usr, pwd) for usr, pwd in self.USERS) |
| 322 write(join(self.svn_repo, 'conf', 'passwd'), text) | 315 write(join(self.svn_repo, 'conf', 'passwd'), text) |
| 323 | 316 |
| 317 # Necessary to be able to change revision properties | |
|
M-A Ruel
2013/04/16 20:28:04
Sadly, this will break tests on Windows. But I don
kustermann
2013/04/17 13:55:06
I introduced a branch for windows, but I've no ide
| |
| 318 revprop_hook_filename = join(self.svn_repo, 'hooks', 'pre-revprop-change') | |
| 319 write(revprop_hook_filename, | |
| 320 '#!/bin/sh\n' | |
| 321 'exit 0\n') | |
| 322 os.chmod(revprop_hook_filename, 0755) | |
| 323 | |
| 324 # Mac 10.6 ships with a buggy subversion build and we need this line | 324 # Mac 10.6 ships with a buggy subversion build and we need this line |
| 325 # to work around the bug. | 325 # to work around the bug. |
| 326 write(join(self.svn_repo, 'db', 'fsfs.conf'), | 326 write(join(self.svn_repo, 'db', 'fsfs.conf'), |
| 327 '[rep-sharing]\n' | 327 '[rep-sharing]\n' |
| 328 'enable-rep-sharing = false\n') | 328 'enable-rep-sharing = false\n') |
| 329 | 329 |
| 330 # Start the daemon. | 330 # Start the daemon. |
| 331 self.svn_port = find_free_port(self.host, 10000) | 331 self.svn_port = find_free_port(self.host, 10000) |
| 332 logging.debug('Using port %d' % self.svn_port) | 332 logging.debug('Using port %d' % self.svn_port) |
| 333 cmd = ['svnserve', '-d', '--foreground', '-r', self.root_dir, | 333 cmd = ['svnserve', '-d', '--foreground', '-r', self.root_dir, |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 385 def _commit_svn(self, tree): | 385 def _commit_svn(self, tree): |
| 386 self._genTree(self.svn_checkout, tree) | 386 self._genTree(self.svn_checkout, tree) |
| 387 commit_svn(self.svn_checkout, self.USERS[0][0], self.USERS[0][1]) | 387 commit_svn(self.svn_checkout, self.USERS[0][0], self.USERS[0][1]) |
| 388 if self.svn_revs and self.svn_revs[-1]: | 388 if self.svn_revs and self.svn_revs[-1]: |
| 389 new_tree = self.svn_revs[-1].copy() | 389 new_tree = self.svn_revs[-1].copy() |
| 390 new_tree.update(tree) | 390 new_tree.update(tree) |
| 391 else: | 391 else: |
| 392 new_tree = tree.copy() | 392 new_tree = tree.copy() |
| 393 self.svn_revs.append(new_tree) | 393 self.svn_revs.append(new_tree) |
| 394 | 394 |
| 395 def _set_svn_commit_date(self, revision, date): | |
| 396 subprocess2.check_output( | |
| 397 ['svn', 'propset', 'svn:date', '--revprop', '-r', revision, date, | |
| 398 self.svn_base, | |
| 399 '--username', self.USERS[0][0], | |
| 400 '--password', self.USERS[0][1], | |
| 401 '--non-interactive']) | |
| 402 | |
| 395 def _commit_git(self, repo, tree): | 403 def _commit_git(self, repo, tree): |
| 396 repo_root = join(self.git_root, repo) | 404 repo_root = join(self.git_root, repo) |
| 397 self._genTree(repo_root, tree) | 405 self._genTree(repo_root, tree) |
| 398 commit_hash = commit_git(repo_root) | 406 commit_hash = commit_git(repo_root) |
| 399 if self.git_hashes[repo][-1]: | 407 if self.git_hashes[repo][-1]: |
| 400 new_tree = self.git_hashes[repo][-1][1].copy() | 408 new_tree = self.git_hashes[repo][-1][1].copy() |
| 401 new_tree.update(tree) | 409 new_tree.update(tree) |
| 402 else: | 410 else: |
| 403 new_tree = tree.copy() | 411 new_tree = tree.copy() |
| 404 self.git_hashes[repo].append((commit_hash, new_tree)) | 412 self.git_hashes[repo].append((commit_hash, new_tree)) |
| (...skipping 228 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 633 ] | 641 ] |
| 634 """ % { | 642 """ % { |
| 635 'git_base': self.git_base, | 643 'git_base': self.git_base, |
| 636 # See self.__init__() for the format. Grab's the hash of the first | 644 # See self.__init__() for the format. Grab's the hash of the first |
| 637 # commit in repo_2. Only keep the first 7 character because of: | 645 # commit in repo_2. Only keep the first 7 character because of: |
| 638 # TODO(maruel): http://crosbug.com/3591 We need to strip the hash.. duh. | 646 # TODO(maruel): http://crosbug.com/3591 We need to strip the hash.. duh. |
| 639 'hash': self.git_hashes['repo_2'][1][0][:7] | 647 'hash': self.git_hashes['repo_2'][1][0][:7] |
| 640 }, | 648 }, |
| 641 'origin': 'git/repo_1@2\n', | 649 'origin': 'git/repo_1@2\n', |
| 642 }) | 650 }) |
| 643 | 651 |
|
M-A Ruel
2013/04/16 20:28:04
2 lines between file-level symbols
kustermann
2013/04/17 13:55:06
Done.
| |
| 652 class FakeRepoTransitive(FakeReposBase): | |
| 653 """Implements populateSvn()""" | |
| 654 | |
| 655 def populateSvn(self): | |
| 656 """Creates a few revisions of changes including a DEPS file.""" | |
| 657 # Repos | |
| 658 subprocess2.check_call( | |
| 659 ['svn', 'checkout', self.svn_base, self.svn_checkout, | |
| 660 '-q', '--non-interactive', '--no-auth-cache', | |
| 661 '--username', self.USERS[0][0], '--password', self.USERS[0][1]]) | |
| 662 assert os.path.isdir(join(self.svn_checkout, '.svn')) | |
| 663 | |
| 664 def file_system(rev): | |
| 665 DEPS = """deps = { | |
| 666 'src/different_repo': '%(svn_base)strunk/third_party', | |
| 667 'src/different_repo_fixed': '%(svn_base)strunk/third_party@1', | |
| 668 'src/same_repo': '/trunk/third_party', | |
| 669 'src/same_repo_fixed': '/trunk/third_party@1', | |
| 670 }""" % { 'svn_base': self.svn_base } | |
| 671 return { | |
| 672 'trunk/src/DEPS': DEPS, | |
| 673 'trunk/src/origin': 'svn/trunk/src@%(rev)d' % { 'rev': rev }, | |
| 674 'trunk/third_party/origin': | |
| 675 'svn/trunk/third_party@%(rev)d' % { 'rev': rev }, | |
| 676 } | |
| 677 | |
| 678 # We make three commits. We use always the same DEPS contents but | |
| 679 # - 'trunk/src/origin' contains 'svn/trunk/src/origin@rX' | |
| 680 # - 'trunk/third_party/origin' contains 'svn/trunk/third_party/origin@rX' | |
| 681 # where 'X' is the revision number. | |
| 682 # So the 'origin' files will change in every commit. | |
| 683 self._commit_svn(file_system(1)) | |
| 684 self._commit_svn(file_system(2)) | |
| 685 self._commit_svn(file_system(3)) | |
| 686 # We rewrite the timestamps so we can test that '--transitive' will take the | |
| 687 # parent timestamp on different repositories and the parent revision | |
| 688 # otherwise. | |
| 689 self._set_svn_commit_date('1', '2011-10-01T03:00:00.000000Z') | |
| 690 self._set_svn_commit_date('2', '2011-10-09T03:00:00.000000Z') | |
| 691 self._set_svn_commit_date('3', '2011-10-02T03:00:00.000000Z') | |
| 692 | |
| 693 def populateGit(self): | |
| 694 pass | |
| 644 | 695 |
|
M-A Ruel
2013/04/16 20:28:04
here too
kustermann
2013/04/17 13:55:06
Done.
| |
| 645 class FakeReposTestBase(trial_dir.TestCase): | 696 class FakeReposTestBase(trial_dir.TestCase): |
| 646 """This is vaguely inspired by twisted.""" | 697 """This is vaguely inspired by twisted.""" |
| 647 # static FakeRepos instance. Lazy loaded. | |
| 648 FAKE_REPOS = None | |
| 649 # Override if necessary. | 698 # Override if necessary. |
| 650 FAKE_REPOS_CLASS = FakeRepos | 699 FAKE_REPOS_CLASS = FakeRepos |
| 651 | 700 |
| 652 def setUp(self): | 701 def setUp(self): |
| 653 super(FakeReposTestBase, self).setUp() | 702 super(FakeReposTestBase, self).setUp() |
| 654 if not FakeReposTestBase.FAKE_REPOS: | 703 FakeReposTestBase.FAKE_REPOS = self.FAKE_REPOS_CLASS() |
|
M-A Ruel
2013/04/16 20:28:04
That will significantly slow down the test but oh
kustermann
2013/04/17 13:55:06
We can cache it based on 'self.FAKE_REPOS_CLASS'.
| |
| 655 # Lazy create the global instance. | |
| 656 FakeReposTestBase.FAKE_REPOS = self.FAKE_REPOS_CLASS() | |
| 657 # No need to call self.FAKE_REPOS.setUp(), it will be called by the child | 704 # No need to call self.FAKE_REPOS.setUp(), it will be called by the child |
| 658 # class. | 705 # class. |
| 659 # Do not define tearDown(), since super's version does the right thing and | 706 # Do not define tearDown(), since super's version does the right thing and |
| 660 # FAKE_REPOS is kept across tests. | 707 # FAKE_REPOS is kept across tests. |
| 661 | 708 |
| 662 @property | 709 @property |
| 663 def svn_base(self): | 710 def svn_base(self): |
| 664 """Shortcut.""" | 711 """Shortcut.""" |
| 665 return self.FAKE_REPOS.svn_base | 712 return self.FAKE_REPOS.svn_base |
| 666 | 713 |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 743 fake.set_up_git() | 790 fake.set_up_git() |
| 744 print('Fake setup, press enter to quit or Ctrl-C to keep the checkouts.') | 791 print('Fake setup, press enter to quit or Ctrl-C to keep the checkouts.') |
| 745 sys.stdin.readline() | 792 sys.stdin.readline() |
| 746 except KeyboardInterrupt: | 793 except KeyboardInterrupt: |
| 747 trial_dir.TrialDir.SHOULD_LEAK.leak = True | 794 trial_dir.TrialDir.SHOULD_LEAK.leak = True |
| 748 return 0 | 795 return 0 |
| 749 | 796 |
| 750 | 797 |
| 751 if __name__ == '__main__': | 798 if __name__ == '__main__': |
| 752 sys.exit(main(sys.argv)) | 799 sys.exit(main(sys.argv)) |
| OLD | NEW |