blob: f5eb6598218e98c3d72b0547d401c048dffbdbbb [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
Steve Funge984a532013-11-25 17:09:25 -08006"""Unit tests for the deploy_chrome script."""
Ryan Cuiafd6c5c2012-07-30 17:48:22 -07007
Mike Frysinger1d4752b2014-11-08 04:00:18 -05008# pylint: disable=bad-whitespace
9
Mike Frysinger383367e2014-09-16 15:06:17 -040010from __future__ import print_function
11
Ryan Cuiafd6c5c2012-07-30 17:48:22 -070012import os
13import sys
David James88e6f032013-03-02 08:13:20 -080014import time
Ryan Cuiafd6c5c2012-07-30 17:48:22 -070015
16sys.path.insert(0, os.path.join(os.path.dirname(os.path.realpath(__file__)),
17 '..', '..'))
Ryan Cuief91e702013-02-04 12:06:36 -080018
Ryan Cui686ec052013-02-12 16:39:41 -080019from chromite.cros.commands import cros_chrome_sdk_unittest
Ryan Cuief91e702013-02-04 12:06:36 -080020from chromite.lib import chrome_util
Ryan Cuiafd6c5c2012-07-30 17:48:22 -070021from chromite.lib import cros_build_lib
22from chromite.lib import cros_test_lib
Ryan Cui686ec052013-02-12 16:39:41 -080023from chromite.lib import osutils
Ryan Cuiafd6c5c2012-07-30 17:48:22 -070024from chromite.lib import partial_mock
25from chromite.lib import remote_access_unittest
Ryan Cuicbd9bb62013-04-30 11:17:02 -070026from chromite.lib import stats
27from chromite.lib import stats_unittest
28
Ryan Cuiafd6c5c2012-07-30 17:48:22 -070029from chromite.scripts import deploy_chrome
30
Ryan Cuief91e702013-02-04 12:06:36 -080031
Brian Harringe7524372012-12-23 02:02:56 -080032# TODO(build): Finish test wrapper (http://crosbug.com/37517).
33# Until then, this has to be after the chromite imports.
34import mock
35
Ryan Cuiafd6c5c2012-07-30 17:48:22 -070036
37# pylint: disable=W0212
38
39_REGULAR_TO = ('--to', 'monkey')
40_GS_PATH = 'gs://foon'
41
42
43def _ParseCommandLine(argv):
44 return deploy_chrome._ParseCommandLine(['--log-level', 'debug'] + argv)
45
46
47class InterfaceTest(cros_test_lib.OutputTestCase):
48 """Tests the commandline interface of the script."""
49
Ryan Cui686ec052013-02-12 16:39:41 -080050 BOARD = 'lumpy'
51
Ryan Cuiafd6c5c2012-07-30 17:48:22 -070052 def testGsLocalPathUnSpecified(self):
53 """Test no chrome path specified."""
54 with self.OutputCapturer():
55 self.assertRaises2(SystemExit, _ParseCommandLine, list(_REGULAR_TO),
56 check_attrs={'code': 2})
57
58 def testGsPathSpecified(self):
59 """Test case of GS path specified."""
60 argv = list(_REGULAR_TO) + ['--gs-path', _GS_PATH]
61 _ParseCommandLine(argv)
62
63 def testLocalPathSpecified(self):
64 """Test case of local path specified."""
Ryan Cuia56a71e2012-10-18 18:40:35 -070065 argv = list(_REGULAR_TO) + ['--local-pkg-path', '/path/to/chrome']
Ryan Cuiafd6c5c2012-07-30 17:48:22 -070066 _ParseCommandLine(argv)
67
68 def testNoTarget(self):
69 """Test no target specified."""
70 argv = ['--gs-path', _GS_PATH]
Ryan Cuief91e702013-02-04 12:06:36 -080071 self.assertParseError(argv)
72
73 def assertParseError(self, argv):
Ryan Cuiafd6c5c2012-07-30 17:48:22 -070074 with self.OutputCapturer():
75 self.assertRaises2(SystemExit, _ParseCommandLine, argv,
76 check_attrs={'code': 2})
77
Ryan Cuief91e702013-02-04 12:06:36 -080078 def testStagingFlagsNoStrict(self):
79 """Errors out when --staging-flags is set without --strict."""
80 argv = ['--staging-only', '--build-dir=/path/to/nowhere',
Ryan Cui686ec052013-02-12 16:39:41 -080081 '--board=%s' % self.BOARD, '--staging-flags=highdpi']
Ryan Cuief91e702013-02-04 12:06:36 -080082 self.assertParseError(argv)
83
84 def testStrictNoBuildDir(self):
85 """Errors out when --strict is set without --build-dir."""
86 argv = ['--staging-only', '--strict', '--gs-path', _GS_PATH]
87 self.assertParseError(argv)
88
Ryan Cui686ec052013-02-12 16:39:41 -080089 def testNoBoardBuildDir(self):
90 argv = ['--staging-only', '--build-dir=/path/to/nowhere']
91 self.assertParseError(argv)
92
Thiago Goncales12793312013-05-23 11:26:17 -070093 def testMountOptionSetsTargetDir(self):
94 argv = list(_REGULAR_TO) + ['--gs-path', _GS_PATH, '--mount']
95 options, _ = _ParseCommandLine(argv)
96 self.assertIsNot(options.target_dir, None)
97
98 def testMountOptionSetsMountDir(self):
99 argv = list(_REGULAR_TO) + ['--gs-path', _GS_PATH, '--mount']
100 options, _ = _ParseCommandLine(argv)
101 self.assertIsNot(options.mount_dir, None)
102
103 def testMountOptionDoesNotOverrideTargetDir(self):
104 argv = list(_REGULAR_TO) + ['--gs-path', _GS_PATH, '--mount',
105 '--target-dir', '/foo/bar/cow']
106 options, _ = _ParseCommandLine(argv)
107 self.assertEqual(options.target_dir, '/foo/bar/cow')
108
109 def testMountOptionDoesNotOverrideMountDir(self):
110 argv = list(_REGULAR_TO) + ['--gs-path', _GS_PATH, '--mount',
111 '--mount-dir', '/foo/bar/cow']
112 options, _ = _ParseCommandLine(argv)
113 self.assertEqual(options.mount_dir, '/foo/bar/cow')
114
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700115
116class DeployChromeMock(partial_mock.PartialMock):
Steve Funge984a532013-11-25 17:09:25 -0800117 """Deploy Chrome Mock Class."""
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700118
119 TARGET = 'chromite.scripts.deploy_chrome.DeployChrome'
David James88e6f032013-03-02 08:13:20 -0800120 ATTRS = ('_KillProcsIfNeeded', '_DisableRootfsVerification')
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700121
David James88e6f032013-03-02 08:13:20 -0800122 def __init__(self):
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700123 partial_mock.PartialMock.__init__(self)
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700124 # Target starts off as having rootfs verification enabled.
Ryan Cuie18f24f2012-12-03 18:39:55 -0800125 self.rsh_mock = remote_access_unittest.RemoteShMock()
David James88e6f032013-03-02 08:13:20 -0800126 self.rsh_mock.SetDefaultCmdResult(0)
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700127 self.MockMountCmd(1)
Pawel Osciak577773a2013-03-05 10:52:12 -0800128 self.rsh_mock.AddCmdResult(
129 deploy_chrome.LSOF_COMMAND % (deploy_chrome._CHROME_DIR,), 1)
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700130
131 def MockMountCmd(self, returnvalue):
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700132 self.rsh_mock.AddCmdResult(deploy_chrome.MOUNT_RW_COMMAND,
David James88e6f032013-03-02 08:13:20 -0800133 returnvalue)
134
135 def _DisableRootfsVerification(self, inst):
136 with mock.patch.object(time, 'sleep'):
137 self.backup['_DisableRootfsVerification'](inst)
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700138
Ryan Cui4d6fca92012-12-13 16:41:56 -0800139 def PreStart(self):
140 self.rsh_mock.start()
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700141
Ryan Cui4d6fca92012-12-13 16:41:56 -0800142 def PreStop(self):
143 self.rsh_mock.stop()
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700144
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700145 def _KillProcsIfNeeded(self, _inst):
146 # Fully stub out for now.
147 pass
148
149
Ryan Cuicbd9bb62013-04-30 11:17:02 -0700150class MainTest(cros_test_lib.MockLoggingTestCase):
Steve Funge984a532013-11-25 17:09:25 -0800151 """Main tests."""
Ryan Cuicbd9bb62013-04-30 11:17:02 -0700152
153 def setUp(self):
154 self.PatchObject(deploy_chrome.DeployChrome, 'Perform', autospec=True)
155 self.stats_module_mock = stats_unittest.StatsModuleMock()
156 self.StartPatcher(self.stats_module_mock)
157
158 def testStatsUpload(self, call_count=1):
159 """The stats upload path."""
160 deploy_chrome.main(['--board=lumpy', '--staging-only',
161 '--build-dir=/tmp/abc'])
162 self.assertEquals(stats.StatsUploader._Upload.call_count, call_count)
163
164 def testStatsUploadError(self):
165 """Don't upload stats if we fail to create it."""
166 self.stats_module_mock.stats_mock.init_exception = True
167 with cros_test_lib.LoggingCapturer():
168 self.testStatsUpload(call_count=0)
169
170
Ryan Cuief91e702013-02-04 12:06:36 -0800171class DeployTest(cros_test_lib.MockTempDirTestCase):
Steve Funge984a532013-11-25 17:09:25 -0800172 """Setup a deploy object with a GS-path for use in tests."""
173
Ryan Cuief91e702013-02-04 12:06:36 -0800174 def _GetDeployChrome(self, args):
175 options, _ = _ParseCommandLine(args)
Ryan Cuia56a71e2012-10-18 18:40:35 -0700176 return deploy_chrome.DeployChrome(
177 options, self.tempdir, os.path.join(self.tempdir, 'staging'))
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700178
179 def setUp(self):
Ryan Cuif1416f32013-01-22 18:43:41 -0800180 self.deploy_mock = self.StartPatcher(DeployChromeMock())
Ryan Cuief91e702013-02-04 12:06:36 -0800181 self.deploy = self._GetDeployChrome(
David James88e6f032013-03-02 08:13:20 -0800182 list(_REGULAR_TO) + ['--gs-path', _GS_PATH, '--force'])
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700183
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700184
David James88e6f032013-03-02 08:13:20 -0800185class TestDisableRootfsVerification(DeployTest):
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700186 """Testing disabling of rootfs verification and RO mode."""
187
David James88e6f032013-03-02 08:13:20 -0800188 def testDisableRootfsVerificationSuccess(self):
189 """Test the working case, disabling rootfs verification."""
190 self.deploy_mock.MockMountCmd(0)
191 self.deploy._DisableRootfsVerification()
192 self.assertFalse(self.deploy._rootfs_is_still_readonly.is_set())
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700193
194 def testDisableRootfsVerificationFailure(self):
195 """Test failure to disable rootfs verification."""
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700196 self.assertRaises(cros_build_lib.RunCommandError,
David James88e6f032013-03-02 08:13:20 -0800197 self.deploy._DisableRootfsVerification)
198 self.assertFalse(self.deploy._rootfs_is_still_readonly.is_set())
199
200
201class TestMount(DeployTest):
202 """Testing mount success and failure."""
203
204 def testSuccess(self):
205 """Test case where we are able to mount as writable."""
206 self.assertFalse(self.deploy._rootfs_is_still_readonly.is_set())
207 self.deploy_mock.MockMountCmd(0)
208 self.deploy._MountRootfsAsWritable()
209 self.assertFalse(self.deploy._rootfs_is_still_readonly.is_set())
210
211 def testMountError(self):
212 """Test that mount failure doesn't raise an exception by default."""
213 self.assertFalse(self.deploy._rootfs_is_still_readonly.is_set())
214 self.deploy._MountRootfsAsWritable()
215 self.assertTrue(self.deploy._rootfs_is_still_readonly.is_set())
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700216
217 def testMountRwFailure(self):
David James88e6f032013-03-02 08:13:20 -0800218 """Test that mount failure raises an exception if error_code_ok=False."""
219 self.assertRaises(cros_build_lib.RunCommandError,
220 self.deploy._MountRootfsAsWritable, error_code_ok=False)
221 self.assertFalse(self.deploy._rootfs_is_still_readonly.is_set())
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700222
223
Ryan Cuief91e702013-02-04 12:06:36 -0800224class TestUiJobStarted(DeployTest):
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700225 """Test detection of a running 'ui' job."""
226
Ryan Cuif2d1a582013-02-19 14:08:13 -0800227 def MockStatusUiCmd(self, **kwargs):
228 self.deploy_mock.rsh_mock.AddCmdResult('status ui', **kwargs)
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700229
230 def testUiJobStartedFalse(self):
231 """Correct results with a stopped job."""
Ryan Cuif2d1a582013-02-19 14:08:13 -0800232 self.MockStatusUiCmd(output='ui stop/waiting')
233 self.assertFalse(self.deploy._CheckUiJobStarted())
234
235 def testNoUiJob(self):
236 """Correct results when the job doesn't exist."""
237 self.MockStatusUiCmd(error='start: Unknown job: ui', returncode=1)
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700238 self.assertFalse(self.deploy._CheckUiJobStarted())
239
240 def testCheckRootfsWriteableTrue(self):
241 """Correct results with a running job."""
Ryan Cuif2d1a582013-02-19 14:08:13 -0800242 self.MockStatusUiCmd(output='ui start/running, process 297')
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700243 self.assertTrue(self.deploy._CheckUiJobStarted())
244
245
Ryan Cuief91e702013-02-04 12:06:36 -0800246class StagingTest(cros_test_lib.MockTempDirTestCase):
247 """Test user-mode and ebuild-mode staging functionality."""
248
249 def setUp(self):
Ryan Cuief91e702013-02-04 12:06:36 -0800250 self.staging_dir = os.path.join(self.tempdir, 'staging')
251 self.build_dir = os.path.join(self.tempdir, 'build_dir')
Ryan Cui686ec052013-02-12 16:39:41 -0800252 self.common_flags = ['--build-dir', self.build_dir,
253 '--board=lumpy', '--staging-only', '--cache-dir',
254 self.tempdir]
Ryan Cuia0215a72013-02-14 16:20:45 -0800255 self.sdk_mock = self.StartPatcher(cros_chrome_sdk_unittest.SDKFetcherMock())
Ryan Cui686ec052013-02-12 16:39:41 -0800256 self.PatchObject(
257 osutils, 'SourceEnvironment', autospec=True,
258 return_value={'STRIP': 'x86_64-cros-linux-gnu-strip'})
Ryan Cuief91e702013-02-04 12:06:36 -0800259
David Jamesa6e08892013-03-01 13:34:11 -0800260 def testSingleFileDeployFailure(self):
261 """Default staging enforces that mandatory files are copied"""
Ryan Cuief91e702013-02-04 12:06:36 -0800262 options, _ = _ParseCommandLine(self.common_flags)
David Jamesa6e08892013-03-01 13:34:11 -0800263 osutils.Touch(os.path.join(self.build_dir, 'chrome'), makedirs=True)
264 self.assertRaises(
265 chrome_util.MissingPathError, deploy_chrome._PrepareStagingDir,
Daniel Eratc89829c2014-05-12 17:24:21 -0700266 options, self.tempdir, self.staging_dir, chrome_util._COPY_PATHS_CHROME)
Ryan Cuief91e702013-02-04 12:06:36 -0800267
David Jamesa6e08892013-03-01 13:34:11 -0800268 def testSloppyDeployFailure(self):
269 """Sloppy staging enforces that at least one file is copied."""
270 options, _ = _ParseCommandLine(self.common_flags + ['--sloppy'])
271 self.assertRaises(
272 chrome_util.MissingPathError, deploy_chrome._PrepareStagingDir,
Daniel Eratc89829c2014-05-12 17:24:21 -0700273 options, self.tempdir, self.staging_dir, chrome_util._COPY_PATHS_CHROME)
David Jamesa6e08892013-03-01 13:34:11 -0800274
275 def testSloppyDeploySuccess(self):
276 """Sloppy staging - stage one file."""
277 options, _ = _ParseCommandLine(self.common_flags + ['--sloppy'])
278 osutils.Touch(os.path.join(self.build_dir, 'chrome'), makedirs=True)
Steve Funge984a532013-11-25 17:09:25 -0800279 deploy_chrome._PrepareStagingDir(options, self.tempdir, self.staging_dir,
Daniel Eratc89829c2014-05-12 17:24:21 -0700280 chrome_util._COPY_PATHS_CHROME)
David Jamesa6e08892013-03-01 13:34:11 -0800281
Ryan Cuief91e702013-02-04 12:06:36 -0800282 def testEmptyDeployStrict(self):
David Jamesa6e08892013-03-01 13:34:11 -0800283 """Strict staging fails when there are no files."""
Ryan Cuief91e702013-02-04 12:06:36 -0800284 options, _ = _ParseCommandLine(
285 self.common_flags + ['--gyp-defines', 'chromeos=1', '--strict'])
Ryan Cui686ec052013-02-12 16:39:41 -0800286
Ryan Cuief91e702013-02-04 12:06:36 -0800287 self.assertRaises(
288 chrome_util.MissingPathError, deploy_chrome._PrepareStagingDir,
Daniel Eratc89829c2014-05-12 17:24:21 -0700289 options, self.tempdir, self.staging_dir, chrome_util._COPY_PATHS_CHROME)
Steve Funge984a532013-11-25 17:09:25 -0800290
291
292class DeployTestBuildDir(cros_test_lib.MockTempDirTestCase):
Daniel Erat1ae46382014-08-14 10:23:39 -0700293 """Set up a deploy object with a build-dir for use in deployment type tests"""
Steve Funge984a532013-11-25 17:09:25 -0800294
295 def _GetDeployChrome(self, args):
296 options, _ = _ParseCommandLine(args)
297 return deploy_chrome.DeployChrome(
298 options, self.tempdir, os.path.join(self.tempdir, 'staging'))
299
300 def setUp(self):
301 self.staging_dir = os.path.join(self.tempdir, 'staging')
302 self.build_dir = os.path.join(self.tempdir, 'build_dir')
303 self.deploy_mock = self.StartPatcher(DeployChromeMock())
304 self.deploy = self._GetDeployChrome(
305 list(_REGULAR_TO) + ['--build-dir', self.build_dir,
306 '--board=lumpy', '--staging-only', '--cache-dir',
307 self.tempdir, '--sloppy'])
308
Daniel Erat1ae46382014-08-14 10:23:39 -0700309 def getCopyPath(self, source_path):
310 """Return a chrome_util.Path or None if not present."""
311 paths = [p for p in self.deploy.copy_paths if p.src == source_path]
312 return paths[0] if paths else None
Steve Funge984a532013-11-25 17:09:25 -0800313
Daniel Erat1ae46382014-08-14 10:23:39 -0700314class TestDeploymentType(DeployTestBuildDir):
Steve Funge984a532013-11-25 17:09:25 -0800315 """Test detection of deployment type using build dir."""
316
Daniel Erat9813f0e2014-11-12 11:00:28 -0700317 def testEnvoyDetection(self):
318 """Check for an envoy deployment"""
319 osutils.Touch(os.path.join(self.deploy.options.build_dir, 'envoy_shell'),
320 makedirs=True)
321 self.deploy._CheckDeployType()
322 self.assertTrue(self.getCopyPath('envoy_shell'))
323 self.assertFalse(self.getCopyPath('app_shell'))
324 self.assertFalse(self.getCopyPath('chrome'))
325
Daniel Erat1ae46382014-08-14 10:23:39 -0700326 def testAppShellDetection(self):
327 """Check for an app_shell deployment"""
328 osutils.Touch(os.path.join(self.deploy.options.build_dir, 'app_shell'),
Steve Funge984a532013-11-25 17:09:25 -0800329 makedirs=True)
330 self.deploy._CheckDeployType()
Daniel Erat1ae46382014-08-14 10:23:39 -0700331 self.assertTrue(self.getCopyPath('app_shell'))
332 self.assertFalse(self.getCopyPath('chrome'))
Daniel Erat9813f0e2014-11-12 11:00:28 -0700333 self.assertFalse(self.getCopyPath('envoy_shell'))
Steve Funge984a532013-11-25 17:09:25 -0800334
Daniel Erat1ae46382014-08-14 10:23:39 -0700335 def testChromeAndAppShellDetection(self):
Daniel Erat9813f0e2014-11-12 11:00:28 -0700336 """Check for a chrome deployment when app_shell/envoy_shell also exist."""
Steve Fung63d705d2014-03-16 03:14:03 -0700337 osutils.Touch(os.path.join(self.deploy.options.build_dir, 'chrome'),
338 makedirs=True)
Daniel Erat1ae46382014-08-14 10:23:39 -0700339 osutils.Touch(os.path.join(self.deploy.options.build_dir, 'app_shell'),
Steve Fung63d705d2014-03-16 03:14:03 -0700340 makedirs=True)
Daniel Erat9813f0e2014-11-12 11:00:28 -0700341 osutils.Touch(os.path.join(self.deploy.options.build_dir, 'envoy_shell'),
342 makedirs=True)
Steve Fung63d705d2014-03-16 03:14:03 -0700343 self.deploy._CheckDeployType()
Daniel Erat1ae46382014-08-14 10:23:39 -0700344 self.assertTrue(self.getCopyPath('chrome'))
Daniel Erat9813f0e2014-11-12 11:00:28 -0700345 self.assertFalse(self.getCopyPath('app_shell'))
346 self.assertFalse(self.getCopyPath('envoy_shell'))
Steve Fung63d705d2014-03-16 03:14:03 -0700347
Steve Funge984a532013-11-25 17:09:25 -0800348 def testChromeDetection(self):
349 """Check for a regular chrome deployment"""
350 osutils.Touch(os.path.join(self.deploy.options.build_dir, 'chrome'),
351 makedirs=True)
352 self.deploy._CheckDeployType()
Daniel Erat1ae46382014-08-14 10:23:39 -0700353 self.assertTrue(self.getCopyPath('chrome'))
Daniel Erat9813f0e2014-11-12 11:00:28 -0700354 self.assertFalse(self.getCopyPath('app_shell'))
355 self.assertFalse(self.getCopyPath('envoy_shell'))
Ryan Cuief91e702013-02-04 12:06:36 -0800356
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700357if __name__ == '__main__':
358 cros_test_lib.main()