blob: cb9025a9aef050565a1ba5fa54979076ad625bd2 [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
Jae Hoon Kimdf842912022-05-19 06:40:42 +000016from chromite.lib import gs
Ryan Cui686ec052013-02-12 16:39:41 -080017from chromite.lib import osutils
Erik Chen75a2f492020-08-06 19:15:11 -070018from chromite.lib import parallel_unittest
Ryan Cuiafd6c5c2012-07-30 17:48:22 -070019from chromite.lib import partial_mock
Robert Flack1dc7ea82014-11-26 13:50:24 -050020from chromite.lib import remote_access
Ryan Cuiafd6c5c2012-07-30 17:48:22 -070021from chromite.lib import remote_access_unittest
22from chromite.scripts import deploy_chrome
23
Ryan Cuief91e702013-02-04 12:06:36 -080024
Mike Frysinger27e21b72018-07-12 14:20:21 -040025# pylint: disable=protected-access
26
Ryan Cuiafd6c5c2012-07-30 17:48:22 -070027
Ben Pastene0ff0fa42020-08-14 15:10:07 -070028_REGULAR_TO = ('--device', 'monkey')
Avery Musbach3edff0e2020-03-27 13:35:53 -070029_TARGET_BOARD = 'eve'
Ryan Cuiafd6c5c2012-07-30 17:48:22 -070030_GS_PATH = 'gs://foon'
31
32
33def _ParseCommandLine(argv):
34 return deploy_chrome._ParseCommandLine(['--log-level', 'debug'] + argv)
35
36
37class InterfaceTest(cros_test_lib.OutputTestCase):
38 """Tests the commandline interface of the script."""
39
40 def testGsLocalPathUnSpecified(self):
41 """Test no chrome path specified."""
42 with self.OutputCapturer():
Avery Musbach3edff0e2020-03-27 13:35:53 -070043 self.assertRaises2(SystemExit, _ParseCommandLine,
44 list(_REGULAR_TO) + ['--board', _TARGET_BOARD],
Ryan Cuiafd6c5c2012-07-30 17:48:22 -070045 check_attrs={'code': 2})
46
Ryo Hashimoto77f8eca2021-04-16 16:43:37 +090047 def testBuildDirSpecified(self):
48 """Test case of build dir specified."""
49 argv = list(_REGULAR_TO) + ['--board', _TARGET_BOARD, '--build-dir',
50 '/path/to/chrome']
51 _ParseCommandLine(argv)
52
53 def testBuildDirSpecifiedWithoutBoard(self):
54 """Test case of build dir specified without --board."""
55 argv = list(_REGULAR_TO) + [
56 '--build-dir', '/path/to/chrome/out_' + _TARGET_BOARD + '/Release']
57 options = _ParseCommandLine(argv)
58 self.assertEqual(options.board, _TARGET_BOARD)
59
60 def testBuildDirSpecifiedWithoutBoardError(self):
61 """Test case of irregular build dir specified without --board."""
62 argv = list(_REGULAR_TO) + ['--build-dir', '/path/to/chrome/foo/bar']
63 self.assertParseError(argv)
64
Ryan Cuiafd6c5c2012-07-30 17:48:22 -070065 def testGsPathSpecified(self):
66 """Test case of GS path specified."""
Avery Musbach3edff0e2020-03-27 13:35:53 -070067 argv = list(_REGULAR_TO) + ['--board', _TARGET_BOARD, '--gs-path', _GS_PATH]
Ryan Cuiafd6c5c2012-07-30 17:48:22 -070068 _ParseCommandLine(argv)
69
70 def testLocalPathSpecified(self):
71 """Test case of local path specified."""
Avery Musbach3edff0e2020-03-27 13:35:53 -070072 argv = list(_REGULAR_TO) + ['--board', _TARGET_BOARD, '--local-pkg-path',
73 '/path/to/chrome']
Ryan Cuiafd6c5c2012-07-30 17:48:22 -070074 _ParseCommandLine(argv)
75
Ryo Hashimoto77f8eca2021-04-16 16:43:37 +090076 def testNoBoard(self):
77 """Test no board specified."""
78 argv = list(_REGULAR_TO) + ['--gs-path', _GS_PATH]
79 self.assertParseError(argv)
80
Ryan Cuiafd6c5c2012-07-30 17:48:22 -070081 def testNoTarget(self):
82 """Test no target specified."""
Avery Musbach3edff0e2020-03-27 13:35:53 -070083 argv = ['--board', _TARGET_BOARD, '--gs-path', _GS_PATH]
Ryan Cuief91e702013-02-04 12:06:36 -080084 self.assertParseError(argv)
85
Erik Chen75a2f492020-08-06 19:15:11 -070086 def testLacros(self):
87 """Test basic lacros invocation."""
Sven Zheng022f7ea2022-07-20 20:09:11 +000088 argv = ['--lacros', '--build-dir', '/path/to/nowhere',
89 '--device', 'monkey', '--board', 'atlas']
Erik Chen75a2f492020-08-06 19:15:11 -070090 options = _ParseCommandLine(argv)
91 self.assertTrue(options.lacros)
92 self.assertEqual(options.target_dir, deploy_chrome.LACROS_DIR)
93
Sven Zheng022f7ea2022-07-20 20:09:11 +000094 def testLacrosNoStrip(self):
95 """Test lacros invocation with nostrip."""
96 argv = ['--lacros', '--nostrip', '--build-dir', '/path/to/nowhere',
97 '--device', 'monkey']
98 options = _ParseCommandLine(argv)
99 self.assertTrue(options.lacros)
100 self.assertFalse(options.dostrip)
101 self.assertEqual(options.target_dir, deploy_chrome.LACROS_DIR)
Erik Chen75a2f492020-08-06 19:15:11 -0700102
Ryan Cuief91e702013-02-04 12:06:36 -0800103 def assertParseError(self, argv):
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700104 with self.OutputCapturer():
105 self.assertRaises2(SystemExit, _ParseCommandLine, argv,
106 check_attrs={'code': 2})
107
Thiago Goncales12793312013-05-23 11:26:17 -0700108 def testMountOptionSetsTargetDir(self):
Avery Musbach3edff0e2020-03-27 13:35:53 -0700109 argv = list(_REGULAR_TO) + ['--board', _TARGET_BOARD, '--gs-path', _GS_PATH,
110 '--mount']
Mike Frysingerc3061a62015-06-04 04:16:18 -0400111 options = _ParseCommandLine(argv)
Thiago Goncales12793312013-05-23 11:26:17 -0700112 self.assertIsNot(options.target_dir, None)
113
114 def testMountOptionSetsMountDir(self):
Avery Musbach3edff0e2020-03-27 13:35:53 -0700115 argv = list(_REGULAR_TO) + ['--board', _TARGET_BOARD, '--gs-path', _GS_PATH,
116 '--mount']
Mike Frysingerc3061a62015-06-04 04:16:18 -0400117 options = _ParseCommandLine(argv)
Thiago Goncales12793312013-05-23 11:26:17 -0700118 self.assertIsNot(options.mount_dir, None)
119
120 def testMountOptionDoesNotOverrideTargetDir(self):
Avery Musbach3edff0e2020-03-27 13:35:53 -0700121 argv = list(_REGULAR_TO) + ['--board', _TARGET_BOARD, '--gs-path', _GS_PATH,
122 '--mount', '--target-dir', '/foo/bar/cow']
Mike Frysingerc3061a62015-06-04 04:16:18 -0400123 options = _ParseCommandLine(argv)
Thiago Goncales12793312013-05-23 11:26:17 -0700124 self.assertEqual(options.target_dir, '/foo/bar/cow')
125
126 def testMountOptionDoesNotOverrideMountDir(self):
Avery Musbach3edff0e2020-03-27 13:35:53 -0700127 argv = list(_REGULAR_TO) + ['--board', _TARGET_BOARD, '--gs-path', _GS_PATH,
128 '--mount', '--mount-dir', '/foo/bar/cow']
Mike Frysingerc3061a62015-06-04 04:16:18 -0400129 options = _ParseCommandLine(argv)
Thiago Goncales12793312013-05-23 11:26:17 -0700130 self.assertEqual(options.mount_dir, '/foo/bar/cow')
131
Adrian Eldera2c548a2017-11-07 19:01:29 -0500132 def testSshIdentityOptionSetsOption(self):
Avery Musbach3edff0e2020-03-27 13:35:53 -0700133 argv = list(_REGULAR_TO) + ['--board', _TARGET_BOARD,
134 '--private-key', '/foo/bar/key',
Bernie Thompson93b9ee62018-02-21 14:56:16 -0800135 '--build-dir', '/path/to/nowhere']
Adrian Eldera2c548a2017-11-07 19:01:29 -0500136 options = _ParseCommandLine(argv)
137 self.assertEqual(options.private_key, '/foo/bar/key')
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700138
139class DeployChromeMock(partial_mock.PartialMock):
Steve Funge984a532013-11-25 17:09:25 -0800140 """Deploy Chrome Mock Class."""
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700141
142 TARGET = 'chromite.scripts.deploy_chrome.DeployChrome'
Erik Chen75a2f492020-08-06 19:15:11 -0700143 ATTRS = ('_KillAshChromeIfNeeded', '_DisableRootfsVerification')
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700144
David James88e6f032013-03-02 08:13:20 -0800145 def __init__(self):
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700146 partial_mock.PartialMock.__init__(self)
Robert Flack1dc7ea82014-11-26 13:50:24 -0500147 self.remote_device_mock = remote_access_unittest.RemoteDeviceMock()
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700148 # Target starts off as having rootfs verification enabled.
Ryan Cuie18f24f2012-12-03 18:39:55 -0800149 self.rsh_mock = remote_access_unittest.RemoteShMock()
David James88e6f032013-03-02 08:13:20 -0800150 self.rsh_mock.SetDefaultCmdResult(0)
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700151 self.MockMountCmd(1)
David Haddock3151d912017-10-24 03:50:32 +0000152 self.rsh_mock.AddCmdResult(
Anushruth8d797672019-10-17 12:22:31 -0700153 deploy_chrome.LSOF_COMMAND_CHROME % (deploy_chrome._CHROME_DIR,), 1)
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700154
155 def MockMountCmd(self, returnvalue):
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700156 self.rsh_mock.AddCmdResult(deploy_chrome.MOUNT_RW_COMMAND,
David James88e6f032013-03-02 08:13:20 -0800157 returnvalue)
158
159 def _DisableRootfsVerification(self, inst):
160 with mock.patch.object(time, 'sleep'):
161 self.backup['_DisableRootfsVerification'](inst)
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700162
Ryan Cui4d6fca92012-12-13 16:41:56 -0800163 def PreStart(self):
Robert Flack1dc7ea82014-11-26 13:50:24 -0500164 self.remote_device_mock.start()
Ryan Cui4d6fca92012-12-13 16:41:56 -0800165 self.rsh_mock.start()
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700166
Ryan Cui4d6fca92012-12-13 16:41:56 -0800167 def PreStop(self):
168 self.rsh_mock.stop()
Robert Flack1dc7ea82014-11-26 13:50:24 -0500169 self.remote_device_mock.stop()
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700170
Erik Chen75a2f492020-08-06 19:15:11 -0700171 def _KillAshChromeIfNeeded(self, _inst):
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700172 # Fully stub out for now.
173 pass
174
175
Ryan Cuief91e702013-02-04 12:06:36 -0800176class DeployTest(cros_test_lib.MockTempDirTestCase):
Steve Funge984a532013-11-25 17:09:25 -0800177 """Setup a deploy object with a GS-path for use in tests."""
178
Ryan Cuief91e702013-02-04 12:06:36 -0800179 def _GetDeployChrome(self, args):
Mike Frysingerc3061a62015-06-04 04:16:18 -0400180 options = _ParseCommandLine(args)
Ryan Cuia56a71e2012-10-18 18:40:35 -0700181 return deploy_chrome.DeployChrome(
182 options, self.tempdir, os.path.join(self.tempdir, 'staging'))
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700183
184 def setUp(self):
Ryan Cuif1416f32013-01-22 18:43:41 -0800185 self.deploy_mock = self.StartPatcher(DeployChromeMock())
Avery Musbach3edff0e2020-03-27 13:35:53 -0700186 self.deploy = self._GetDeployChrome(list(_REGULAR_TO) +
187 ['--board', _TARGET_BOARD, '--gs-path',
188 _GS_PATH, '--force', '--mount'])
Mike Frysingerfcca49e2021-03-17 01:09:20 -0400189 self.remote_reboot_mock = self.PatchObject(
190 remote_access.RemoteAccess, 'RemoteReboot', return_value=True)
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700191
Avery Musbach3edff0e2020-03-27 13:35:53 -0700192
193class TestCheckIfBoardMatches(DeployTest):
194 """Testing checking whether the DUT board matches the target board."""
195
196 def testMatchedBoard(self):
197 """Test the case where the DUT board matches the target board."""
198 self.PatchObject(remote_access.ChromiumOSDevice, 'board', _TARGET_BOARD)
199 self.assertTrue(self.deploy.options.force)
200 self.deploy._CheckBoard()
201 self.deploy.options.force = False
202 self.deploy._CheckBoard()
203
204 def testMismatchedBoard(self):
205 """Test the case where the DUT board does not match the target board."""
206 self.PatchObject(remote_access.ChromiumOSDevice, 'board', 'cedar')
207 self.assertTrue(self.deploy.options.force)
208 self.deploy._CheckBoard()
209 self.deploy.options.force = False
210 self.PatchObject(cros_build_lib, 'BooleanPrompt', return_value=True)
211 self.deploy._CheckBoard()
212 self.PatchObject(cros_build_lib, 'BooleanPrompt', return_value=False)
213 self.assertRaises(deploy_chrome.DeployFailure, self.deploy._CheckBoard)
214
215
David James88e6f032013-03-02 08:13:20 -0800216class TestDisableRootfsVerification(DeployTest):
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700217 """Testing disabling of rootfs verification and RO mode."""
218
David James88e6f032013-03-02 08:13:20 -0800219 def testDisableRootfsVerificationSuccess(self):
220 """Test the working case, disabling rootfs verification."""
221 self.deploy_mock.MockMountCmd(0)
222 self.deploy._DisableRootfsVerification()
Steven Bennettsca73efa2018-07-10 13:36:56 -0700223 self.assertFalse(self.deploy._root_dir_is_still_readonly.is_set())
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700224
225 def testDisableRootfsVerificationFailure(self):
226 """Test failure to disable rootfs verification."""
Mike Frysinger27e21b72018-07-12 14:20:21 -0400227 # pylint: disable=unused-argument
Shuqian Zhao14e61092017-11-17 00:02:16 +0000228 def RaiseRunCommandError(timeout_sec=None):
Mike Frysinger929f3ba2019-09-12 03:24:59 -0400229 raise cros_build_lib.RunCommandError('Mock RunCommandError')
Luigi Semenzato1bc79b22016-11-22 16:32:17 -0800230 self.remote_reboot_mock.side_effect = RaiseRunCommandError
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700231 self.assertRaises(cros_build_lib.RunCommandError,
David James88e6f032013-03-02 08:13:20 -0800232 self.deploy._DisableRootfsVerification)
Luigi Semenzato1bc79b22016-11-22 16:32:17 -0800233 self.remote_reboot_mock.side_effect = None
Steven Bennettsca73efa2018-07-10 13:36:56 -0700234 self.assertFalse(self.deploy._root_dir_is_still_readonly.is_set())
David James88e6f032013-03-02 08:13:20 -0800235
236
237class TestMount(DeployTest):
238 """Testing mount success and failure."""
239
240 def testSuccess(self):
241 """Test case where we are able to mount as writable."""
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 self.deploy_mock.MockMountCmd(0)
244 self.deploy._MountRootfsAsWritable()
Steven Bennettsca73efa2018-07-10 13:36:56 -0700245 self.assertFalse(self.deploy._root_dir_is_still_readonly.is_set())
David James88e6f032013-03-02 08:13:20 -0800246
247 def testMountError(self):
248 """Test that mount failure doesn't raise an exception by default."""
Steven Bennettsca73efa2018-07-10 13:36:56 -0700249 self.assertFalse(self.deploy._root_dir_is_still_readonly.is_set())
Avery Musbach3edff0e2020-03-27 13:35:53 -0700250 self.PatchObject(remote_access.ChromiumOSDevice, 'IsDirWritable',
Robert Flack1dc7ea82014-11-26 13:50:24 -0500251 return_value=False, autospec=True)
David James88e6f032013-03-02 08:13:20 -0800252 self.deploy._MountRootfsAsWritable()
Steven Bennettsca73efa2018-07-10 13:36:56 -0700253 self.assertTrue(self.deploy._root_dir_is_still_readonly.is_set())
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700254
255 def testMountRwFailure(self):
Mike Frysingerf5a3b2d2019-12-12 14:36:17 -0500256 """Test that mount failure raises an exception if check=True."""
David James88e6f032013-03-02 08:13:20 -0800257 self.assertRaises(cros_build_lib.RunCommandError,
Mike Frysingerf5a3b2d2019-12-12 14:36:17 -0500258 self.deploy._MountRootfsAsWritable, check=True)
Steven Bennettsca73efa2018-07-10 13:36:56 -0700259 self.assertFalse(self.deploy._root_dir_is_still_readonly.is_set())
Robert Flack1dc7ea82014-11-26 13:50:24 -0500260
261 def testMountTempDir(self):
262 """Test that mount succeeds if target dir is writable."""
Steven Bennettsca73efa2018-07-10 13:36:56 -0700263 self.assertFalse(self.deploy._root_dir_is_still_readonly.is_set())
Avery Musbach3edff0e2020-03-27 13:35:53 -0700264 self.PatchObject(remote_access.ChromiumOSDevice, 'IsDirWritable',
Robert Flack1dc7ea82014-11-26 13:50:24 -0500265 return_value=True, autospec=True)
266 self.deploy._MountRootfsAsWritable()
Steven Bennettsca73efa2018-07-10 13:36:56 -0700267 self.assertFalse(self.deploy._root_dir_is_still_readonly.is_set())
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700268
269
Anushruth8d797672019-10-17 12:22:31 -0700270class TestMountTarget(DeployTest):
Mike Frysingerdf1d0b02019-11-12 17:44:12 -0500271 """Testing mount and umount command handling."""
Anushruth8d797672019-10-17 12:22:31 -0700272
273 def testMountTargetUmountFailure(self):
274 """Test error being thrown if umount fails.
275
276 Test that 'lsof' is run on mount-dir and 'mount -rbind' command is not run
277 if 'umount' cmd fails.
278 """
279 mount_dir = self.deploy.options.mount_dir
280 target_dir = self.deploy.options.target_dir
281 self.deploy_mock.rsh_mock.AddCmdResult(
282 deploy_chrome._UMOUNT_DIR_IF_MOUNTPOINT_CMD %
283 {'dir': mount_dir}, returncode=errno.EBUSY, stderr='Target is Busy')
284 self.deploy_mock.rsh_mock.AddCmdResult(deploy_chrome.LSOF_COMMAND %
285 (mount_dir,), returncode=0,
286 stdout='process ' + mount_dir)
287 # Check for RunCommandError being thrown.
288 self.assertRaises(cros_build_lib.RunCommandError,
289 self.deploy._MountTarget)
290 # Check for the 'mount -rbind' command not run.
291 self.deploy_mock.rsh_mock.assertCommandContains(
292 (deploy_chrome._BIND_TO_FINAL_DIR_CMD % (target_dir, mount_dir)),
293 expected=False)
294 # Check for lsof command being called.
295 self.deploy_mock.rsh_mock.assertCommandContains(
296 (deploy_chrome.LSOF_COMMAND % (mount_dir,)))
297
298
Ryan Cuief91e702013-02-04 12:06:36 -0800299class TestUiJobStarted(DeployTest):
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700300 """Test detection of a running 'ui' job."""
301
Ryan Cuif2d1a582013-02-19 14:08:13 -0800302 def MockStatusUiCmd(self, **kwargs):
David Haddock3151d912017-10-24 03:50:32 +0000303 self.deploy_mock.rsh_mock.AddCmdResult('status ui', **kwargs)
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700304
305 def testUiJobStartedFalse(self):
306 """Correct results with a stopped job."""
Mike Frysinger876a8e52022-06-23 18:07:30 -0400307 self.MockStatusUiCmd(stdout='ui stop/waiting')
Ryan Cuif2d1a582013-02-19 14:08:13 -0800308 self.assertFalse(self.deploy._CheckUiJobStarted())
309
310 def testNoUiJob(self):
311 """Correct results when the job doesn't exist."""
Mike Frysinger876a8e52022-06-23 18:07:30 -0400312 self.MockStatusUiCmd(stderr='start: Unknown job: ui', returncode=1)
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700313 self.assertFalse(self.deploy._CheckUiJobStarted())
314
315 def testCheckRootfsWriteableTrue(self):
316 """Correct results with a running job."""
Mike Frysinger876a8e52022-06-23 18:07:30 -0400317 self.MockStatusUiCmd(stdout='ui start/running, process 297')
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700318 self.assertTrue(self.deploy._CheckUiJobStarted())
319
320
Ryan Cuief91e702013-02-04 12:06:36 -0800321class StagingTest(cros_test_lib.MockTempDirTestCase):
322 """Test user-mode and ebuild-mode staging functionality."""
323
324 def setUp(self):
Ryan Cuief91e702013-02-04 12:06:36 -0800325 self.staging_dir = os.path.join(self.tempdir, 'staging')
Jae Hoon Kimdf842912022-05-19 06:40:42 +0000326 osutils.SafeMakedirs(self.staging_dir)
327 self.staging_tarball_path = os.path.join(
328 self.tempdir, deploy_chrome._CHROME_DIR_STAGING_TARBALL_ZSTD)
Ryan Cuief91e702013-02-04 12:06:36 -0800329 self.build_dir = os.path.join(self.tempdir, 'build_dir')
Avery Musbach3edff0e2020-03-27 13:35:53 -0700330 self.common_flags = ['--board', _TARGET_BOARD,
331 '--build-dir', self.build_dir, '--staging-only',
Mike Frysinger3bb61cb2022-04-14 16:07:44 -0400332 '--cache-dir', str(self.tempdir)]
Ryan Cuia0215a72013-02-14 16:20:45 -0800333 self.sdk_mock = self.StartPatcher(cros_chrome_sdk_unittest.SDKFetcherMock())
Ryan Cui686ec052013-02-12 16:39:41 -0800334 self.PatchObject(
335 osutils, 'SourceEnvironment', autospec=True,
336 return_value={'STRIP': 'x86_64-cros-linux-gnu-strip'})
Ryan Cuief91e702013-02-04 12:06:36 -0800337
David Jamesa6e08892013-03-01 13:34:11 -0800338 def testSingleFileDeployFailure(self):
339 """Default staging enforces that mandatory files are copied"""
Mike Frysingerc3061a62015-06-04 04:16:18 -0400340 options = _ParseCommandLine(self.common_flags)
David Jamesa6e08892013-03-01 13:34:11 -0800341 osutils.Touch(os.path.join(self.build_dir, 'chrome'), makedirs=True)
342 self.assertRaises(
343 chrome_util.MissingPathError, deploy_chrome._PrepareStagingDir,
Daniel Eratc89829c2014-05-12 17:24:21 -0700344 options, self.tempdir, self.staging_dir, chrome_util._COPY_PATHS_CHROME)
Ryan Cuief91e702013-02-04 12:06:36 -0800345
David Jamesa6e08892013-03-01 13:34:11 -0800346 def testSloppyDeployFailure(self):
347 """Sloppy staging enforces that at least one file is copied."""
Mike Frysingerc3061a62015-06-04 04:16:18 -0400348 options = _ParseCommandLine(self.common_flags + ['--sloppy'])
David Jamesa6e08892013-03-01 13:34:11 -0800349 self.assertRaises(
350 chrome_util.MissingPathError, deploy_chrome._PrepareStagingDir,
Daniel Eratc89829c2014-05-12 17:24:21 -0700351 options, self.tempdir, self.staging_dir, chrome_util._COPY_PATHS_CHROME)
David Jamesa6e08892013-03-01 13:34:11 -0800352
353 def testSloppyDeploySuccess(self):
354 """Sloppy staging - stage one file."""
Mike Frysingerc3061a62015-06-04 04:16:18 -0400355 options = _ParseCommandLine(self.common_flags + ['--sloppy'])
David Jamesa6e08892013-03-01 13:34:11 -0800356 osutils.Touch(os.path.join(self.build_dir, 'chrome'), makedirs=True)
Steve Funge984a532013-11-25 17:09:25 -0800357 deploy_chrome._PrepareStagingDir(options, self.tempdir, self.staging_dir,
Daniel Eratc89829c2014-05-12 17:24:21 -0700358 chrome_util._COPY_PATHS_CHROME)
David Jamesa6e08892013-03-01 13:34:11 -0800359
Jae Hoon Kimdf842912022-05-19 06:40:42 +0000360 @cros_test_lib.pytestmark_network_test
361 def testUploadStagingDir(self):
362 """Upload staging directory."""
363 mockGsCopy = self.PatchObject(gs.GSContext, 'Copy')
364 staging_upload = 'gs://some-path'
365 options = _ParseCommandLine(
366 self.common_flags + ['--staging-upload', staging_upload])
367 osutils.Touch(os.path.join(self.build_dir, 'chrome'), makedirs=True)
368 deploy_chrome._UploadStagingDir(options, self.tempdir, self.staging_dir)
369 self.assertEqual(mockGsCopy.call_args_list, [
370 mock.call(self.staging_tarball_path, staging_upload, acl=''),
371 ])
372
373 @cros_test_lib.pytestmark_network_test
374 def testUploadStagingPublicReadACL(self):
375 """Upload staging directory with public-read ACL."""
376 mockGsCopy = self.PatchObject(gs.GSContext, 'Copy')
377 staging_upload = 'gs://some-path'
378 options = _ParseCommandLine(
379 self.common_flags +
380 ['--staging-upload', staging_upload, '--public-read'])
381 osutils.Touch(os.path.join(self.build_dir, 'chrome'), makedirs=True)
382 deploy_chrome._UploadStagingDir(options, self.tempdir, self.staging_dir)
383 self.assertEqual(mockGsCopy.call_args_list, [
384 mock.call(self.staging_tarball_path, staging_upload, acl='public-read'),
385 ])
386
Steve Funge984a532013-11-25 17:09:25 -0800387
388class DeployTestBuildDir(cros_test_lib.MockTempDirTestCase):
Daniel Erat1ae46382014-08-14 10:23:39 -0700389 """Set up a deploy object with a build-dir for use in deployment type tests"""
Steve Funge984a532013-11-25 17:09:25 -0800390
391 def _GetDeployChrome(self, args):
Mike Frysingerc3061a62015-06-04 04:16:18 -0400392 options = _ParseCommandLine(args)
Steve Funge984a532013-11-25 17:09:25 -0800393 return deploy_chrome.DeployChrome(
394 options, self.tempdir, os.path.join(self.tempdir, 'staging'))
395
396 def setUp(self):
397 self.staging_dir = os.path.join(self.tempdir, 'staging')
398 self.build_dir = os.path.join(self.tempdir, 'build_dir')
399 self.deploy_mock = self.StartPatcher(DeployChromeMock())
400 self.deploy = self._GetDeployChrome(
Avery Musbach3edff0e2020-03-27 13:35:53 -0700401 list(_REGULAR_TO) + ['--board', _TARGET_BOARD,
402 '--build-dir', self.build_dir, '--staging-only',
Mike Frysinger3bb61cb2022-04-14 16:07:44 -0400403 '--cache-dir', str(self.tempdir), '--sloppy'])
Steve Funge984a532013-11-25 17:09:25 -0800404
Daniel Erat1ae46382014-08-14 10:23:39 -0700405 def getCopyPath(self, source_path):
406 """Return a chrome_util.Path or None if not present."""
407 paths = [p for p in self.deploy.copy_paths if p.src == source_path]
408 return paths[0] if paths else None
Steve Funge984a532013-11-25 17:09:25 -0800409
Daniel Erat1ae46382014-08-14 10:23:39 -0700410class TestDeploymentType(DeployTestBuildDir):
Steve Funge984a532013-11-25 17:09:25 -0800411 """Test detection of deployment type using build dir."""
412
Daniel Erat1ae46382014-08-14 10:23:39 -0700413 def testAppShellDetection(self):
414 """Check for an app_shell deployment"""
415 osutils.Touch(os.path.join(self.deploy.options.build_dir, 'app_shell'),
Steve Funge984a532013-11-25 17:09:25 -0800416 makedirs=True)
417 self.deploy._CheckDeployType()
Daniel Erat1ae46382014-08-14 10:23:39 -0700418 self.assertTrue(self.getCopyPath('app_shell'))
419 self.assertFalse(self.getCopyPath('chrome'))
Steve Funge984a532013-11-25 17:09:25 -0800420
Daniel Erat1ae46382014-08-14 10:23:39 -0700421 def testChromeAndAppShellDetection(self):
Daniel Eratf53bd3a2016-12-02 11:28:36 -0700422 """Check for a chrome deployment when app_shell also exists."""
Steve Fung63d705d2014-03-16 03:14:03 -0700423 osutils.Touch(os.path.join(self.deploy.options.build_dir, 'chrome'),
424 makedirs=True)
Daniel Erat1ae46382014-08-14 10:23:39 -0700425 osutils.Touch(os.path.join(self.deploy.options.build_dir, 'app_shell'),
Steve Fung63d705d2014-03-16 03:14:03 -0700426 makedirs=True)
427 self.deploy._CheckDeployType()
Daniel Erat1ae46382014-08-14 10:23:39 -0700428 self.assertTrue(self.getCopyPath('chrome'))
Daniel Erat9813f0e2014-11-12 11:00:28 -0700429 self.assertFalse(self.getCopyPath('app_shell'))
Steve Fung63d705d2014-03-16 03:14:03 -0700430
Steve Funge984a532013-11-25 17:09:25 -0800431 def testChromeDetection(self):
432 """Check for a regular chrome deployment"""
433 osutils.Touch(os.path.join(self.deploy.options.build_dir, 'chrome'),
434 makedirs=True)
435 self.deploy._CheckDeployType()
Daniel Erat1ae46382014-08-14 10:23:39 -0700436 self.assertTrue(self.getCopyPath('chrome'))
Daniel Erat9813f0e2014-11-12 11:00:28 -0700437 self.assertFalse(self.getCopyPath('app_shell'))
Ben Pastenee484b342020-06-30 18:29:27 -0700438
439
440class TestDeployTestBinaries(cros_test_lib.RunCommandTempDirTestCase):
441 """Tests _DeployTestBinaries()."""
442
443 def setUp(self):
444 options = _ParseCommandLine(list(_REGULAR_TO) + [
445 '--board', _TARGET_BOARD, '--force', '--mount',
446 '--build-dir', os.path.join(self.tempdir, 'build_dir'),
447 '--nostrip'])
448 self.deploy = deploy_chrome.DeployChrome(
449 options, self.tempdir, os.path.join(self.tempdir, 'staging'))
450
Brian Sheedy86f12342020-10-29 15:30:02 -0700451 def _SimulateBinaries(self):
452 # Ensure the staging dir contains the right binaries to copy over.
Ben Pastenee484b342020-06-30 18:29:27 -0700453 test_binaries = [
454 'run_a_tests',
455 'run_b_tests',
456 'run_c_tests',
457 ]
458 # Simulate having the binaries both on the device and in our local build
459 # dir.
460 self.rc.AddCmdResult(
461 partial_mock.In(deploy_chrome._FIND_TEST_BIN_CMD),
462 stdout='\n'.join(test_binaries))
463 for binary in test_binaries:
464 osutils.Touch(os.path.join(self.deploy.options.build_dir, binary),
465 makedirs=True, mode=0o700)
Brian Sheedy86f12342020-10-29 15:30:02 -0700466 return test_binaries
Ben Pastenee484b342020-06-30 18:29:27 -0700467
Brian Sheedy86f12342020-10-29 15:30:02 -0700468 def _AssertBinariesInStagingDir(self, test_binaries):
Ben Pastenee484b342020-06-30 18:29:27 -0700469 # Ensure the binaries were placed in the staging dir used to copy them over.
470 staging_dir = os.path.join(
471 self.tempdir, os.path.basename(deploy_chrome._CHROME_TEST_BIN_DIR))
472 for binary in test_binaries:
473 self.assertIn(binary, os.listdir(staging_dir))
Erik Chen75a2f492020-08-06 19:15:11 -0700474
Brian Sheedy86f12342020-10-29 15:30:02 -0700475 def testFindError(self):
476 """Ensure an error is thrown if we can't inspect the device."""
477 self.rc.AddCmdResult(
478 partial_mock.In(deploy_chrome._FIND_TEST_BIN_CMD), 1)
479 self.assertRaises(
480 deploy_chrome.DeployFailure, self.deploy._DeployTestBinaries)
481
482 def testSuccess(self):
483 """Ensure that the happy path succeeds as expected."""
484 test_binaries = self._SimulateBinaries()
485 self.deploy._DeployTestBinaries()
486 self._AssertBinariesInStagingDir(test_binaries)
487
488 def testRetrySuccess(self):
489 """Ensure that a transient exception still results in success."""
490 # Raises a RunCommandError on its first invocation, but passes on subsequent
491 # calls.
492 def SideEffect(*args, **kwargs):
Yuke Liaobe6bac32020-12-26 22:16:49 -0800493 # pylint: disable=unused-argument
Brian Sheedy86f12342020-10-29 15:30:02 -0700494 if not SideEffect.called:
495 SideEffect.called = True
496 raise cros_build_lib.RunCommandError('fail')
497 SideEffect.called = False
498
499 test_binaries = self._SimulateBinaries()
500 with mock.patch.object(
501 remote_access.ChromiumOSDevice, 'CopyToDevice',
502 side_effect=SideEffect) as copy_mock:
503 self.deploy._DeployTestBinaries()
504 self.assertEqual(copy_mock.call_count, 2)
505 self._AssertBinariesInStagingDir(test_binaries)
506
507 def testRetryFailure(self):
508 """Ensure that consistent exceptions result in failure."""
509 self._SimulateBinaries()
510 with self.assertRaises(cros_build_lib.RunCommandError):
511 with mock.patch.object(
512 remote_access.ChromiumOSDevice, 'CopyToDevice',
513 side_effect=cros_build_lib.RunCommandError('fail')):
514 self.deploy._DeployTestBinaries()
515
Erik Chen75a2f492020-08-06 19:15:11 -0700516
517class LacrosPerformTest(cros_test_lib.RunCommandTempDirTestCase):
518 """Line coverage for Perform() method with --lacros option."""
519
520 def setUp(self):
Yuke Liao24fc60c2020-12-26 22:16:49 -0800521 self.deploy = None
522 self._ran_start_command = False
523 self.StartPatcher(parallel_unittest.ParallelMock())
524
525 def start_ui_side_effect(*args, **kwargs):
526 # pylint: disable=unused-argument
527 self._ran_start_command = True
528
529 self.rc.AddCmdResult(partial_mock.In('start ui'),
530 side_effect=start_ui_side_effect)
531
532 def prepareDeploy(self, options=None):
533 if not options:
534 options = _ParseCommandLine([
535 '--lacros', '--nostrip', '--build-dir', '/path/to/nowhere',
536 '--device', 'monkey'
537 ])
Erik Chen75a2f492020-08-06 19:15:11 -0700538 self.deploy = deploy_chrome.DeployChrome(
539 options, self.tempdir, os.path.join(self.tempdir, 'staging'))
540
541 # These methods being mocked are all side effects expected for a --lacros
542 # deploy.
543 self.deploy._EnsureTargetDir = mock.Mock()
544 self.deploy._GetDeviceInfo = mock.Mock()
545 self.deploy._CheckConnection = mock.Mock()
546 self.deploy._MountRootfsAsWritable = mock.Mock()
547 self.deploy._PrepareStagingDir = mock.Mock()
548 self.deploy._CheckDeviceFreeSpace = mock.Mock()
Yuke Liaobe6bac32020-12-26 22:16:49 -0800549 self.deploy._KillAshChromeIfNeeded = mock.Mock()
Erik Chen75a2f492020-08-06 19:15:11 -0700550
551 def testConfNotModified(self):
552 """When the conf file is not modified we don't restart chrome ."""
Yuke Liao24fc60c2020-12-26 22:16:49 -0800553 self.prepareDeploy()
Erik Chen75a2f492020-08-06 19:15:11 -0700554 self.deploy.Perform()
555 self.deploy._KillAshChromeIfNeeded.assert_not_called()
556 self.assertFalse(self._ran_start_command)
557
558 def testConfModified(self):
559 """When the conf file is modified we restart chrome."""
Yuke Liao24fc60c2020-12-26 22:16:49 -0800560 self.prepareDeploy()
Erik Chen75a2f492020-08-06 19:15:11 -0700561
562 # We intentionally add '\n' to MODIFIED_CONF_FILE to simulate echo adding a
563 # newline when invoked in the shell.
564 self.rc.AddCmdResult(
565 partial_mock.In(deploy_chrome.ENABLE_LACROS_VIA_CONF_COMMAND),
566 stdout=deploy_chrome.MODIFIED_CONF_FILE + '\n')
567
568 self.deploy.Perform()
569 self.deploy._KillAshChromeIfNeeded.assert_called()
570 self.assertTrue(self._ran_start_command)
Yuke Liao24fc60c2020-12-26 22:16:49 -0800571
572 def testSkipModifyingConf(self):
573 """SKip modifying the config file when the argument is specified."""
574 self.prepareDeploy(
575 _ParseCommandLine([
576 '--lacros', '--nostrip', '--build-dir', '/path/to/nowhere',
577 '--device', 'monkey', '--skip-modifying-config-file'
578 ]))
579
580 self.rc.AddCmdResult(
581 partial_mock.In(deploy_chrome.ENABLE_LACROS_VIA_CONF_COMMAND),
582 stdout=deploy_chrome.MODIFIED_CONF_FILE + '\n')
583
584 self.deploy.Perform()
585 self.deploy._KillAshChromeIfNeeded.assert_not_called()
586 self.assertFalse(self._ran_start_command)