blob: b7035bc96745cd21505ff19cd4caeecdd7ee0e55 [file] [log] [blame]
Ryan Cuiafd6c5c2012-07-30 17:48:22 -07001#!/usr/bin/python
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.
5
6
Ryan Cuiafd6c5c2012-07-30 17:48:22 -07007import os
8import sys
David James88e6f032013-03-02 08:13:20 -08009import time
Ryan Cuiafd6c5c2012-07-30 17:48:22 -070010
11sys.path.insert(0, os.path.join(os.path.dirname(os.path.realpath(__file__)),
12 '..', '..'))
Ryan Cuief91e702013-02-04 12:06:36 -080013
Ryan Cui686ec052013-02-12 16:39:41 -080014from chromite.cros.commands import cros_chrome_sdk_unittest
Ryan Cuief91e702013-02-04 12:06:36 -080015from chromite.lib import chrome_util
Ryan Cuiafd6c5c2012-07-30 17:48:22 -070016from chromite.lib import cros_build_lib
17from chromite.lib import cros_test_lib
Ryan Cui686ec052013-02-12 16:39:41 -080018from chromite.lib import osutils
Ryan Cuiafd6c5c2012-07-30 17:48:22 -070019from chromite.lib import partial_mock
20from chromite.lib import remote_access_unittest
Ryan Cuicbd9bb62013-04-30 11:17:02 -070021from chromite.lib import stats
22from chromite.lib import stats_unittest
23
Ryan Cuiafd6c5c2012-07-30 17:48:22 -070024from chromite.scripts import deploy_chrome
25
Ryan Cuief91e702013-02-04 12:06:36 -080026
Brian Harringe7524372012-12-23 02:02:56 -080027# TODO(build): Finish test wrapper (http://crosbug.com/37517).
28# Until then, this has to be after the chromite imports.
29import mock
30
Ryan Cuiafd6c5c2012-07-30 17:48:22 -070031
32# pylint: disable=W0212
33
34_REGULAR_TO = ('--to', 'monkey')
35_GS_PATH = 'gs://foon'
36
37
38def _ParseCommandLine(argv):
39 return deploy_chrome._ParseCommandLine(['--log-level', 'debug'] + argv)
40
41
42class InterfaceTest(cros_test_lib.OutputTestCase):
43 """Tests the commandline interface of the script."""
44
Ryan Cui686ec052013-02-12 16:39:41 -080045 BOARD = 'lumpy'
46
Ryan Cuiafd6c5c2012-07-30 17:48:22 -070047 def testGsLocalPathUnSpecified(self):
48 """Test no chrome path specified."""
49 with self.OutputCapturer():
50 self.assertRaises2(SystemExit, _ParseCommandLine, list(_REGULAR_TO),
51 check_attrs={'code': 2})
52
53 def testGsPathSpecified(self):
54 """Test case of GS path specified."""
55 argv = list(_REGULAR_TO) + ['--gs-path', _GS_PATH]
56 _ParseCommandLine(argv)
57
58 def testLocalPathSpecified(self):
59 """Test case of local path specified."""
Ryan Cuia56a71e2012-10-18 18:40:35 -070060 argv = list(_REGULAR_TO) + ['--local-pkg-path', '/path/to/chrome']
Ryan Cuiafd6c5c2012-07-30 17:48:22 -070061 _ParseCommandLine(argv)
62
63 def testNoTarget(self):
64 """Test no target specified."""
65 argv = ['--gs-path', _GS_PATH]
Ryan Cuief91e702013-02-04 12:06:36 -080066 self.assertParseError(argv)
67
68 def assertParseError(self, argv):
Ryan Cuiafd6c5c2012-07-30 17:48:22 -070069 with self.OutputCapturer():
70 self.assertRaises2(SystemExit, _ParseCommandLine, argv,
71 check_attrs={'code': 2})
72
Ryan Cuief91e702013-02-04 12:06:36 -080073 def testStagingFlagsNoStrict(self):
74 """Errors out when --staging-flags is set without --strict."""
75 argv = ['--staging-only', '--build-dir=/path/to/nowhere',
Ryan Cui686ec052013-02-12 16:39:41 -080076 '--board=%s' % self.BOARD, '--staging-flags=highdpi']
Ryan Cuief91e702013-02-04 12:06:36 -080077 self.assertParseError(argv)
78
79 def testStrictNoBuildDir(self):
80 """Errors out when --strict is set without --build-dir."""
81 argv = ['--staging-only', '--strict', '--gs-path', _GS_PATH]
82 self.assertParseError(argv)
83
Ryan Cui686ec052013-02-12 16:39:41 -080084 def testNoBoardBuildDir(self):
85 argv = ['--staging-only', '--build-dir=/path/to/nowhere']
86 self.assertParseError(argv)
87
Thiago Goncales12793312013-05-23 11:26:17 -070088 def testMountOptionSetsTargetDir(self):
89 argv = list(_REGULAR_TO) + ['--gs-path', _GS_PATH, '--mount']
90 options, _ = _ParseCommandLine(argv)
91 self.assertIsNot(options.target_dir, None)
92
93 def testMountOptionSetsMountDir(self):
94 argv = list(_REGULAR_TO) + ['--gs-path', _GS_PATH, '--mount']
95 options, _ = _ParseCommandLine(argv)
96 self.assertIsNot(options.mount_dir, None)
97
98 def testMountOptionDoesNotOverrideTargetDir(self):
99 argv = list(_REGULAR_TO) + ['--gs-path', _GS_PATH, '--mount',
100 '--target-dir', '/foo/bar/cow']
101 options, _ = _ParseCommandLine(argv)
102 self.assertEqual(options.target_dir, '/foo/bar/cow')
103
104 def testMountOptionDoesNotOverrideMountDir(self):
105 argv = list(_REGULAR_TO) + ['--gs-path', _GS_PATH, '--mount',
106 '--mount-dir', '/foo/bar/cow']
107 options, _ = _ParseCommandLine(argv)
108 self.assertEqual(options.mount_dir, '/foo/bar/cow')
109
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700110
111class DeployChromeMock(partial_mock.PartialMock):
112
113 TARGET = 'chromite.scripts.deploy_chrome.DeployChrome'
David James88e6f032013-03-02 08:13:20 -0800114 ATTRS = ('_KillProcsIfNeeded', '_DisableRootfsVerification')
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700115
David James88e6f032013-03-02 08:13:20 -0800116 def __init__(self):
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700117 partial_mock.PartialMock.__init__(self)
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700118 # Target starts off as having rootfs verification enabled.
Ryan Cuie18f24f2012-12-03 18:39:55 -0800119 self.rsh_mock = remote_access_unittest.RemoteShMock()
David James88e6f032013-03-02 08:13:20 -0800120 self.rsh_mock.SetDefaultCmdResult(0)
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700121 self.MockMountCmd(1)
Pawel Osciak577773a2013-03-05 10:52:12 -0800122 self.rsh_mock.AddCmdResult(
123 deploy_chrome.LSOF_COMMAND % (deploy_chrome._CHROME_DIR,), 1)
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700124
125 def MockMountCmd(self, returnvalue):
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700126 self.rsh_mock.AddCmdResult(deploy_chrome.MOUNT_RW_COMMAND,
David James88e6f032013-03-02 08:13:20 -0800127 returnvalue)
128
129 def _DisableRootfsVerification(self, inst):
130 with mock.patch.object(time, 'sleep'):
131 self.backup['_DisableRootfsVerification'](inst)
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700132
Ryan Cui4d6fca92012-12-13 16:41:56 -0800133 def PreStart(self):
134 self.rsh_mock.start()
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700135
Ryan Cui4d6fca92012-12-13 16:41:56 -0800136 def PreStop(self):
137 self.rsh_mock.stop()
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700138
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700139 def _KillProcsIfNeeded(self, _inst):
140 # Fully stub out for now.
141 pass
142
143
Ryan Cuicbd9bb62013-04-30 11:17:02 -0700144class MainTest(cros_test_lib.MockLoggingTestCase):
145
146 def setUp(self):
147 self.PatchObject(deploy_chrome.DeployChrome, 'Perform', autospec=True)
148 self.stats_module_mock = stats_unittest.StatsModuleMock()
149 self.StartPatcher(self.stats_module_mock)
150
151 def testStatsUpload(self, call_count=1):
152 """The stats upload path."""
153 deploy_chrome.main(['--board=lumpy', '--staging-only',
154 '--build-dir=/tmp/abc'])
155 self.assertEquals(stats.StatsUploader._Upload.call_count, call_count)
156
157 def testStatsUploadError(self):
158 """Don't upload stats if we fail to create it."""
159 self.stats_module_mock.stats_mock.init_exception = True
160 with cros_test_lib.LoggingCapturer():
161 self.testStatsUpload(call_count=0)
162
163
Ryan Cuief91e702013-02-04 12:06:36 -0800164class DeployTest(cros_test_lib.MockTempDirTestCase):
165 def _GetDeployChrome(self, args):
166 options, _ = _ParseCommandLine(args)
Ryan Cuia56a71e2012-10-18 18:40:35 -0700167 return deploy_chrome.DeployChrome(
168 options, self.tempdir, os.path.join(self.tempdir, 'staging'))
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700169
170 def setUp(self):
Ryan Cuif1416f32013-01-22 18:43:41 -0800171 self.deploy_mock = self.StartPatcher(DeployChromeMock())
Ryan Cuief91e702013-02-04 12:06:36 -0800172 self.deploy = self._GetDeployChrome(
David James88e6f032013-03-02 08:13:20 -0800173 list(_REGULAR_TO) + ['--gs-path', _GS_PATH, '--force'])
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700174
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700175
David James88e6f032013-03-02 08:13:20 -0800176class TestDisableRootfsVerification(DeployTest):
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700177 """Testing disabling of rootfs verification and RO mode."""
178
David James88e6f032013-03-02 08:13:20 -0800179 def testDisableRootfsVerificationSuccess(self):
180 """Test the working case, disabling rootfs verification."""
181 self.deploy_mock.MockMountCmd(0)
182 self.deploy._DisableRootfsVerification()
183 self.assertFalse(self.deploy._rootfs_is_still_readonly.is_set())
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700184
185 def testDisableRootfsVerificationFailure(self):
186 """Test failure to disable rootfs verification."""
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700187 self.assertRaises(cros_build_lib.RunCommandError,
David James88e6f032013-03-02 08:13:20 -0800188 self.deploy._DisableRootfsVerification)
189 self.assertFalse(self.deploy._rootfs_is_still_readonly.is_set())
190
191
192class TestMount(DeployTest):
193 """Testing mount success and failure."""
194
195 def testSuccess(self):
196 """Test case where we are able to mount as writable."""
197 self.assertFalse(self.deploy._rootfs_is_still_readonly.is_set())
198 self.deploy_mock.MockMountCmd(0)
199 self.deploy._MountRootfsAsWritable()
200 self.assertFalse(self.deploy._rootfs_is_still_readonly.is_set())
201
202 def testMountError(self):
203 """Test that mount failure doesn't raise an exception by default."""
204 self.assertFalse(self.deploy._rootfs_is_still_readonly.is_set())
205 self.deploy._MountRootfsAsWritable()
206 self.assertTrue(self.deploy._rootfs_is_still_readonly.is_set())
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700207
208 def testMountRwFailure(self):
David James88e6f032013-03-02 08:13:20 -0800209 """Test that mount failure raises an exception if error_code_ok=False."""
210 self.assertRaises(cros_build_lib.RunCommandError,
211 self.deploy._MountRootfsAsWritable, error_code_ok=False)
212 self.assertFalse(self.deploy._rootfs_is_still_readonly.is_set())
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700213
214
Ryan Cuief91e702013-02-04 12:06:36 -0800215class TestUiJobStarted(DeployTest):
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700216 """Test detection of a running 'ui' job."""
217
Ryan Cuif2d1a582013-02-19 14:08:13 -0800218 def MockStatusUiCmd(self, **kwargs):
219 self.deploy_mock.rsh_mock.AddCmdResult('status ui', **kwargs)
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700220
221 def testUiJobStartedFalse(self):
222 """Correct results with a stopped job."""
Ryan Cuif2d1a582013-02-19 14:08:13 -0800223 self.MockStatusUiCmd(output='ui stop/waiting')
224 self.assertFalse(self.deploy._CheckUiJobStarted())
225
226 def testNoUiJob(self):
227 """Correct results when the job doesn't exist."""
228 self.MockStatusUiCmd(error='start: Unknown job: ui', returncode=1)
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700229 self.assertFalse(self.deploy._CheckUiJobStarted())
230
231 def testCheckRootfsWriteableTrue(self):
232 """Correct results with a running job."""
Ryan Cuif2d1a582013-02-19 14:08:13 -0800233 self.MockStatusUiCmd(output='ui start/running, process 297')
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700234 self.assertTrue(self.deploy._CheckUiJobStarted())
235
236
Ryan Cuief91e702013-02-04 12:06:36 -0800237class StagingTest(cros_test_lib.MockTempDirTestCase):
238 """Test user-mode and ebuild-mode staging functionality."""
239
240 def setUp(self):
Ryan Cuief91e702013-02-04 12:06:36 -0800241 self.staging_dir = os.path.join(self.tempdir, 'staging')
242 self.build_dir = os.path.join(self.tempdir, 'build_dir')
Ryan Cui686ec052013-02-12 16:39:41 -0800243 self.common_flags = ['--build-dir', self.build_dir,
244 '--board=lumpy', '--staging-only', '--cache-dir',
245 self.tempdir]
Ryan Cuia0215a72013-02-14 16:20:45 -0800246 self.sdk_mock = self.StartPatcher(cros_chrome_sdk_unittest.SDKFetcherMock())
Ryan Cui686ec052013-02-12 16:39:41 -0800247 self.PatchObject(
248 osutils, 'SourceEnvironment', autospec=True,
249 return_value={'STRIP': 'x86_64-cros-linux-gnu-strip'})
Ryan Cuief91e702013-02-04 12:06:36 -0800250
David Jamesa6e08892013-03-01 13:34:11 -0800251 def testSingleFileDeployFailure(self):
252 """Default staging enforces that mandatory files are copied"""
Ryan Cuief91e702013-02-04 12:06:36 -0800253 options, _ = _ParseCommandLine(self.common_flags)
David Jamesa6e08892013-03-01 13:34:11 -0800254 osutils.Touch(os.path.join(self.build_dir, 'chrome'), makedirs=True)
255 self.assertRaises(
256 chrome_util.MissingPathError, deploy_chrome._PrepareStagingDir,
Ryan Cuief91e702013-02-04 12:06:36 -0800257 options, self.tempdir, self.staging_dir)
258
David Jamesa6e08892013-03-01 13:34:11 -0800259 def testSloppyDeployFailure(self):
260 """Sloppy staging enforces that at least one file is copied."""
261 options, _ = _ParseCommandLine(self.common_flags + ['--sloppy'])
262 self.assertRaises(
263 chrome_util.MissingPathError, deploy_chrome._PrepareStagingDir,
264 options, self.tempdir, self.staging_dir)
265
266 def testSloppyDeploySuccess(self):
267 """Sloppy staging - stage one file."""
268 options, _ = _ParseCommandLine(self.common_flags + ['--sloppy'])
269 osutils.Touch(os.path.join(self.build_dir, 'chrome'), makedirs=True)
270 deploy_chrome._PrepareStagingDir(options, self.tempdir, self.staging_dir)
271
Ryan Cuief91e702013-02-04 12:06:36 -0800272 def testEmptyDeployStrict(self):
David Jamesa6e08892013-03-01 13:34:11 -0800273 """Strict staging fails when there are no files."""
Ryan Cuief91e702013-02-04 12:06:36 -0800274 options, _ = _ParseCommandLine(
275 self.common_flags + ['--gyp-defines', 'chromeos=1', '--strict'])
Ryan Cui686ec052013-02-12 16:39:41 -0800276 chrome_util.MissingPathError(deploy_chrome._PrepareStagingDir,
277 options, self.tempdir, self.staging_dir)
278
Ryan Cuief91e702013-02-04 12:06:36 -0800279 self.assertRaises(
280 chrome_util.MissingPathError, deploy_chrome._PrepareStagingDir,
281 options, self.tempdir, self.staging_dir)
282
283
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700284if __name__ == '__main__':
285 cros_test_lib.main()