Chromium Code Reviews| Index: tests/gclient_test.py |
| diff --git a/tests/gclient_test.py b/tests/gclient_test.py |
| new file mode 100755 |
| index 0000000000000000000000000000000000000000..065d718d613bd7c7cd4dd3cb6be116a624fdf411 |
| --- /dev/null |
| +++ b/tests/gclient_test.py |
| @@ -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 |
|
M-A Ruel
2011/08/30 15:07:34
Added a comment to explain what this function chec
|
| + # 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() |