2 # Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file.
6 """Test the commandline module."""
12 sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.dirname(
13 os.path.abspath(__file__)))))
15 from chromite.lib import commandline
16 from chromite.lib import cros_build_lib_unittest
17 from chromite.lib import cros_test_lib
18 from chromite.lib import gs
19 from chromite.lib import partial_mock
21 from chromite.cbuildbot import constants
23 # pylint: disable=W0212
24 class TestShutDownException(cros_test_lib.TestCase):
25 """Test that ShutDownException can be pickled."""
27 def testShutDownException(self):
28 """Test that ShutDownException can be pickled."""
29 ex = commandline._ShutDownException(signal.SIGTERM, 'Received SIGTERM')
30 ex2 = cPickle.loads(cPickle.dumps(ex))
31 self.assertEqual(ex.signal, ex2.signal)
32 self.assertEqual(ex.message, ex2.message)
35 class GSPathTest(cros_test_lib.TestCase):
36 """Test type=gs_path normalization functionality."""
38 GS_REL_PATH = 'bucket/path/to/artifacts'
41 def _ParseCommandLine(argv):
42 parser = commandline.OptionParser()
43 parser.add_option('-g', '--gs-path', type='gs_path',
44 help=('GS path that contains the chrome to deploy.'))
45 return parser.parse_args(argv)
47 def _RunGSPathTestCase(self, raw, parsed):
48 options, _ = self._ParseCommandLine(['--gs-path', raw])
49 self.assertEquals(options.gs_path, parsed)
51 def testNoGSPathCorrectionNeeded(self):
52 """Test case where GS path correction is not needed."""
53 gs_path = '%s/%s' % (gs.BASE_GS_URL, self.GS_REL_PATH)
54 self._RunGSPathTestCase(gs_path, gs_path)
56 def testTrailingSlashRemoval(self):
57 """Test case where GS path ends with /."""
58 gs_path = '%s/%s/' % (gs.BASE_GS_URL, self.GS_REL_PATH)
59 self._RunGSPathTestCase(gs_path, gs_path.rstrip('/'))
61 def testDuplicateSlashesRemoved(self):
62 """Test case where GS path contains many / in a row."""
63 self._RunGSPathTestCase(
64 '%s/a/dir/with//////////slashes' % gs.BASE_GS_URL,
65 '%s/a/dir/with/slashes' % gs.BASE_GS_URL)
67 def testRelativePathsRemoved(self):
68 """Test case where GS path contain /../ logic."""
69 self._RunGSPathTestCase(
70 '%s/a/dir/up/here/.././../now/down/there' % gs.BASE_GS_URL,
71 '%s/a/dir/now/down/there' % gs.BASE_GS_URL)
73 def testCorrectionNeeded(self):
74 """Test case where GS path correction is needed."""
75 self._RunGSPathTestCase(
76 '%s/%s/' % (gs.PRIVATE_BASE_HTTPS_URL, self.GS_REL_PATH),
77 '%s/%s' % (gs.BASE_GS_URL, self.GS_REL_PATH))
79 def testInvalidPath(self):
80 """Path cannot be normalized."""
81 with cros_test_lib.OutputCapturer():
83 SystemExit, self._RunGSPathTestCase, 'http://badhost.com/path', '',
84 check_attrs={'code': 2})
87 class DetermineCheckoutTest(cros_test_lib.MockTempDirTestCase):
88 """Verify functionality for figuring out what checkout we're in."""
91 self.rc_mock = cros_build_lib_unittest.RunCommandMock()
92 self.StartPatcher(self.rc_mock)
93 self.rc_mock.SetDefaultCmdResult()
95 def RunTest(self, dir_struct, cwd, expected_root, expected_type,
97 """Run a test with specific parameters and expected results."""
98 cros_test_lib.CreateOnDiskHierarchy(self.tempdir, dir_struct)
99 cwd = os.path.join(self.tempdir, cwd)
100 checkout_info = commandline.DetermineCheckout(cwd)
101 full_root = expected_root
102 if expected_root is not None:
103 full_root = os.path.join(self.tempdir, expected_root)
104 full_src = expected_src
105 if expected_src is not None:
106 full_src = os.path.join(self.tempdir, expected_src)
108 self.assertEquals(checkout_info.root, full_root)
109 self.assertEquals(checkout_info.type, expected_type)
110 self.assertEquals(checkout_info.chrome_src_dir, full_src)
112 def testGclientRepo(self):
119 self.RunTest(dir_struct, 'a/b/c', 'a/b/c',
120 commandline.CHECKOUT_TYPE_GCLIENT,
122 self.RunTest(dir_struct, 'a/b/c/d', 'a/b/c',
123 commandline.CHECKOUT_TYPE_GCLIENT,
125 self.RunTest(dir_struct, 'a/b', 'a/b',
126 commandline.CHECKOUT_TYPE_REPO,
128 self.RunTest(dir_struct, 'a', 'a',
129 commandline.CHECKOUT_TYPE_GCLIENT,
132 def testGitSubmodule(self):
133 """Recognizes a chrome git submodule checkout."""
134 self.rc_mock.AddCmdResult(
135 partial_mock.In('config'), output=constants.CHROMIUM_GOB_URL)
141 self.RunTest(dir_struct, 'a/b', 'a/b',
142 commandline.CHECKOUT_TYPE_SUBMODULE,
145 def testBadGit1(self):
146 """.git is not a directory."""
147 self.RunTest(['a/.git'], 'a', None,
148 commandline.CHECKOUT_TYPE_UNKNOWN, None)
150 def testBadGit2(self):
151 """'git config' returns nothing."""
152 self.RunTest(['a/.repo/', 'a/b/.git/'], 'a/b', 'a',
153 commandline.CHECKOUT_TYPE_REPO, None)
155 def testBadGit3(self):
156 """'git config' returns error."""
157 self.rc_mock.AddCmdResult(partial_mock.In('config'), returncode=5)
158 self.RunTest(['a/.git/'], 'a', None,
159 commandline.CHECKOUT_TYPE_UNKNOWN, None)
162 class CacheTest(cros_test_lib.MockTempDirTestCase):
163 """Test cache dir specification and finding functionality."""
165 REPO_ROOT = '/fake/repo/root'
166 GCLIENT_ROOT = '/fake/gclient/root'
167 SUBMODULE_ROOT = '/fake/submodule/root'
168 CACHE_DIR = '/fake/cache/dir'
171 self.PatchObject(commandline.ArgumentParser, 'ConfigureCacheDir')
177 cros_test_lib.CreateOnDiskHierarchy(self.tempdir, dir_struct)
178 self.repo_root = os.path.join(self.tempdir, 'repo')
179 self.gclient_root = os.path.join(self.tempdir, 'gclient')
180 self.submodule_root = os.path.join(self.tempdir, 'submodule')
181 self.nocheckout_root = os.path.join(self.tempdir, 'nothing')
183 self.rc_mock = self.StartPatcher(cros_build_lib_unittest.RunCommandMock())
184 self.rc_mock.AddCmdResult(
185 partial_mock.In('config'), output=constants.CHROMIUM_GOB_URL)
186 self.cwd_mock = self.PatchObject(os, 'getcwd')
187 self.parser = commandline.ArgumentParser(caching=True)
189 def _CheckCall(self, expected):
190 # pylint: disable=E1101
191 f = self.parser.ConfigureCacheDir
192 self.assertEquals(1, f.call_count)
193 self.assertTrue(f.call_args[0][0].startswith(expected))
195 def testRepoRoot(self):
196 """Test when we are inside a repo checkout."""
197 self.cwd_mock.return_value = self.repo_root
198 self.parser.parse_args([])
199 self._CheckCall(self.repo_root)
201 def testGclientRoot(self):
202 """Test when we are inside a gclient checkout."""
203 self.cwd_mock.return_value = self.gclient_root
204 self.parser.parse_args([])
205 self._CheckCall(self.gclient_root)
207 def testSubmoduleRoot(self):
208 """Test when we are inside a git submodule Chrome checkout."""
209 self.cwd_mock.return_value = self.submodule_root
210 self.parser.parse_args([])
211 self._CheckCall(self.submodule_root)
213 def testTempdir(self):
214 """Test when we are not in any checkout."""
215 self.cwd_mock.return_value = self.nocheckout_root
216 self.parser.parse_args([])
217 self._CheckCall('/tmp')
219 def testSpecifiedDir(self):
220 """Test when user specifies a cache dir."""
221 self.cwd_mock.return_value = self.repo_root
222 self.parser.parse_args(['--cache-dir', self.CACHE_DIR])
223 self._CheckCall(self.CACHE_DIR)
226 class ParseArgsTest(cros_test_lib.TestCase):
227 """Test parse_args behavior of our custom argument parsing classes."""
229 def _CreateOptionParser(self, cls):
230 """Create a class of optparse.OptionParser with prepared config.
233 cls: Some subclass of optparse.OptionParser.
236 The created OptionParser object.
238 usage = 'usage: some usage'
239 parser = cls(usage=usage)
242 parser.add_option('-x', '--xxx', action='store_true', default=False,
244 parser.add_option('-y', '--yyy', action='store_true', default=False,
246 parser.add_option('-a', '--aaa', type='string', default='Allan',
248 parser.add_option('-b', '--bbb', type='string', default='Barry',
250 parser.add_option('-c', '--ccc', type='string', default='Connor',
255 def _CreateArgumentParser(self, cls):
256 """Create a class of argparse.ArgumentParser with prepared config.
259 cls: Some subclass of argparse.ArgumentParser.
262 The created ArgumentParser object.
264 usage = 'usage: some usage'
265 parser = cls(usage=usage)
268 parser.add_argument('-x', '--xxx', action='store_true', default=False,
270 parser.add_argument('-y', '--yyy', action='store_true', default=False,
272 parser.add_argument('-a', '--aaa', type=str, default='Allan',
274 parser.add_argument('-b', '--bbb', type=str, default='Barry',
276 parser.add_argument('-c', '--ccc', type=str, default='Connor',
278 parser.add_argument('args', type=str, nargs='*', help='args')
282 def _TestParser(self, parser):
283 """Test the given parser with a prepared argv."""
284 argv = ['-x', '--bbb', 'Bobby', '-c', 'Connor', 'foobar']
286 parsed = parser.parse_args(argv)
288 if isinstance(parser, commandline.OptionParser):
289 # optparse returns options and args separately.
290 options, args = parsed
291 self.assertEquals(['foobar'], args)
293 # argparse returns just options. Options configured above to have the
294 # args stored at option "args".
296 self.assertEquals(['foobar'], parsed.args)
298 self.assertTrue(options.xxx)
299 self.assertFalse(options.yyy)
301 self.assertEquals('Allan', options.aaa)
302 self.assertEquals('Bobby', options.bbb)
303 self.assertEquals('Connor', options.ccc)
305 self.assertRaises(AttributeError, getattr, options, 'xyz')
307 # Now try altering option values.
308 options.aaa = 'Arick'
309 self.assertEquals('Arick', options.aaa)
311 # Now freeze the options and try altering again.
313 self.assertRaises(commandline.cros_build_lib.AttributeFrozenError,
314 setattr, options, 'aaa', 'Arnold')
315 self.assertEquals('Arick', options.aaa)
317 def testOptionParser(self):
318 self._TestParser(self._CreateOptionParser(commandline.OptionParser))
320 def testFilterParser(self):
321 self._TestParser(self._CreateOptionParser(commandline.FilteringParser))
323 def testArgumentParser(self):
324 self._TestParser(self._CreateArgumentParser(commandline.ArgumentParser))
327 class ScriptWrapperMainTest(cros_test_lib.MockTestCase):
328 """Test the behavior of the ScriptWrapperMain function."""
331 self.PatchObject(sys, 'exit')
333 # pylint: disable=W0613
335 def _DummyChrootTarget(args):
336 raise commandline.ChrootRequiredError()
338 DUMMY_CHROOT_TARGET_ARGS = ['cmd', 'arg1', 'arg2']
341 def _DummyChrootTargetArgs(args):
342 args = ScriptWrapperMainTest.DUMMY_CHROOT_TARGET_ARGS
343 raise commandline.ChrootRequiredError(args)
345 def testRestartInChroot(self):
346 rc = self.StartPatcher(cros_build_lib_unittest.RunCommandMock())
347 rc.SetDefaultCmdResult()
349 ret = lambda x: ScriptWrapperMainTest._DummyChrootTarget
350 commandline.ScriptWrapperMain(ret)
351 rc.assertCommandContains(enter_chroot=True)
352 rc.assertCommandContains(self.DUMMY_CHROOT_TARGET_ARGS, expected=False)
354 def testRestartInChrootArgs(self):
355 rc = self.StartPatcher(cros_build_lib_unittest.RunCommandMock())
356 rc.SetDefaultCmdResult()
358 ret = lambda x: ScriptWrapperMainTest._DummyChrootTargetArgs
359 commandline.ScriptWrapperMain(ret)
360 rc.assertCommandContains(self.DUMMY_CHROOT_TARGET_ARGS, enter_chroot=True)
363 if __name__ == '__main__':