From 389d6dea37a850fb10dffa006262930f78565733 Mon Sep 17 00:00:00 2001 From: "maruel@chromium.org" Date: Thu, 9 Sep 2010 14:14:37 +0000 Subject: [PATCH] Improve tests and remove some unused GIT test. This is needed to improve the git tests further in a later change. BUG=54084 TEST=none Review URL: http://codereview.chromium.org/3294017 git-svn-id: svn://svn.chromium.org/chrome/trunk/tools/depot_tools@58934 0039d316-1c4b-4281-b951-d872f2087c98 --- tests/gclient_scm_test.py | 165 ++++++++++++++++++++++++-------------- tests/scm_unittest.py | 94 ++-------------------- tests/super_mox.py | 37 ++++++--- 3 files changed, 137 insertions(+), 159 deletions(-) diff --git a/tests/gclient_scm_test.py b/tests/gclient_scm_test.py index 3267745bb5..43cae2b753 100755 --- a/tests/gclient_scm_test.py +++ b/tests/gclient_scm_test.py @@ -11,17 +11,18 @@ from shutil import rmtree import StringIO from subprocess import Popen, PIPE, STDOUT import tempfile +import unittest import __builtin__ # Fixes include path. -from super_mox import mox, SuperMoxBaseTestBase, SuperMoxTestBase +from super_mox import mox, TestCaseUtils, SuperMoxTestBase import gclient_scm -class GCBaseTestCase(SuperMoxTestBase): - # Like unittest's assertRaises, but checks for Gclient.Error. +class GCBaseTestCase(object): def assertRaisesError(self, msg, fn, *args, **kwargs): + """Like unittest's assertRaises() but checks for Gclient.Error.""" try: fn(*args, **kwargs) except gclient_scm.gclient_utils.Error, e: @@ -29,15 +30,33 @@ class GCBaseTestCase(SuperMoxTestBase): else: self.fail('%s not raised' % msg) + def setUp(self): + self.stdout = StringIO.StringIO() -class BaseTestCase(GCBaseTestCase): + def tearDown(self): + try: + self.stdout.getvalue() + self.fail() + except AttributeError: + pass + + def checkstdout(self, expected): + value = self.stdout.getvalue() + self.stdout.close() + self.assertEquals(expected, value) + + +class BaseTestCase(GCBaseTestCase, SuperMoxTestBase): def setUp(self): GCBaseTestCase.setUp(self) + SuperMoxTestBase.setUp(self) + self.mox.StubOutWithMock(gclient_scm.gclient_utils, 'CheckCall') self.mox.StubOutWithMock(gclient_scm.gclient_utils, 'CheckCallAndFilter') self.mox.StubOutWithMock(gclient_scm.gclient_utils, 'CheckCallAndFilterAndHeader') self.mox.StubOutWithMock(gclient_scm.gclient_utils, 'FileRead') self.mox.StubOutWithMock(gclient_scm.gclient_utils, 'FileWrite') + self.mox.StubOutWithMock(gclient_scm.gclient_utils, 'Popen') self.mox.StubOutWithMock(gclient_scm.gclient_utils, 'RemoveDirectory') self._CaptureSVNInfo = gclient_scm.scm.SVN.CaptureInfo self.mox.StubOutWithMock(gclient_scm.scm.SVN, 'Capture') @@ -47,20 +66,10 @@ class BaseTestCase(GCBaseTestCase): self._scm_wrapper = gclient_scm.CreateSCM gclient_scm.sys.stdout.flush = lambda: None gclient_scm.scm.SVN.current_version = None - self.stdout = StringIO.StringIO() def tearDown(self): GCBaseTestCase.tearDown(self) - try: - self.stdout.getvalue() - self.fail() - except AttributeError: - pass - - def checkstdout(self, expected): - value = self.stdout.getvalue() - self.stdout.close() - self.assertEquals(expected, value) + SuperMoxTestBase.tearDown(self) class SVNWrapperTestCase(BaseTestCase): @@ -80,10 +89,7 @@ class SVNWrapperTestCase(BaseTestCase): def setUp(self): BaseTestCase.setUp(self) - self.root_dir = self.Dir() - self.args = self.Args() - self.url = self.Url() - self.relpath = 'asf' + self.url = self.SvnUrl() def testDir(self): members = [ @@ -497,7 +503,7 @@ class SVNWrapperTestCase(BaseTestCase): ('________ found .git directory; skipping %s\n' % self.relpath)) -class GitWrapperTestCase(BaseTestCase): +class GitWrapperTestCase(GCBaseTestCase, TestCaseUtils, unittest.TestCase): """This class doesn't use pymox.""" class OptionsObject(object): def __init__(self, test_case, verbose=False, revision=None): @@ -508,7 +514,7 @@ class GitWrapperTestCase(BaseTestCase): self.force = False self.reset = False self.nohooks = False - self.stdout = StringIO.StringIO() + self.stdout = test_case.stdout sample_git_import = """blob mark :1 @@ -561,36 +567,39 @@ from :3 def CreateGitRepo(self, git_import, path): """Do it for real.""" try: - Popen(['git', 'init'], stdout=PIPE, stderr=STDOUT, + Popen(['git', 'init', '-q'], stdout=PIPE, stderr=STDOUT, cwd=path).communicate() except OSError: # git is not available, skip this test. return False - Popen(['git', 'fast-import'], stdin=PIPE, stdout=PIPE, stderr=STDOUT, - cwd=path).communicate(input=git_import) - Popen(['git', 'checkout'], stdout=PIPE, stderr=STDOUT, - cwd=path).communicate() + Popen(['git', 'fast-import', '--quiet'], stdin=PIPE, stdout=PIPE, + stderr=STDOUT, cwd=path).communicate(input=git_import) + Popen(['git', 'checkout', '-q'], stdout=PIPE, stderr=STDOUT, + cwd=path).communicate() Popen(['git', 'remote', 'add', '-f', 'origin', '.'], stdout=PIPE, - stderr=STDOUT, cwd=path).communicate() - Popen(['git', 'checkout', '-b', 'new', 'origin/master'], stdout=PIPE, - stderr=STDOUT, cwd=path).communicate() - Popen(['git', 'push', 'origin', 'origin/origin:origin/master'], stdout=PIPE, - stderr=STDOUT, cwd=path).communicate() + stderr=STDOUT, cwd=path).communicate() + Popen(['git', 'checkout', '-b', 'new', 'origin/master', '-q'], stdout=PIPE, + stderr=STDOUT, cwd=path).communicate() + Popen(['git', 'push', 'origin', 'origin/origin:origin/master', '-q'], + stdout=PIPE, stderr=STDOUT, cwd=path).communicate() Popen(['git', 'config', '--unset', 'remote.origin.fetch'], stdout=PIPE, - stderr=STDOUT, cwd=path).communicate() + stderr=STDOUT, cwd=path).communicate() return True def setUp(self): - self.args = self.Args() + GCBaseTestCase.setUp(self) + TestCaseUtils.setUp(self) + unittest.TestCase.setUp(self) self.url = 'git://foo' self.root_dir = tempfile.mkdtemp() self.relpath = '.' self.base_path = gclient_scm.os.path.join(self.root_dir, self.relpath) self.enabled = self.CreateGitRepo(self.sample_git_import, self.base_path) - BaseTestBase.setUp(self) def tearDown(self): - BaseTestBase.tearDown(self) + GCBaseTestCase.tearDown(self) + TestCaseUtils.tearDown(self) + unittest.TestCase.tearDown(self) rmtree(self.root_dir) def testDir(self): @@ -602,6 +611,7 @@ from :3 # If you add a member, be sure to add the relevant test! self.compareMembers(gclient_scm.CreateSCM(url=self.url), members) + self.checkstdout('') def testRevertMissing(self): if not self.enabled: @@ -619,6 +629,11 @@ from :3 file_list = [] scm.diff(options, self.args, file_list) self.assertEquals(file_list, []) + self.checkstdout( + ('\n_____ . at refs/heads/master\n\n\n' + '________ running \'git reset --hard origin/master\' in \'%s\'\n' + 'HEAD is now at a7142dc Personalized\n') % + gclient_scm.os.path.join(self.root_dir, '.')) def testRevertNone(self): if not self.enabled: @@ -633,7 +648,11 @@ from :3 self.assertEquals(file_list, []) self.assertEquals(scm.revinfo(options, self.args, None), 'a7142dc9f0009350b96a11f372b6ea658592aa95') - + self.checkstdout( + ('\n_____ . at refs/heads/master\n\n\n' + '________ running \'git reset --hard origin/master\' in \'%s\'\n' + 'HEAD is now at a7142dc Personalized\n') % + gclient_scm.os.path.join(self.root_dir, '.')) def testRevertModified(self): if not self.enabled: @@ -653,6 +672,11 @@ from :3 self.assertEquals(file_list, []) self.assertEquals(scm.revinfo(options, self.args, None), 'a7142dc9f0009350b96a11f372b6ea658592aa95') + self.checkstdout( + ('\n_____ . at refs/heads/master\n\n\n' + '________ running \'git reset --hard origin/master\' in \'%s\'\n' + 'HEAD is now at a7142dc Personalized\n') % + gclient_scm.os.path.join(self.root_dir, '.')) def testRevertNew(self): if not self.enabled: @@ -676,6 +700,11 @@ from :3 self.assertEquals(file_list, []) self.assertEquals(scm.revinfo(options, self.args, None), 'a7142dc9f0009350b96a11f372b6ea658592aa95') + self.checkstdout( + ('\n_____ . at refs/heads/master\n\n\n' + '________ running \'git reset --hard origin/master\' in \'%s\'\n' + 'HEAD is now at a7142dc Personalized\n') % + gclient_scm.os.path.join(self.root_dir, '.')) def testStatusNew(self): if not self.enabled: @@ -688,6 +717,10 @@ from :3 file_list = [] scm.status(options, self.args, file_list) self.assertEquals(file_list, [file_path]) + self.checkstdout( + ('\n________ running \'git diff --name-status ' + '069c602044c5388d2d15c3f875b057c852003458\' in \'%s\'\nM\ta\n') % + gclient_scm.os.path.join(self.root_dir, '.')) def testStatus2New(self): if not self.enabled: @@ -705,6 +738,10 @@ from :3 expected_file_list = [gclient_scm.os.path.join(self.base_path, x) for x in ['a', 'b']] self.assertEquals(sorted(file_list), expected_file_list) + self.checkstdout( + ('\n________ running \'git diff --name-status ' + '069c602044c5388d2d15c3f875b057c852003458\' in \'%s\'\nM\ta\nM\tb\n') % + gclient_scm.os.path.join(self.root_dir, '.')) def testUpdateCheckout(self): if not self.enabled: @@ -726,6 +763,13 @@ from :3 '069c602044c5388d2d15c3f875b057c852003458') finally: rmtree(root_dir) + join = gclient_scm.os.path.join + self.checkstdout( + ('\n_____ foo at refs/heads/master\n\n' + '________ running \'git clone -b master --verbose %s %s\' in \'%s\'\n' + 'Initialized empty Git repository in %s\n') % + (join(self.root_dir, '.', '.git'), join(root_dir, 'foo'), root_dir, + join(root_dir, 'foo', '.git') + '/')) def testUpdateUpdate(self): if not self.enabled: @@ -740,6 +784,7 @@ from :3 self.assertEquals(file_list, expected_file_list) self.assertEquals(scm.revinfo(options, (), None), 'a7142dc9f0009350b96a11f372b6ea658592aa95') + self.checkstdout('\n_____ . at refs/heads/master\n\n') def testUpdateUnstagedConflict(self): if not self.enabled: @@ -754,6 +799,7 @@ from :3 "Aborting.\n" "Please, commit your changes or stash them before you can merge.\n") self.assertRaisesError(exception, scm.update, options, (), []) + self.checkstdout('\n_____ . at refs/heads/master\n') def testUpdateConflict(self): if not self.enabled: @@ -763,23 +809,26 @@ from :3 relpath=self.relpath) file_path = gclient_scm.os.path.join(self.base_path, 'b') f = open(file_path, 'w').writelines('conflict\n') - scm._Run(['commit', '-am', 'test']) - self.mox.StubOutWithMock(__builtin__, 'raw_input') - __builtin__.raw_input.__call__(mox.StrContains('Cannot fast-forward merge, ' - 'attempt to rebase? (y)es / ' - '(q)uit / (s)kip : ') - ).AndReturn('y') - self.mox.ReplayAll() - exception = \ - 'Conflict while rebasing this branch.\n' \ - 'Fix the conflict and run gclient again.\n' \ - "See 'man git-rebase' for details.\n" + scm._Run(['commit', '-am', 'test'], options) + __builtin__.raw_input = lambda x: 'y' + exception = ('Conflict while rebasing this branch.\n' + 'Fix the conflict and run gclient again.\n' + 'See \'man git-rebase\' for details.\n') self.assertRaisesError(exception, scm.update, options, (), []) - exception = \ - '\n____ . at refs/heads/master\n' \ - '\tYou have unstaged changes.\n' \ - '\tPlease commit, stash, or reset.\n' + exception = ('\n____ . at refs/heads/master\n' + '\tYou have unstaged changes.\n' + '\tPlease commit, stash, or reset.\n') self.assertRaisesError(exception, scm.update, options, (), []) + # The hash always changes. Use a cheap trick. + start = ('\n________ running \'git commit -am test\' in \'%s\'\n' + '[new ') % gclient_scm.os.path.join(self.root_dir, '.') + end = ('] test\n 1 files changed, 1 insertions(+), ' + '1 deletions(-)\n\n_____ . at refs/heads/master\n' + 'Attempting rebase onto refs/remotes/origin/master...\n') + self.assertTrue(self.stdout.getvalue().startswith(start)) + self.assertTrue(self.stdout.getvalue().endswith(end)) + self.assertEquals(len(self.stdout.getvalue()), len(start) + len(end) + 7) + self.stdout.close() def testUpdateNotGit(self): if not self.enabled: @@ -789,13 +838,13 @@ from :3 relpath=self.relpath) git_path = gclient_scm.os.path.join(self.base_path, '.git') rename(git_path, git_path + 'foo') - exception = \ - '\n____ . at refs/heads/master\n' \ - '\tPath is not a git repo. No .git dir.\n' \ - '\tTo resolve:\n' \ - '\t\trm -rf .\n' \ - '\tAnd run gclient sync again\n' + exception = ('\n____ . at refs/heads/master\n' + '\tPath is not a git repo. No .git dir.\n' + '\tTo resolve:\n' + '\t\trm -rf .\n' + '\tAnd run gclient sync again\n') self.assertRaisesError(exception, scm.update, options, (), []) + self.checkstdout('') def testRevinfo(self): if not self.enabled: @@ -805,10 +854,10 @@ from :3 relpath=self.relpath) rev_info = scm.revinfo(options, (), None) self.assertEquals(rev_info, '069c602044c5388d2d15c3f875b057c852003458') + self.checkstdout('') if __name__ == '__main__': - import unittest unittest.main() # vim: ts=2:sw=2:tw=80:et: diff --git a/tests/scm_unittest.py b/tests/scm_unittest.py index 0df6335378..bc552ce4d2 100755 --- a/tests/scm_unittest.py +++ b/tests/scm_unittest.py @@ -9,7 +9,7 @@ from shutil import rmtree import tempfile # Fixes include path. -from super_mox import mox, SuperMoxBaseTestBase, SuperMoxTestBase +from super_mox import mox, TestCaseUtils, SuperMoxTestBase import scm @@ -46,89 +46,8 @@ class RootTestCase(BaseSCMTestCase): self.compareMembers(scm, members) -class GitWrapperTestCase(SuperMoxBaseTestBase): - sample_git_import = """blob -mark :1 -data 6 -Hello - -blob -mark :2 -data 4 -Bye - -reset refs/heads/master -commit refs/heads/master -mark :3 -author Bob 1253744361 -0700 -committer Bob 1253744361 -0700 -data 8 -A and B -M 100644 :1 a -M 100644 :2 b - -blob -mark :4 -data 10 -Hello -You - -blob -mark :5 -data 8 -Bye -You - -commit refs/heads/origin -mark :6 -author Alice 1253744424 -0700 -committer Alice 1253744424 -0700 -data 13 -Personalized -from :3 -M 100644 :4 a -M 100644 :5 b - -reset refs/heads/master -from :3 -""" - - def CreateGitRepo(self, git_import, path): - try: - scm.subprocess.Popen(['git', 'init'], - stdout=scm.subprocess.PIPE, - stderr=scm.subprocess.STDOUT, - cwd=path).communicate() - except OSError: - # git is not available, skip this test. - return False - scm.subprocess.Popen(['git', 'fast-import'], - stdin=scm.subprocess.PIPE, - stdout=scm.subprocess.PIPE, - stderr=scm.subprocess.STDOUT, - cwd=path).communicate(input=git_import) - scm.subprocess.Popen(['git', 'checkout'], - stdout=scm.subprocess.PIPE, - stderr=scm.subprocess.STDOUT, - cwd=path).communicate() - return True - - def setUp(self): - SuperMoxBaseTestBase.setUp(self) - self.args = self.Args() - self.url = 'git://foo' - self.root_dir = tempfile.mkdtemp() - self.relpath = '.' - self.base_path = scm.os.path.join(self.root_dir, self.relpath) - self.enabled = self.CreateGitRepo(self.sample_git_import, self.base_path) - self.fake_root = self.Dir() - - def tearDown(self): - rmtree(self.root_dir) - SuperMoxBaseTestBase.tearDown(self) - +class GitWrapperTestCase(BaseSCMTestCase): def testMembersChanged(self): - self.mox.ReplayAll() members = [ 'AssertVersion', 'Capture', 'CaptureStatus', 'FetchUpstreamTuple', @@ -141,20 +60,17 @@ from :3 def testGetEmail(self): self.mox.StubOutWithMock(scm.GIT, 'Capture') - scm.GIT.Capture(['config', 'user.email'], self.fake_root, error_ok=True + scm.GIT.Capture(['config', 'user.email'], self.root_dir, error_ok=True ).AndReturn(['mini@me.com', '']) self.mox.ReplayAll() - self.assertEqual(scm.GIT.GetEmail(self.fake_root), 'mini@me.com') + self.assertEqual(scm.GIT.GetEmail(self.root_dir), 'mini@me.com') class SVNTestCase(BaseSCMTestCase): def setUp(self): BaseSCMTestCase.setUp(self) - self.root_dir = self.Dir() - self.args = self.Args() - self.url = self.Url() - self.relpath = 'asf' self.mox.StubOutWithMock(scm.SVN, 'Capture') + self.url = self.SvnUrl() def testMembersChanged(self): self.mox.ReplayAll() diff --git a/tests/super_mox.py b/tests/super_mox.py index bdd96a5c55..b8047cd26c 100644 --- a/tests/super_mox.py +++ b/tests/super_mox.py @@ -28,7 +28,7 @@ class IsOneOf(mox.Comparator): return '' % str(self._keys) -class SuperMoxBaseTestBase(mox.MoxTestBase): +class TestCaseUtils(object): """Base class with some additional functionalities. People will usually want to use SuperMoxTestBase instead.""" # Backup the separator in case it gets mocked @@ -56,7 +56,7 @@ class SuperMoxBaseTestBase(mox.MoxTestBase): return (self._RANDOM_CHOICE((self._OS_SEP, '')) + self._DirElts(max_elt_count, max_elt_length)) - def Url(self, max_elt_count=4, max_elt_length=8): + def SvnUrl(self, max_elt_count=4, max_elt_length=8): return ('svn://random_host:port/a' + self._DirElts(max_elt_count, max_elt_length ).replace(self._OS_SEP, '/')) @@ -64,11 +64,11 @@ class SuperMoxBaseTestBase(mox.MoxTestBase): def RootDir(self, max_elt_count=4, max_elt_length=8): return self._OS_SEP + self._DirElts(max_elt_count, max_elt_length) - def compareMembers(self, object, members): + def compareMembers(self, obj, members): """If you add a member, be sure to add the relevant test!""" # Skip over members starting with '_' since they are usually not meant to # be for public use. - actual_members = [x for x in sorted(dir(object)) + actual_members = [x for x in sorted(dir(obj)) if not x.startswith('_')] expected_members = sorted(members) if actual_members != expected_members: @@ -77,18 +77,20 @@ class SuperMoxBaseTestBase(mox.MoxTestBase): print>>sys.stderr, diff self.assertEqual(actual_members, expected_members) - def UnMock(self, object, name): - """Restore an object inside a test.""" - for (parent, old_child, child_name) in self.mox.stubs.cache: - if parent == object and child_name == name: - setattr(parent, child_name, old_child) - break + def setUp(self): + self.root_dir = self.Dir() + self.args = self.Args() + self.relpath = self.String(200) + + def tearDown(self): + pass -class SuperMoxTestBase(SuperMoxBaseTestBase): +class SuperMoxTestBase(TestCaseUtils, mox.MoxTestBase): def setUp(self): """Patch a few functions with know side-effects.""" - SuperMoxBaseTestBase.setUp(self) + TestCaseUtils.setUp(self) + mox.MoxTestBase.setUp(self) #self.mox.StubOutWithMock(__builtin__, 'open') os_to_mock = ('chdir', 'chown', 'close', 'closerange', 'dup', 'dup2', 'fchdir', 'fchmod', 'fchown', 'fdopen', 'getcwd', 'getpid', 'lseek', @@ -104,6 +106,10 @@ class SuperMoxTestBase(SuperMoxBaseTestBase): # Don't mock stderr since it confuses unittests. self.MockList(sys, ('stdin', 'stdout')) + def tearDown(self): + TestCaseUtils.tearDown(self) + mox.MoxTestBase.tearDown(self) + def MockList(self, parent, items_to_mock): for item in items_to_mock: # Skip over items not present because of OS-specific implementation, @@ -113,3 +119,10 @@ class SuperMoxTestBase(SuperMoxBaseTestBase): self.mox.StubOutWithMock(parent, item) except TypeError: raise TypeError('Couldn\'t mock %s in %s' % (item, parent.__name__)) + + def UnMock(self, object, name): + """Restore an object inside a test.""" + for (parent, old_child, child_name) in self.mox.stubs.cache: + if parent == object and child_name == name: + setattr(parent, child_name, old_child) + break