Add regression test for the parallel jobs dependency issue.
Well, the funny thing is that it doesn't find the bug but the framework is already good enough as-is to be worth checked-in, so the next commit can show the relevant difference. R=dpranke@chromium.org BUG=60725 TEST= Review URL: http://codereview.chromium.org/7773001 git-svn-id: svn://svn.chromium.org/chrome/trunk/tools/depot_tools@98869 0039d316-1c4b-4281-b951-d872f2087c98experimental/szager/collated-output
parent
0895b75236
commit
f40e2a5627
@ -0,0 +1,167 @@
|
||||
#!/usr/bin/env python
|
||||
# Copyright (c) 2011 The Chromium Authors. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
"""Unit tests for gclient.py.
|
||||
|
||||
See gclient_smoketest.py for integration tests.
|
||||
"""
|
||||
|
||||
import Queue
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
import unittest
|
||||
|
||||
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||
sys.path.insert(0, os.path.dirname(BASE_DIR))
|
||||
|
||||
import gclient
|
||||
from tests import trial_dir
|
||||
|
||||
|
||||
def write(filename, content):
|
||||
"""Writes the content of a file and create the directories as needed."""
|
||||
filename = os.path.abspath(filename)
|
||||
dirname = os.path.dirname(filename)
|
||||
if not os.path.isdir(dirname):
|
||||
os.makedirs(dirname)
|
||||
with open(filename, 'w') as f:
|
||||
f.write(content)
|
||||
|
||||
|
||||
class SCMMock(object):
|
||||
def __init__(self, unit_test, url):
|
||||
self.unit_test = unit_test
|
||||
self.url = url
|
||||
|
||||
def RunCommand(self, command, options, args, file_list):
|
||||
self.unit_test.assertEquals('None', command)
|
||||
self.unit_test.processed.put(self.url)
|
||||
|
||||
def FullUrlForRelativeUrl(self, url):
|
||||
return self.url + url
|
||||
|
||||
|
||||
class GclientTest(trial_dir.TestCase):
|
||||
def setUp(self):
|
||||
super(GclientTest, self).setUp()
|
||||
self.processed = Queue.Queue()
|
||||
self.previous_dir = os.getcwd()
|
||||
os.chdir(self.root_dir)
|
||||
# Manual mocks.
|
||||
self._old_createscm = gclient.gclient_scm.CreateSCM
|
||||
gclient.gclient_scm.CreateSCM = self._createscm
|
||||
self._old_sys_stdout = sys.stdout
|
||||
sys.stdout = gclient.gclient_utils.MakeFileAutoFlush(sys.stdout)
|
||||
sys.stdout = gclient.gclient_utils.MakeFileAnnotated(sys.stdout)
|
||||
|
||||
def tearDown(self):
|
||||
self.assertEquals([], self._get_processed())
|
||||
gclient.gclient_scm.CreateSCM = self._old_createscm
|
||||
sys.stdout = self._old_sys_stdout
|
||||
os.chdir(self.previous_dir)
|
||||
super(GclientTest, self).tearDown()
|
||||
|
||||
def _createscm(self, parsed_url, root_dir, name):
|
||||
self.assertTrue(parsed_url.startswith('svn://example.com/'), parsed_url)
|
||||
self.assertTrue(root_dir.startswith(self.root_dir), root_dir)
|
||||
return SCMMock(self, parsed_url)
|
||||
|
||||
def testDependencies(self):
|
||||
self._dependencies('1', False)
|
||||
|
||||
def testDependenciesReverse(self):
|
||||
self._dependencies('1', True)
|
||||
|
||||
def testDependenciesJobs(self):
|
||||
self._dependencies('1000', False)
|
||||
|
||||
def testDependenciesJobsReverse(self):
|
||||
self._dependencies('1000', True)
|
||||
|
||||
def _dependencies(self, jobs, reverse):
|
||||
# Verify that dependencies are processed in the right order, e.g. if there
|
||||
# is a dependency 'src' and another 'src/third_party/bar', that bar isn't
|
||||
# fetched until 'src' is done.
|
||||
# jobs is the number of parallel jobs simulated. reverse is to reshuffle the
|
||||
# list to see if it is still processed in order correctly.
|
||||
parser = gclient.Parser()
|
||||
options, args = parser.parse_args(['--jobs', jobs])
|
||||
write(
|
||||
'.gclient',
|
||||
'solutions = [\n'
|
||||
' { "name": "foo", "url": "svn://example.com/foo" },\n'
|
||||
' { "name": "bar", "url": "svn://example.com/bar" },\n'
|
||||
']')
|
||||
write(
|
||||
os.path.join('foo', 'DEPS'),
|
||||
'deps = {\n'
|
||||
' "foo/dir1": "/dir1",\n'
|
||||
' "foo/dir1/dir2/dir3": "/dir1/dir2/dir3",\n'
|
||||
' "foo/dir1/dir4": "/dir1/dir4",\n'
|
||||
' "foo/dir1/dir2/dir3/dir4": "/dir1/dir2/dir3/dir4",\n'
|
||||
'}')
|
||||
write(
|
||||
os.path.join('bar', 'DEPS'),
|
||||
'deps = {\n'
|
||||
' "foo/dir1/dir2": "/dir1/dir2",\n'
|
||||
'}')
|
||||
|
||||
obj = gclient.GClient.LoadCurrentConfig(options)
|
||||
self._check_requirements(obj.dependencies[0], {})
|
||||
self._check_requirements(obj.dependencies[1], {})
|
||||
obj.RunOnDeps('None', args)
|
||||
# The trick here is to manually process the list to make sure it's out of
|
||||
# order.
|
||||
obj.dependencies[0].dependencies.sort(key=lambda x: x.name, reverse=reverse)
|
||||
actual = self._get_processed()
|
||||
# We don't care of the ordering of this item.
|
||||
actual.remove('svn://example.com/bar/dir1/dir2')
|
||||
self.assertEquals(
|
||||
[
|
||||
'svn://example.com/foo',
|
||||
'svn://example.com/bar',
|
||||
'svn://example.com/foo/dir1',
|
||||
'svn://example.com/foo/dir1/dir4',
|
||||
'svn://example.com/foo/dir1/dir2/dir3',
|
||||
'svn://example.com/foo/dir1/dir2/dir3/dir4',
|
||||
],
|
||||
actual)
|
||||
self._check_requirements(
|
||||
obj.dependencies[0],
|
||||
{
|
||||
'foo/dir1': ['foo'],
|
||||
'foo/dir1/dir2/dir3': ['foo', 'foo/dir1'],
|
||||
'foo/dir1/dir2/dir3/dir4': ['foo', 'foo/dir1', 'foo/dir1/dir2/dir3'],
|
||||
'foo/dir1/dir4': ['foo', 'foo/dir1'],
|
||||
})
|
||||
self._check_requirements(
|
||||
obj.dependencies[1],
|
||||
{
|
||||
'foo/dir1/dir2': ['bar'],
|
||||
})
|
||||
|
||||
def _check_requirements(self, solution, expected):
|
||||
for dependency in solution.dependencies:
|
||||
self.assertEquals(expected.pop(dependency.name), dependency.requirements)
|
||||
self.assertEquals({}, expected)
|
||||
|
||||
def _get_processed(self):
|
||||
items = []
|
||||
try:
|
||||
while True:
|
||||
items.append(self.processed.get_nowait())
|
||||
except Queue.Empty:
|
||||
pass
|
||||
return items
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
logging.basicConfig(
|
||||
level=[logging.ERROR, logging.WARNING, logging.INFO, logging.DEBUG][
|
||||
min(sys.argv.count('-v'), 3)],
|
||||
format='%(asctime).19s %(levelname)s %(filename)s:'
|
||||
'%(lineno)s %(message)s')
|
||||
unittest.main()
|
Loading…
Reference in New Issue