blob: 458dc28aaa907c034cfa8558d39fba33ae74c7f8 [file] [log] [blame]
Ryan Cuiafd6c5c2012-07-30 17:48:22 -07001# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
Steve Funge984a532013-11-25 17:09:25 -08005"""Unit tests for the deploy_chrome script."""
Ryan Cuiafd6c5c2012-07-30 17:48:22 -07006
Anushruth8d797672019-10-17 12:22:31 -07007import errno
Ryan Cuiafd6c5c2012-07-30 17:48:22 -07008import os
David James88e6f032013-03-02 08:13:20 -08009import time
Mike Frysinger166fea02021-02-12 05:30:33 -050010from unittest import mock
Ryan Cuiafd6c5c2012-07-30 17:48:22 -070011
David Pursellcfd58872015-03-19 09:15:48 -070012from chromite.cli.cros import cros_chrome_sdk_unittest
Ryan Cuief91e702013-02-04 12:06:36 -080013from chromite.lib import chrome_util
Ryan Cuiafd6c5c2012-07-30 17:48:22 -070014from chromite.lib import cros_build_lib
15from chromite.lib import cros_test_lib
Ryan Cui686ec052013-02-12 16:39:41 -080016from chromite.lib import osutils
Erik Chen75a2f492020-08-06 19:15:11 -070017from chromite.lib import parallel_unittest
Ryan Cuiafd6c5c2012-07-30 17:48:22 -070018from chromite.lib import partial_mock
Robert Flack1dc7ea82014-11-26 13:50:24 -050019from chromite.lib import remote_access
Ryan Cuiafd6c5c2012-07-30 17:48:22 -070020from chromite.lib import remote_access_unittest
21from chromite.scripts import deploy_chrome
22
Ryan Cuief91e702013-02-04 12:06:36 -080023
Mike Frysinger27e21b72018-07-12 14:20:21 -040024# pylint: disable=protected-access
25
Ryan Cuiafd6c5c2012-07-30 17:48:22 -070026
Ben Pastene0ff0fa42020-08-14 15:10:07 -070027_REGULAR_TO = ('--device', 'monkey')
Avery Musbach3edff0e2020-03-27 13:35:53 -070028_TARGET_BOARD = 'eve'
Ryan Cuiafd6c5c2012-07-30 17:48:22 -070029_GS_PATH = 'gs://foon'
30
31
32def _ParseCommandLine(argv):
33 return deploy_chrome._ParseCommandLine(['--log-level', 'debug'] + argv)
34
35
36class InterfaceTest(cros_test_lib.OutputTestCase):
37 """Tests the commandline interface of the script."""
38
39 def testGsLocalPathUnSpecified(self):
40 """Test no chrome path specified."""
41 with self.OutputCapturer():
Avery Musbach3edff0e2020-03-27 13:35:53 -070042 self.assertRaises2(SystemExit, _ParseCommandLine,
43 list(_REGULAR_TO) + ['--board', _TARGET_BOARD],
Ryan Cuiafd6c5c2012-07-30 17:48:22 -070044 check_attrs={'code': 2})
45
Ryo Hashimoto77f8eca2021-04-16 16:43:37 +090046 def testBuildDirSpecified(self):
47 """Test case of build dir specified."""
48 argv = list(_REGULAR_TO) + ['--board', _TARGET_BOARD, '--build-dir',
49 '/path/to/chrome']
50 _ParseCommandLine(argv)
51
52 def testBuildDirSpecifiedWithoutBoard(self):
53 """Test case of build dir specified without --board."""
54 argv = list(_REGULAR_TO) + [
55 '--build-dir', '/path/to/chrome/out_' + _TARGET_BOARD + '/Release']
56 options = _ParseCommandLine(argv)
57 self.assertEqual(options.board, _TARGET_BOARD)
58
59 def testBuildDirSpecifiedWithoutBoardError(self):
60 """Test case of irregular build dir specified without --board."""
61 argv = list(_REGULAR_TO) + ['--build-dir', '/path/to/chrome/foo/bar']
62 self.assertParseError(argv)
63
Ryan Cuiafd6c5c2012-07-30 17:48:22 -070064 def testGsPathSpecified(self):
65 """Test case of GS path specified."""
Avery Musbach3edff0e2020-03-27 13:35:53 -070066 argv = list(_REGULAR_TO) + ['--board', _TARGET_BOARD, '--gs-path', _GS_PATH]
Ryan Cuiafd6c5c2012-07-30 17:48:22 -070067 _ParseCommandLine(argv)
68
69 def testLocalPathSpecified(self):
70 """Test case of local path specified."""
Avery Musbach3edff0e2020-03-27 13:35:53 -070071 argv = list(_REGULAR_TO) + ['--board', _TARGET_BOARD, '--local-pkg-path',
72 '/path/to/chrome']
Ryan Cuiafd6c5c2012-07-30 17:48:22 -070073 _ParseCommandLine(argv)
74
Ryo Hashimoto77f8eca2021-04-16 16:43:37 +090075 def testNoBoard(self):
76 """Test no board specified."""
77 argv = list(_REGULAR_TO) + ['--gs-path', _GS_PATH]
78 self.assertParseError(argv)
79
Ryan Cuiafd6c5c2012-07-30 17:48:22 -070080 def testNoTarget(self):
81 """Test no target specified."""
Avery Musbach3edff0e2020-03-27 13:35:53 -070082 argv = ['--board', _TARGET_BOARD, '--gs-path', _GS_PATH]
Ryan Cuief91e702013-02-04 12:06:36 -080083 self.assertParseError(argv)
84
Erik Chen75a2f492020-08-06 19:15:11 -070085 def testLacros(self):
86 """Test basic lacros invocation."""
87 argv = ['--lacros', '--nostrip', '--build-dir', '/path/to/nowhere',
Ben Pastene0ff0fa42020-08-14 15:10:07 -070088 '--device', 'monkey']
Erik Chen75a2f492020-08-06 19:15:11 -070089 options = _ParseCommandLine(argv)
90 self.assertTrue(options.lacros)
91 self.assertEqual(options.target_dir, deploy_chrome.LACROS_DIR)
92
93 def testLacrosRequiresNostrip(self):
94 """Lacros requires --nostrip"""
Ben Pastene0ff0fa42020-08-14 15:10:07 -070095 argv = ['--lacros', '--build-dir', '/path/to/nowhere', '--device',
96 'monkey']
Erik Chen75a2f492020-08-06 19:15:11 -070097 self.assertRaises2(SystemExit, _ParseCommandLine, argv,
98 check_attrs={'code': 2})
99
Ryan Cuief91e702013-02-04 12:06:36 -0800100 def assertParseError(self, argv):
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700101 with self.OutputCapturer():
102 self.assertRaises2(SystemExit, _ParseCommandLine, argv,
103 check_attrs={'code': 2})
104
Thiago Goncales12793312013-05-23 11:26:17 -0700105 def testMountOptionSetsTargetDir(self):
Avery Musbach3edff0e2020-03-27 13:35:53 -0700106 argv = list(_REGULAR_TO) + ['--board', _TARGET_BOARD, '--gs-path', _GS_PATH,
107 '--mount']
Mike Frysingerc3061a62015-06-04 04:16:18 -0400108 options = _ParseCommandLine(argv)
Thiago Goncales12793312013-05-23 11:26:17 -0700109 self.assertIsNot(options.target_dir, None)
110
111 def testMountOptionSetsMountDir(self):
Avery Musbach3edff0e2020-03-27 13:35:53 -0700112 argv = list(_REGULAR_TO) + ['--board', _TARGET_BOARD, '--gs-path', _GS_PATH,
113 '--mount']
Mike Frysingerc3061a62015-06-04 04:16:18 -0400114 options = _ParseCommandLine(argv)
Thiago Goncales12793312013-05-23 11:26:17 -0700115 self.assertIsNot(options.mount_dir, None)
116
117 def testMountOptionDoesNotOverrideTargetDir(self):
Avery Musbach3edff0e2020-03-27 13:35:53 -0700118 argv = list(_REGULAR_TO) + ['--board', _TARGET_BOARD, '--gs-path', _GS_PATH,
119 '--mount', '--target-dir', '/foo/bar/cow']
Mike Frysingerc3061a62015-06-04 04:16:18 -0400120 options = _ParseCommandLine(argv)
Thiago Goncales12793312013-05-23 11:26:17 -0700121 self.assertEqual(options.target_dir, '/foo/bar/cow')
122
123 def testMountOptionDoesNotOverrideMountDir(self):
Avery Musbach3edff0e2020-03-27 13:35:53 -0700124 argv = list(_REGULAR_TO) + ['--board', _TARGET_BOARD, '--gs-path', _GS_PATH,
125 '--mount', '--mount-dir', '/foo/bar/cow']
Mike Frysingerc3061a62015-06-04 04:16:18 -0400126 options = _ParseCommandLine(argv)
Thiago Goncales12793312013-05-23 11:26:17 -0700127 self.assertEqual(options.mount_dir, '/foo/bar/cow')
128
Adrian Eldera2c548a2017-11-07 19:01:29 -0500129 def testSshIdentityOptionSetsOption(self):
Avery Musbach3edff0e2020-03-27 13:35:53 -0700130 argv = list(_REGULAR_TO) + ['--board', _TARGET_BOARD,
131 '--private-key', '/foo/bar/key',
Bernie Thompson93b9ee62018-02-21 14:56:16 -0800132 '--build-dir', '/path/to/nowhere']
Adrian Eldera2c548a2017-11-07 19:01:29 -0500133 options = _ParseCommandLine(argv)
134 self.assertEqual(options.private_key, '/foo/bar/key')
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700135
136class DeployChromeMock(partial_mock.PartialMock):
Steve Funge984a532013-11-25 17:09:25 -0800137 """Deploy Chrome Mock Class."""
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700138
139 TARGET = 'chromite.scripts.deploy_chrome.DeployChrome'
Erik Chen75a2f492020-08-06 19:15:11 -0700140 ATTRS = ('_KillAshChromeIfNeeded', '_DisableRootfsVerification')
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700141
David James88e6f032013-03-02 08:13:20 -0800142 def __init__(self):
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700143 partial_mock.PartialMock.__init__(self)
Robert Flack1dc7ea82014-11-26 13:50:24 -0500144 self.remote_device_mock = remote_access_unittest.RemoteDeviceMock()
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700145 # Target starts off as having rootfs verification enabled.
Ryan Cuie18f24f2012-12-03 18:39:55 -0800146 self.rsh_mock = remote_access_unittest.RemoteShMock()
David James88e6f032013-03-02 08:13:20 -0800147 self.rsh_mock.SetDefaultCmdResult(0)
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700148 self.MockMountCmd(1)
David Haddock3151d912017-10-24 03:50:32 +0000149 self.rsh_mock.AddCmdResult(
Anushruth8d797672019-10-17 12:22:31 -0700150 deploy_chrome.LSOF_COMMAND_CHROME % (deploy_chrome._CHROME_DIR,), 1)
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700151
152 def MockMountCmd(self, returnvalue):
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700153 self.rsh_mock.AddCmdResult(deploy_chrome.MOUNT_RW_COMMAND,
David James88e6f032013-03-02 08:13:20 -0800154 returnvalue)
155
156 def _DisableRootfsVerification(self, inst):
157 with mock.patch.object(time, 'sleep'):
158 self.backup['_DisableRootfsVerification'](inst)
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700159
Ryan Cui4d6fca92012-12-13 16:41:56 -0800160 def PreStart(self):
Robert Flack1dc7ea82014-11-26 13:50:24 -0500161 self.remote_device_mock.start()
Ryan Cui4d6fca92012-12-13 16:41:56 -0800162 self.rsh_mock.start()
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700163
Ryan Cui4d6fca92012-12-13 16:41:56 -0800164 def PreStop(self):
165 self.rsh_mock.stop()
Robert Flack1dc7ea82014-11-26 13:50:24 -0500166 self.remote_device_mock.stop()
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700167
Erik Chen75a2f492020-08-06 19:15:11 -0700168 def _KillAshChromeIfNeeded(self, _inst):
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700169 # Fully stub out for now.
170 pass
171
172
Ryan Cuief91e702013-02-04 12:06:36 -0800173class DeployTest(cros_test_lib.MockTempDirTestCase):
Steve Funge984a532013-11-25 17:09:25 -0800174 """Setup a deploy object with a GS-path for use in tests."""
175
Ryan Cuief91e702013-02-04 12:06:36 -0800176 def _GetDeployChrome(self, args):
Mike Frysingerc3061a62015-06-04 04:16:18 -0400177 options = _ParseCommandLine(args)
Ryan Cuia56a71e2012-10-18 18:40:35 -0700178 return deploy_chrome.DeployChrome(
179 options, self.tempdir, os.path.join(self.tempdir, 'staging'))
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700180
181 def setUp(self):
Ryan Cuif1416f32013-01-22 18:43:41 -0800182 self.deploy_mock = self.StartPatcher(DeployChromeMock())
Avery Musbach3edff0e2020-03-27 13:35:53 -0700183 self.deploy = self._GetDeployChrome(list(_REGULAR_TO) +
184 ['--board', _TARGET_BOARD, '--gs-path',
185 _GS_PATH, '--force', '--mount'])
Mike Frysingerfcca49e2021-03-17 01:09:20 -0400186 self.remote_reboot_mock = self.PatchObject(
187 remote_access.RemoteAccess, 'RemoteReboot', return_value=True)
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700188
Avery Musbach3edff0e2020-03-27 13:35:53 -0700189
190class TestCheckIfBoardMatches(DeployTest):
191 """Testing checking whether the DUT board matches the target board."""
192
193 def testMatchedBoard(self):
194 """Test the case where the DUT board matches the target board."""
195 self.PatchObject(remote_access.ChromiumOSDevice, 'board', _TARGET_BOARD)
196 self.assertTrue(self.deploy.options.force)
197 self.deploy._CheckBoard()
198 self.deploy.options.force = False
199 self.deploy._CheckBoard()
200
201 def testMismatchedBoard(self):
202 """Test the case where the DUT board does not match the target board."""
203 self.PatchObject(remote_access.ChromiumOSDevice, 'board', 'cedar')
204 self.assertTrue(self.deploy.options.force)
205 self.deploy._CheckBoard()
206 self.deploy.options.force = False
207 self.PatchObject(cros_build_lib, 'BooleanPrompt', return_value=True)
208 self.deploy._CheckBoard()
209 self.PatchObject(cros_build_lib, 'BooleanPrompt', return_value=False)
210 self.assertRaises(deploy_chrome.DeployFailure, self.deploy._CheckBoard)
211
212
David James88e6f032013-03-02 08:13:20 -0800213class TestDisableRootfsVerification(DeployTest):
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700214 """Testing disabling of rootfs verification and RO mode."""
215
David James88e6f032013-03-02 08:13:20 -0800216 def testDisableRootfsVerificationSuccess(self):
217 """Test the working case, disabling rootfs verification."""
218 self.deploy_mock.MockMountCmd(0)
219 self.deploy._DisableRootfsVerification()
Steven Bennettsca73efa2018-07-10 13:36:56 -0700220 self.assertFalse(self.deploy._root_dir_is_still_readonly.is_set())
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700221
222 def testDisableRootfsVerificationFailure(self):
223 """Test failure to disable rootfs verification."""
Mike Frysinger27e21b72018-07-12 14:20:21 -0400224 # pylint: disable=unused-argument
Shuqian Zhao14e61092017-11-17 00:02:16 +0000225 def RaiseRunCommandError(timeout_sec=None):
Mike Frysinger929f3ba2019-09-12 03:24:59 -0400226 raise cros_build_lib.RunCommandError('Mock RunCommandError')
Luigi Semenzato1bc79b22016-11-22 16:32:17 -0800227 self.remote_reboot_mock.side_effect = RaiseRunCommandError
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700228 self.assertRaises(cros_build_lib.RunCommandError,
David James88e6f032013-03-02 08:13:20 -0800229 self.deploy._DisableRootfsVerification)
Luigi Semenzato1bc79b22016-11-22 16:32:17 -0800230 self.remote_reboot_mock.side_effect = None
Steven Bennettsca73efa2018-07-10 13:36:56 -0700231 self.assertFalse(self.deploy._root_dir_is_still_readonly.is_set())
David James88e6f032013-03-02 08:13:20 -0800232
233
234class TestMount(DeployTest):
235 """Testing mount success and failure."""
236
237 def testSuccess(self):
238 """Test case where we are able to mount as writable."""
Steven Bennettsca73efa2018-07-10 13:36:56 -0700239 self.assertFalse(self.deploy._root_dir_is_still_readonly.is_set())
David James88e6f032013-03-02 08:13:20 -0800240 self.deploy_mock.MockMountCmd(0)
241 self.deploy._MountRootfsAsWritable()
Steven Bennettsca73efa2018-07-10 13:36:56 -0700242 self.assertFalse(self.deploy._root_dir_is_still_readonly.is_set())
David James88e6f032013-03-02 08:13:20 -0800243
244 def testMountError(self):
245 """Test that mount failure doesn't raise an exception by default."""
Steven Bennettsca73efa2018-07-10 13:36:56 -0700246 self.assertFalse(self.deploy._root_dir_is_still_readonly.is_set())
Avery Musbach3edff0e2020-03-27 13:35:53 -0700247 self.PatchObject(remote_access.ChromiumOSDevice, 'IsDirWritable',
Robert Flack1dc7ea82014-11-26 13:50:24 -0500248 return_value=False, autospec=True)
David James88e6f032013-03-02 08:13:20 -0800249 self.deploy._MountRootfsAsWritable()
Steven Bennettsca73efa2018-07-10 13:36:56 -0700250 self.assertTrue(self.deploy._root_dir_is_still_readonly.is_set())
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700251
252 def testMountRwFailure(self):
Mike Frysingerf5a3b2d2019-12-12 14:36:17 -0500253 """Test that mount failure raises an exception if check=True."""
David James88e6f032013-03-02 08:13:20 -0800254 self.assertRaises(cros_build_lib.RunCommandError,
Mike Frysingerf5a3b2d2019-12-12 14:36:17 -0500255 self.deploy._MountRootfsAsWritable, check=True)
Steven Bennettsca73efa2018-07-10 13:36:56 -0700256 self.assertFalse(self.deploy._root_dir_is_still_readonly.is_set())
Robert Flack1dc7ea82014-11-26 13:50:24 -0500257
258 def testMountTempDir(self):
259 """Test that mount succeeds if target dir is writable."""
Steven Bennettsca73efa2018-07-10 13:36:56 -0700260 self.assertFalse(self.deploy._root_dir_is_still_readonly.is_set())
Avery Musbach3edff0e2020-03-27 13:35:53 -0700261 self.PatchObject(remote_access.ChromiumOSDevice, 'IsDirWritable',
Robert Flack1dc7ea82014-11-26 13:50:24 -0500262 return_value=True, autospec=True)
263 self.deploy._MountRootfsAsWritable()
Steven Bennettsca73efa2018-07-10 13:36:56 -0700264 self.assertFalse(self.deploy._root_dir_is_still_readonly.is_set())
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700265
266
Anushruth8d797672019-10-17 12:22:31 -0700267class TestMountTarget(DeployTest):
Mike Frysingerdf1d0b02019-11-12 17:44:12 -0500268 """Testing mount and umount command handling."""
Anushruth8d797672019-10-17 12:22:31 -0700269
270 def testMountTargetUmountFailure(self):
271 """Test error being thrown if umount fails.
272
273 Test that 'lsof' is run on mount-dir and 'mount -rbind' command is not run
274 if 'umount' cmd fails.
275 """
276 mount_dir = self.deploy.options.mount_dir
277 target_dir = self.deploy.options.target_dir
278 self.deploy_mock.rsh_mock.AddCmdResult(
279 deploy_chrome._UMOUNT_DIR_IF_MOUNTPOINT_CMD %
280 {'dir': mount_dir}, returncode=errno.EBUSY, stderr='Target is Busy')
281 self.deploy_mock.rsh_mock.AddCmdResult(deploy_chrome.LSOF_COMMAND %
282 (mount_dir,), returncode=0,
283 stdout='process ' + mount_dir)
284 # Check for RunCommandError being thrown.
285 self.assertRaises(cros_build_lib.RunCommandError,
286 self.deploy._MountTarget)
287 # Check for the 'mount -rbind' command not run.
288 self.deploy_mock.rsh_mock.assertCommandContains(
289 (deploy_chrome._BIND_TO_FINAL_DIR_CMD % (target_dir, mount_dir)),
290 expected=False)
291 # Check for lsof command being called.
292 self.deploy_mock.rsh_mock.assertCommandContains(
293 (deploy_chrome.LSOF_COMMAND % (mount_dir,)))
294
295
Ryan Cuief91e702013-02-04 12:06:36 -0800296class TestUiJobStarted(DeployTest):
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700297 """Test detection of a running 'ui' job."""
298
Ryan Cuif2d1a582013-02-19 14:08:13 -0800299 def MockStatusUiCmd(self, **kwargs):
David Haddock3151d912017-10-24 03:50:32 +0000300 self.deploy_mock.rsh_mock.AddCmdResult('status ui', **kwargs)
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700301
302 def testUiJobStartedFalse(self):
303 """Correct results with a stopped job."""
Ryan Cuif2d1a582013-02-19 14:08:13 -0800304 self.MockStatusUiCmd(output='ui stop/waiting')
305 self.assertFalse(self.deploy._CheckUiJobStarted())
306
307 def testNoUiJob(self):
308 """Correct results when the job doesn't exist."""
309 self.MockStatusUiCmd(error='start: Unknown job: ui', returncode=1)
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700310 self.assertFalse(self.deploy._CheckUiJobStarted())
311
312 def testCheckRootfsWriteableTrue(self):
313 """Correct results with a running job."""
Ryan Cuif2d1a582013-02-19 14:08:13 -0800314 self.MockStatusUiCmd(output='ui start/running, process 297')
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700315 self.assertTrue(self.deploy._CheckUiJobStarted())
316
317
Ryan Cuief91e702013-02-04 12:06:36 -0800318class StagingTest(cros_test_lib.MockTempDirTestCase):
319 """Test user-mode and ebuild-mode staging functionality."""
320
321 def setUp(self):
Ryan Cuief91e702013-02-04 12:06:36 -0800322 self.staging_dir = os.path.join(self.tempdir, 'staging')
323 self.build_dir = os.path.join(self.tempdir, 'build_dir')
Avery Musbach3edff0e2020-03-27 13:35:53 -0700324 self.common_flags = ['--board', _TARGET_BOARD,
325 '--build-dir', self.build_dir, '--staging-only',
Mike Frysinger3bb61cb2022-04-14 16:07:44 -0400326 '--cache-dir', str(self.tempdir)]
Ryan Cuia0215a72013-02-14 16:20:45 -0800327 self.sdk_mock = self.StartPatcher(cros_chrome_sdk_unittest.SDKFetcherMock())
Ryan Cui686ec052013-02-12 16:39:41 -0800328 self.PatchObject(
329 osutils, 'SourceEnvironment', autospec=True,
330 return_value={'STRIP': 'x86_64-cros-linux-gnu-strip'})
Ryan Cuief91e702013-02-04 12:06:36 -0800331
David Jamesa6e08892013-03-01 13:34:11 -0800332 def testSingleFileDeployFailure(self):
333 """Default staging enforces that mandatory files are copied"""
Mike Frysingerc3061a62015-06-04 04:16:18 -0400334 options = _ParseCommandLine(self.common_flags)
David Jamesa6e08892013-03-01 13:34:11 -0800335 osutils.Touch(os.path.join(self.build_dir, 'chrome'), makedirs=True)
336 self.assertRaises(
337 chrome_util.MissingPathError, deploy_chrome._PrepareStagingDir,
Daniel Eratc89829c2014-05-12 17:24:21 -0700338 options, self.tempdir, self.staging_dir, chrome_util._COPY_PATHS_CHROME)
Ryan Cuief91e702013-02-04 12:06:36 -0800339
David Jamesa6e08892013-03-01 13:34:11 -0800340 def testSloppyDeployFailure(self):
341 """Sloppy staging enforces that at least one file is copied."""
Mike Frysingerc3061a62015-06-04 04:16:18 -0400342 options = _ParseCommandLine(self.common_flags + ['--sloppy'])
David Jamesa6e08892013-03-01 13:34:11 -0800343 self.assertRaises(
344 chrome_util.MissingPathError, deploy_chrome._PrepareStagingDir,
Daniel Eratc89829c2014-05-12 17:24:21 -0700345 options, self.tempdir, self.staging_dir, chrome_util._COPY_PATHS_CHROME)
David Jamesa6e08892013-03-01 13:34:11 -0800346
347 def testSloppyDeploySuccess(self):
348 """Sloppy staging - stage one file."""
Mike Frysingerc3061a62015-06-04 04:16:18 -0400349 options = _ParseCommandLine(self.common_flags + ['--sloppy'])
David Jamesa6e08892013-03-01 13:34:11 -0800350 osutils.Touch(os.path.join(self.build_dir, 'chrome'), makedirs=True)
Steve Funge984a532013-11-25 17:09:25 -0800351 deploy_chrome._PrepareStagingDir(options, self.tempdir, self.staging_dir,
Daniel Eratc89829c2014-05-12 17:24:21 -0700352 chrome_util._COPY_PATHS_CHROME)
David Jamesa6e08892013-03-01 13:34:11 -0800353
Steve Funge984a532013-11-25 17:09:25 -0800354
355class DeployTestBuildDir(cros_test_lib.MockTempDirTestCase):
Daniel Erat1ae46382014-08-14 10:23:39 -0700356 """Set up a deploy object with a build-dir for use in deployment type tests"""
Steve Funge984a532013-11-25 17:09:25 -0800357
358 def _GetDeployChrome(self, args):
Mike Frysingerc3061a62015-06-04 04:16:18 -0400359 options = _ParseCommandLine(args)
Steve Funge984a532013-11-25 17:09:25 -0800360 return deploy_chrome.DeployChrome(
361 options, self.tempdir, os.path.join(self.tempdir, 'staging'))
362
363 def setUp(self):
364 self.staging_dir = os.path.join(self.tempdir, 'staging')
365 self.build_dir = os.path.join(self.tempdir, 'build_dir')
366 self.deploy_mock = self.StartPatcher(DeployChromeMock())
367 self.deploy = self._GetDeployChrome(
Avery Musbach3edff0e2020-03-27 13:35:53 -0700368 list(_REGULAR_TO) + ['--board', _TARGET_BOARD,
369 '--build-dir', self.build_dir, '--staging-only',
Mike Frysinger3bb61cb2022-04-14 16:07:44 -0400370 '--cache-dir', str(self.tempdir), '--sloppy'])
Steve Funge984a532013-11-25 17:09:25 -0800371
Daniel Erat1ae46382014-08-14 10:23:39 -0700372 def getCopyPath(self, source_path):
373 """Return a chrome_util.Path or None if not present."""
374 paths = [p for p in self.deploy.copy_paths if p.src == source_path]
375 return paths[0] if paths else None
Steve Funge984a532013-11-25 17:09:25 -0800376
Daniel Erat1ae46382014-08-14 10:23:39 -0700377class TestDeploymentType(DeployTestBuildDir):
Steve Funge984a532013-11-25 17:09:25 -0800378 """Test detection of deployment type using build dir."""
379
Daniel Erat1ae46382014-08-14 10:23:39 -0700380 def testAppShellDetection(self):
381 """Check for an app_shell deployment"""
382 osutils.Touch(os.path.join(self.deploy.options.build_dir, 'app_shell'),
Steve Funge984a532013-11-25 17:09:25 -0800383 makedirs=True)
384 self.deploy._CheckDeployType()
Daniel Erat1ae46382014-08-14 10:23:39 -0700385 self.assertTrue(self.getCopyPath('app_shell'))
386 self.assertFalse(self.getCopyPath('chrome'))
Steve Funge984a532013-11-25 17:09:25 -0800387
Daniel Erat1ae46382014-08-14 10:23:39 -0700388 def testChromeAndAppShellDetection(self):
Daniel Eratf53bd3a2016-12-02 11:28:36 -0700389 """Check for a chrome deployment when app_shell also exists."""
Steve Fung63d705d2014-03-16 03:14:03 -0700390 osutils.Touch(os.path.join(self.deploy.options.build_dir, 'chrome'),
391 makedirs=True)
Daniel Erat1ae46382014-08-14 10:23:39 -0700392 osutils.Touch(os.path.join(self.deploy.options.build_dir, 'app_shell'),
Steve Fung63d705d2014-03-16 03:14:03 -0700393 makedirs=True)
394 self.deploy._CheckDeployType()
Daniel Erat1ae46382014-08-14 10:23:39 -0700395 self.assertTrue(self.getCopyPath('chrome'))
Daniel Erat9813f0e2014-11-12 11:00:28 -0700396 self.assertFalse(self.getCopyPath('app_shell'))
Steve Fung63d705d2014-03-16 03:14:03 -0700397
Steve Funge984a532013-11-25 17:09:25 -0800398 def testChromeDetection(self):
399 """Check for a regular chrome deployment"""
400 osutils.Touch(os.path.join(self.deploy.options.build_dir, 'chrome'),
401 makedirs=True)
402 self.deploy._CheckDeployType()
Daniel Erat1ae46382014-08-14 10:23:39 -0700403 self.assertTrue(self.getCopyPath('chrome'))
Daniel Erat9813f0e2014-11-12 11:00:28 -0700404 self.assertFalse(self.getCopyPath('app_shell'))
Ben Pastenee484b342020-06-30 18:29:27 -0700405
406
407class TestDeployTestBinaries(cros_test_lib.RunCommandTempDirTestCase):
408 """Tests _DeployTestBinaries()."""
409
410 def setUp(self):
411 options = _ParseCommandLine(list(_REGULAR_TO) + [
412 '--board', _TARGET_BOARD, '--force', '--mount',
413 '--build-dir', os.path.join(self.tempdir, 'build_dir'),
414 '--nostrip'])
415 self.deploy = deploy_chrome.DeployChrome(
416 options, self.tempdir, os.path.join(self.tempdir, 'staging'))
417
Brian Sheedy86f12342020-10-29 15:30:02 -0700418 def _SimulateBinaries(self):
419 # Ensure the staging dir contains the right binaries to copy over.
Ben Pastenee484b342020-06-30 18:29:27 -0700420 test_binaries = [
421 'run_a_tests',
422 'run_b_tests',
423 'run_c_tests',
424 ]
425 # Simulate having the binaries both on the device and in our local build
426 # dir.
427 self.rc.AddCmdResult(
428 partial_mock.In(deploy_chrome._FIND_TEST_BIN_CMD),
429 stdout='\n'.join(test_binaries))
430 for binary in test_binaries:
431 osutils.Touch(os.path.join(self.deploy.options.build_dir, binary),
432 makedirs=True, mode=0o700)
Brian Sheedy86f12342020-10-29 15:30:02 -0700433 return test_binaries
Ben Pastenee484b342020-06-30 18:29:27 -0700434
Brian Sheedy86f12342020-10-29 15:30:02 -0700435 def _AssertBinariesInStagingDir(self, test_binaries):
Ben Pastenee484b342020-06-30 18:29:27 -0700436 # Ensure the binaries were placed in the staging dir used to copy them over.
437 staging_dir = os.path.join(
438 self.tempdir, os.path.basename(deploy_chrome._CHROME_TEST_BIN_DIR))
439 for binary in test_binaries:
440 self.assertIn(binary, os.listdir(staging_dir))
Erik Chen75a2f492020-08-06 19:15:11 -0700441
Brian Sheedy86f12342020-10-29 15:30:02 -0700442 def testFindError(self):
443 """Ensure an error is thrown if we can't inspect the device."""
444 self.rc.AddCmdResult(
445 partial_mock.In(deploy_chrome._FIND_TEST_BIN_CMD), 1)
446 self.assertRaises(
447 deploy_chrome.DeployFailure, self.deploy._DeployTestBinaries)
448
449 def testSuccess(self):
450 """Ensure that the happy path succeeds as expected."""
451 test_binaries = self._SimulateBinaries()
452 self.deploy._DeployTestBinaries()
453 self._AssertBinariesInStagingDir(test_binaries)
454
455 def testRetrySuccess(self):
456 """Ensure that a transient exception still results in success."""
457 # Raises a RunCommandError on its first invocation, but passes on subsequent
458 # calls.
459 def SideEffect(*args, **kwargs):
Yuke Liaobe6bac32020-12-26 22:16:49 -0800460 # pylint: disable=unused-argument
Brian Sheedy86f12342020-10-29 15:30:02 -0700461 if not SideEffect.called:
462 SideEffect.called = True
463 raise cros_build_lib.RunCommandError('fail')
464 SideEffect.called = False
465
466 test_binaries = self._SimulateBinaries()
467 with mock.patch.object(
468 remote_access.ChromiumOSDevice, 'CopyToDevice',
469 side_effect=SideEffect) as copy_mock:
470 self.deploy._DeployTestBinaries()
471 self.assertEqual(copy_mock.call_count, 2)
472 self._AssertBinariesInStagingDir(test_binaries)
473
474 def testRetryFailure(self):
475 """Ensure that consistent exceptions result in failure."""
476 self._SimulateBinaries()
477 with self.assertRaises(cros_build_lib.RunCommandError):
478 with mock.patch.object(
479 remote_access.ChromiumOSDevice, 'CopyToDevice',
480 side_effect=cros_build_lib.RunCommandError('fail')):
481 self.deploy._DeployTestBinaries()
482
Erik Chen75a2f492020-08-06 19:15:11 -0700483
484class LacrosPerformTest(cros_test_lib.RunCommandTempDirTestCase):
485 """Line coverage for Perform() method with --lacros option."""
486
487 def setUp(self):
Yuke Liao24fc60c2020-12-26 22:16:49 -0800488 self.deploy = None
489 self._ran_start_command = False
490 self.StartPatcher(parallel_unittest.ParallelMock())
491
492 def start_ui_side_effect(*args, **kwargs):
493 # pylint: disable=unused-argument
494 self._ran_start_command = True
495
496 self.rc.AddCmdResult(partial_mock.In('start ui'),
497 side_effect=start_ui_side_effect)
498
499 def prepareDeploy(self, options=None):
500 if not options:
501 options = _ParseCommandLine([
502 '--lacros', '--nostrip', '--build-dir', '/path/to/nowhere',
503 '--device', 'monkey'
504 ])
Erik Chen75a2f492020-08-06 19:15:11 -0700505 self.deploy = deploy_chrome.DeployChrome(
506 options, self.tempdir, os.path.join(self.tempdir, 'staging'))
507
508 # These methods being mocked are all side effects expected for a --lacros
509 # deploy.
510 self.deploy._EnsureTargetDir = mock.Mock()
511 self.deploy._GetDeviceInfo = mock.Mock()
512 self.deploy._CheckConnection = mock.Mock()
513 self.deploy._MountRootfsAsWritable = mock.Mock()
514 self.deploy._PrepareStagingDir = mock.Mock()
515 self.deploy._CheckDeviceFreeSpace = mock.Mock()
Yuke Liaobe6bac32020-12-26 22:16:49 -0800516 self.deploy._KillAshChromeIfNeeded = mock.Mock()
Erik Chen75a2f492020-08-06 19:15:11 -0700517
518 def testConfNotModified(self):
519 """When the conf file is not modified we don't restart chrome ."""
Yuke Liao24fc60c2020-12-26 22:16:49 -0800520 self.prepareDeploy()
Erik Chen75a2f492020-08-06 19:15:11 -0700521 self.deploy.Perform()
522 self.deploy._KillAshChromeIfNeeded.assert_not_called()
523 self.assertFalse(self._ran_start_command)
524
525 def testConfModified(self):
526 """When the conf file is modified we restart chrome."""
Yuke Liao24fc60c2020-12-26 22:16:49 -0800527 self.prepareDeploy()
Erik Chen75a2f492020-08-06 19:15:11 -0700528
529 # We intentionally add '\n' to MODIFIED_CONF_FILE to simulate echo adding a
530 # newline when invoked in the shell.
531 self.rc.AddCmdResult(
532 partial_mock.In(deploy_chrome.ENABLE_LACROS_VIA_CONF_COMMAND),
533 stdout=deploy_chrome.MODIFIED_CONF_FILE + '\n')
534
535 self.deploy.Perform()
536 self.deploy._KillAshChromeIfNeeded.assert_called()
537 self.assertTrue(self._ran_start_command)
Yuke Liao24fc60c2020-12-26 22:16:49 -0800538
539 def testSkipModifyingConf(self):
540 """SKip modifying the config file when the argument is specified."""
541 self.prepareDeploy(
542 _ParseCommandLine([
543 '--lacros', '--nostrip', '--build-dir', '/path/to/nowhere',
544 '--device', 'monkey', '--skip-modifying-config-file'
545 ]))
546
547 self.rc.AddCmdResult(
548 partial_mock.In(deploy_chrome.ENABLE_LACROS_VIA_CONF_COMMAND),
549 stdout=deploy_chrome.MODIFIED_CONF_FILE + '\n')
550
551 self.deploy.Perform()
552 self.deploy._KillAshChromeIfNeeded.assert_not_called()
553 self.assertFalse(self._ran_start_command)