Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(113)

Unified Diff: tests/fake_repos.py

Issue 2352002: Make FakeRepos more reusable. Make it work with 'coverage'. (Closed)
Patch Set: Created 10 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « gclient.py ('k') | tests/gclient_smoketest.py » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: tests/fake_repos.py
diff --git a/tests/fake_repos.py b/tests/fake_repos.py
index 85746cf3ab0faf23401d01df8ae6486e50414d53..6d2d0d5ca5c776c25620177437aa57971319b761 100755
--- a/tests/fake_repos.py
+++ b/tests/fake_repos.py
@@ -5,12 +5,17 @@
"""Generate fake repositories for testing."""
+import atexit
import logging
import os
import re
import shutil
import subprocess
import sys
+import unittest
+
+
+## Utility functions
def addKill():
@@ -44,11 +49,6 @@ def write(path, content):
join = os.path.join
-def call(*args, **kwargs):
- logging.debug(args[0])
- subprocess.call(*args, **kwargs)
-
-
def check_call(*args, **kwargs):
logging.debug(args[0])
subprocess.check_call(*args, **kwargs)
@@ -61,6 +61,48 @@ def Popen(*args, **kwargs):
return subprocess.Popen(*args, **kwargs)
+def read_tree(tree_root):
+ """Returns a dict of all the files in a tree. Defaults to self.root_dir."""
+ tree = {}
+ for root, dirs, files in os.walk(tree_root):
+ for d in filter(lambda x: x.startswith('.'), dirs):
+ dirs.remove(d)
+ for f in [join(root, f) for f in files if not f.startswith('.')]:
+ tree[f[len(tree_root) + 1:]] = open(join(root, f), 'rb').read()
+ return tree
+
+
+def dict_diff(dict1, dict2):
+ diff = {}
+ for k, v in dict1.iteritems():
+ if k not in dict2:
+ diff[k] = v
+ elif v != dict2[k]:
+ diff[k] = (v, dict2[k])
+ for k, v in dict2.iteritems():
+ if k not in dict1:
+ diff[k] = v
+ return diff
+
+
+def mangle_svn_tree(*args):
+ result = {}
+ for old_root, new_root, tree in args:
+ for k, v in tree.iteritems():
+ if not k.startswith(old_root):
+ continue
+ result[join(new_root, k[len(old_root) + 1:])] = v
+ return result
+
+
+def mangle_git_tree(*args):
+ result = {}
+ for new_root, tree in args:
+ for k, v in tree.iteritems():
+ result[join(new_root, k)] = v
+ return result
+
+
def commit_svn(repo):
"""Commits the changes and returns the new revision number."""
# Basic parsing.
@@ -96,6 +138,8 @@ def commit_git(repo):
return rev
+_FAKE_LOADED = False
+
class FakeRepos(object):
"""Generate both svn and git repositories to test gclient functionality.
@@ -104,38 +148,71 @@ class FakeRepos(object):
And types of dependencies: Relative urls, Full urls, both svn and git."""
- def __init__(self, trial_dir, leak, local_only):
- self.trial_dir = trial_dir
- self.repos_dir = os.path.join(self.trial_dir, 'repos')
- self.git_root = join(self.repos_dir, 'git')
- self.svn_root = join(self.repos_dir, 'svn_checkout')
- self.leak = leak
- self.local_only = local_only
- self.svnserve = []
- self.gitdaemon = []
- addKill()
- rmtree(self.trial_dir)
- os.mkdir(self.trial_dir)
- os.mkdir(self.repos_dir)
+ # Should leak the repositories.
+ SHOULD_LEAK = False
+ # Override if unhappy.
+ TRIAL_DIR = None
+ # Hostname
+ HOST = '127.0.0.1'
+
+ def __init__(self, trial_dir=None, leak=None, host=None):
+ global _FAKE_LOADED
+ if _FAKE_LOADED:
+ raise Exception('You can only start one FakeRepos at a time.')
+ _FAKE_LOADED = True
+ # Quick hack.
+ if '-v' in sys.argv:
+ logging.basicConfig(level=logging.DEBUG)
+ if '-l' in sys.argv:
+ self.SHOULD_LEAK = True
+ sys.argv.remove('-l')
+ elif leak is not None:
+ self.SHOULD_LEAK = leak
+ if host:
+ self.HOST = host
+ if trial_dir:
+ self.TRIAL_DIR = trial_dir
+
# Format is [ None, tree, tree, ...]
self.svn_revs = [None]
# Format is { repo: [ (hash, tree), (hash, tree), ... ], ... }
self.git_hashes = {}
+ self.svnserve = None
+ self.gitdaemon = None
+ self.common_init = False
+
+ def trial_dir(self):
+ if not self.TRIAL_DIR:
+ self.TRIAL_DIR = os.path.join(
+ os.path.dirname(os.path.abspath(__file__)), '_trial')
+ return self.TRIAL_DIR
def setUp(self):
- self.setUpSVN()
- self.setUpGIT()
+ """All late initialization comes here.
+
+ Note that it deletes all trial_dir() and not only repos_dir."""
+ if not self.common_init:
+ self.common_init = True
+ self.repos_dir = os.path.join(self.trial_dir(), 'repos')
+ self.git_root = join(self.repos_dir, 'git')
+ self.svn_root = join(self.repos_dir, 'svn_checkout')
+ addKill()
+ rmtree(self.trial_dir())
+ os.makedirs(self.repos_dir)
+ atexit.register(self.tearDown)
def tearDown(self):
- for i in self.svnserve:
- logging.debug('Killing svnserve pid %s' % i.pid)
- i.kill()
- for i in self.gitdaemon:
- logging.debug('Killing git-daemon pid %s' % i.pid)
- i.kill()
- if not self.leak:
- logging.debug('Removing %s' % self.trial_dir)
- rmtree(self.trial_dir)
+ if self.svnserve:
+ logging.debug('Killing svnserve pid %s' % self.svnserve.pid)
+ self.svnserve.kill()
+ self.svnserve = None
+ if self.gitdaemon:
+ logging.debug('Killing git-daemon pid %s' % self.gitdaemon.pid)
+ self.gitdaemon.kill()
+ self.gitdaemon = None
+ if not self.SHOULD_LEAK:
+ logging.debug('Removing %s' % self.trial_dir())
+ rmtree(self.trial_dir())
def _genTree(self, root, tree_dict):
"""For a dictionary of file contents, generate a filesystem."""
@@ -155,9 +232,10 @@ class FakeRepos(object):
def setUpSVN(self):
"""Creates subversion repositories and start the servers."""
- assert not self.svnserve
+ if self.svnserve:
+ return
+ self.setUp()
root = join(self.repos_dir, 'svn')
- rmtree(root)
check_call(['svnadmin', 'create', root])
write(join(root, 'conf', 'svnserve.conf'),
'[general]\n'
@@ -171,10 +249,10 @@ class FakeRepos(object):
# Start the daemon.
cmd = ['svnserve', '-d', '--foreground', '-r', self.repos_dir]
- if self.local_only:
+ if self.HOST == '127.0.0.1':
cmd.append('--listen-host=127.0.0.1')
logging.debug(cmd)
- self.svnserve.append(Popen(cmd, cwd=root))
+ self.svnserve = Popen(cmd, cwd=root)
self.populateSvn()
def populateSvn(self):
@@ -224,7 +302,7 @@ deps_os = {
'mac': {
'src/third_party/prout': '/trunk/third_party/prout',
},
-}""" % { 'host': '127.0.0.1' }))
+}""" % { 'host': self.HOST }))
self._commit_svn(file_system(2, """
deps = {
@@ -246,12 +324,13 @@ hooks = [
'open(\\'src/hooked2\\', \\'w\\').write(\\'hooked2\\')'],
},
]
-""" % { 'host': '127.0.0.1' }))
+""" % { 'host': self.HOST }))
def setUpGIT(self):
"""Creates git repositories and start the servers."""
- assert not self.gitdaemon
- rmtree(self.git_root)
+ if self.gitdaemon:
+ return
+ self.setUp()
for repo in ['repo_%d' % r for r in range(1, 5)]:
check_call(['git', 'init', '-q', join(self.git_root, repo)])
self.git_hashes[repo] = []
@@ -281,7 +360,7 @@ deps_os = {
'mac': {
'src/repo4': '/repo_4',
},
-}""" % { 'host': '127.0.0.1' },
+}""" % { 'host': self.HOST },
'origin': 'git/repo_1@1\n',
})
@@ -331,17 +410,19 @@ hooks = [
},
]
""" % {
- # TODO(maruel): http://crosbug.com/3591 We need to strip the hash.. duh.
- 'host': '127.0.0.1', 'hash': self.git_hashes['repo_2'][0][0][:7] },
+ # TODO(maruel): http://crosbug.com/3591 We need to strip the hash.. duh.
+ 'host': self.HOST,
+ 'hash': self.git_hashes['repo_2'][0][0][:7]
+ },
'origin': "git/repo_1@2\n"
})
# Start the daemon.
cmd = ['git', 'daemon', '--export-all', '--base-path=' + self.repos_dir]
- if self.local_only:
+ if self.HOST == '127.0.0.1':
cmd.append('--listen=127.0.0.1')
logging.debug(cmd)
- self.gitdaemon.append(Popen(cmd, cwd=self.repos_dir))
+ self.gitdaemon = Popen(cmd, cwd=self.repos_dir)
def _commit_svn(self, tree):
self._genTree(self.svn_root, tree)
@@ -365,27 +446,71 @@ hooks = [
self.git_hashes[repo].append((hash, new_tree))
+class FakeReposTestBase(unittest.TestCase):
+ """This is vaguely inspired by twisted."""
+
+ # Replace this in your subclass.
+ CLASS_ROOT_DIR = None
+
+ # static FakeRepos instance.
+ FAKE_REPOS = FakeRepos()
+
+ def setUp(self):
+ unittest.TestCase.setUp(self)
+ self.FAKE_REPOS.setUp()
+
+ # Remove left overs and start fresh.
+ if not self.CLASS_ROOT_DIR:
+ self.CLASS_ROOT_DIR = join(self.FAKE_REPOS.trial_dir(), 'smoke')
+ self.root_dir = join(self.CLASS_ROOT_DIR, self.id())
+ rmtree(self.root_dir)
+ os.makedirs(self.root_dir)
+ self.svn_base = 'svn://%s/svn/' % self.FAKE_REPOS.HOST
+ self.git_base = 'git://%s/git/' % self.FAKE_REPOS.HOST
+
+ def tearDown(self):
+ if not self.FAKE_REPOS.SHOULD_LEAK:
+ rmtree(self.root_dir)
+
+ def checkString(self, expected, result):
+ """Prints the diffs to ease debugging."""
+ if expected != result:
+ # Strip the begining
+ while expected and result and expected[0] == result[0]:
+ expected = expected[1:]
+ result = result[1:]
+ # The exception trace makes it hard to read so dump it too.
+ if '\n' in result:
+ print result
+ self.assertEquals(expected, result)
+
+ def check(self, expected, results):
+ """Checks stdout, stderr, retcode."""
+ self.checkString(expected[0], results[0])
+ self.checkString(expected[1], results[1])
+ self.assertEquals(expected[2], results[2])
+
+ def assertTree(self, tree, tree_root=None):
+ """Diff the checkout tree with a dict."""
+ if not tree_root:
+ tree_root = self.root_dir
+ actual = read_tree(tree_root)
+ diff = dict_diff(tree, actual)
+ if diff:
+ logging.debug('Actual %s\n%s' % (tree_root, pprint.pformat(actual)))
+ logging.debug('Expected\n%s' % pprint.pformat(tree))
+ logging.debug('Diff\n%s' % pprint.pformat(diff))
+
+
def main(argv):
- leak = '-l' in argv
- if leak:
- argv.remove('-l')
- verbose = '-v' in argv
- if verbose:
- logging.basicConfig(level=logging.DEBUG)
- argv.remove('-v')
- assert len(argv) == 1, argv
- trial_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)),
- '_trial')
- print 'Using %s' % trial_dir
- fake = FakeRepos(trial_dir, leak, True)
+ fake = FakeRepos()
+ print 'Using %s' % fake.trial_dir()
try:
fake.setUp()
print('Fake setup, press enter to quit or Ctrl-C to keep the checkouts.')
sys.stdin.readline()
except KeyboardInterrupt:
- fake.leak = True
- finally:
- fake.tearDown()
+ fake.SHOULD_LEAK = True
return 0
« no previous file with comments | « gclient.py ('k') | tests/gclient_smoketest.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698