blob: 872ed8ec9f15f4ca8c09fadff619fbe6b4bc12d3 [file] [log] [blame]
Mike Frysingere58c0e22017-10-04 15:43:30 -04001# -*- coding: utf-8 -*-
Ryan Cuiafd6c5c2012-07-30 17:48:22 -07002# 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 Frysinger383367e2014-09-16 15:06:17 -04008from __future__ import print_function
9
Mike Frysingerea838d12014-12-08 11:55:32 -050010import mock
Ryan Cuiafd6c5c2012-07-30 17:48:22 -070011import os
David James88e6f032013-03-02 08:13:20 -080012import time
Ryan Cuiafd6c5c2012-07-30 17:48:22 -070013
David Pursellcfd58872015-03-19 09:15:48 -070014from chromite.cli.cros 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
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
Ryan Cuiafd6c5c2012-07-30 17:48:22 -070025# pylint: disable=W0212
26
27_REGULAR_TO = ('--to', 'monkey')
28_GS_PATH = 'gs://foon'
29
30
31def _ParseCommandLine(argv):
32 return deploy_chrome._ParseCommandLine(['--log-level', 'debug'] + argv)
33
34
35class InterfaceTest(cros_test_lib.OutputTestCase):
36 """Tests the commandline interface of the script."""
37
Ryan Cui686ec052013-02-12 16:39:41 -080038 BOARD = 'lumpy'
39
Ryan Cuiafd6c5c2012-07-30 17:48:22 -070040 def testGsLocalPathUnSpecified(self):
41 """Test no chrome path specified."""
42 with self.OutputCapturer():
43 self.assertRaises2(SystemExit, _ParseCommandLine, list(_REGULAR_TO),
44 check_attrs={'code': 2})
45
46 def testGsPathSpecified(self):
47 """Test case of GS path specified."""
48 argv = list(_REGULAR_TO) + ['--gs-path', _GS_PATH]
49 _ParseCommandLine(argv)
50
51 def testLocalPathSpecified(self):
52 """Test case of local path specified."""
Mike Frysingerd6e2df02014-11-26 02:55:04 -050053 argv = list(_REGULAR_TO) + ['--local-pkg-path', '/path/to/chrome']
Ryan Cuiafd6c5c2012-07-30 17:48:22 -070054 _ParseCommandLine(argv)
55
56 def testNoTarget(self):
57 """Test no target specified."""
58 argv = ['--gs-path', _GS_PATH]
Ryan Cuief91e702013-02-04 12:06:36 -080059 self.assertParseError(argv)
60
61 def assertParseError(self, argv):
Ryan Cuiafd6c5c2012-07-30 17:48:22 -070062 with self.OutputCapturer():
63 self.assertRaises2(SystemExit, _ParseCommandLine, argv,
64 check_attrs={'code': 2})
65
Ryan Cui686ec052013-02-12 16:39:41 -080066 def testNoBoardBuildDir(self):
67 argv = ['--staging-only', '--build-dir=/path/to/nowhere']
68 self.assertParseError(argv)
69
Thiago Goncales12793312013-05-23 11:26:17 -070070 def testMountOptionSetsTargetDir(self):
71 argv = list(_REGULAR_TO) + ['--gs-path', _GS_PATH, '--mount']
Mike Frysingerc3061a62015-06-04 04:16:18 -040072 options = _ParseCommandLine(argv)
Thiago Goncales12793312013-05-23 11:26:17 -070073 self.assertIsNot(options.target_dir, None)
74
75 def testMountOptionSetsMountDir(self):
76 argv = list(_REGULAR_TO) + ['--gs-path', _GS_PATH, '--mount']
Mike Frysingerc3061a62015-06-04 04:16:18 -040077 options = _ParseCommandLine(argv)
Thiago Goncales12793312013-05-23 11:26:17 -070078 self.assertIsNot(options.mount_dir, None)
79
80 def testMountOptionDoesNotOverrideTargetDir(self):
81 argv = list(_REGULAR_TO) + ['--gs-path', _GS_PATH, '--mount',
82 '--target-dir', '/foo/bar/cow']
Mike Frysingerc3061a62015-06-04 04:16:18 -040083 options = _ParseCommandLine(argv)
Thiago Goncales12793312013-05-23 11:26:17 -070084 self.assertEqual(options.target_dir, '/foo/bar/cow')
85
86 def testMountOptionDoesNotOverrideMountDir(self):
87 argv = list(_REGULAR_TO) + ['--gs-path', _GS_PATH, '--mount',
88 '--mount-dir', '/foo/bar/cow']
Mike Frysingerc3061a62015-06-04 04:16:18 -040089 options = _ParseCommandLine(argv)
Thiago Goncales12793312013-05-23 11:26:17 -070090 self.assertEqual(options.mount_dir, '/foo/bar/cow')
91
Ryan Cuiafd6c5c2012-07-30 17:48:22 -070092
93class DeployChromeMock(partial_mock.PartialMock):
Steve Funge984a532013-11-25 17:09:25 -080094 """Deploy Chrome Mock Class."""
Ryan Cuiafd6c5c2012-07-30 17:48:22 -070095
96 TARGET = 'chromite.scripts.deploy_chrome.DeployChrome'
David James88e6f032013-03-02 08:13:20 -080097 ATTRS = ('_KillProcsIfNeeded', '_DisableRootfsVerification')
Ryan Cuiafd6c5c2012-07-30 17:48:22 -070098
David James88e6f032013-03-02 08:13:20 -080099 def __init__(self):
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700100 partial_mock.PartialMock.__init__(self)
Robert Flack1dc7ea82014-11-26 13:50:24 -0500101 self.remote_device_mock = remote_access_unittest.RemoteDeviceMock()
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700102 # Target starts off as having rootfs verification enabled.
Ryan Cuie18f24f2012-12-03 18:39:55 -0800103 self.rsh_mock = remote_access_unittest.RemoteShMock()
David James88e6f032013-03-02 08:13:20 -0800104 self.rsh_mock.SetDefaultCmdResult(0)
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700105 self.MockMountCmd(1)
David Haddock3151d912017-10-24 03:50:32 +0000106 self.rsh_mock.AddCmdResult(
107 deploy_chrome.LSOF_COMMAND % (deploy_chrome._CHROME_DIR,), 1)
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700108
109 def MockMountCmd(self, returnvalue):
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700110 self.rsh_mock.AddCmdResult(deploy_chrome.MOUNT_RW_COMMAND,
David James88e6f032013-03-02 08:13:20 -0800111 returnvalue)
112
113 def _DisableRootfsVerification(self, inst):
114 with mock.patch.object(time, 'sleep'):
115 self.backup['_DisableRootfsVerification'](inst)
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700116
Ryan Cui4d6fca92012-12-13 16:41:56 -0800117 def PreStart(self):
Robert Flack1dc7ea82014-11-26 13:50:24 -0500118 self.remote_device_mock.start()
Ryan Cui4d6fca92012-12-13 16:41:56 -0800119 self.rsh_mock.start()
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700120
Ryan Cui4d6fca92012-12-13 16:41:56 -0800121 def PreStop(self):
122 self.rsh_mock.stop()
Robert Flack1dc7ea82014-11-26 13:50:24 -0500123 self.remote_device_mock.stop()
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700124
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700125 def _KillProcsIfNeeded(self, _inst):
126 # Fully stub out for now.
127 pass
128
129
Ryan Cuief91e702013-02-04 12:06:36 -0800130class DeployTest(cros_test_lib.MockTempDirTestCase):
Steve Funge984a532013-11-25 17:09:25 -0800131 """Setup a deploy object with a GS-path for use in tests."""
132
Ryan Cuief91e702013-02-04 12:06:36 -0800133 def _GetDeployChrome(self, args):
Mike Frysingerc3061a62015-06-04 04:16:18 -0400134 options = _ParseCommandLine(args)
Ryan Cuia56a71e2012-10-18 18:40:35 -0700135 return deploy_chrome.DeployChrome(
136 options, self.tempdir, os.path.join(self.tempdir, 'staging'))
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700137
138 def setUp(self):
Ryan Cuif1416f32013-01-22 18:43:41 -0800139 self.deploy_mock = self.StartPatcher(DeployChromeMock())
Ryan Cuief91e702013-02-04 12:06:36 -0800140 self.deploy = self._GetDeployChrome(
David James88e6f032013-03-02 08:13:20 -0800141 list(_REGULAR_TO) + ['--gs-path', _GS_PATH, '--force'])
Luigi Semenzato1bc79b22016-11-22 16:32:17 -0800142 self.remote_reboot_mock = \
143 self.PatchObject(remote_access.RemoteAccess, 'RemoteReboot',
144 return_value=True)
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700145
David James88e6f032013-03-02 08:13:20 -0800146class TestDisableRootfsVerification(DeployTest):
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700147 """Testing disabling of rootfs verification and RO mode."""
148
David James88e6f032013-03-02 08:13:20 -0800149 def testDisableRootfsVerificationSuccess(self):
150 """Test the working case, disabling rootfs verification."""
151 self.deploy_mock.MockMountCmd(0)
152 self.deploy._DisableRootfsVerification()
Robert Flack1dc7ea82014-11-26 13:50:24 -0500153 self.assertFalse(self.deploy._target_dir_is_still_readonly.is_set())
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700154
155 def testDisableRootfsVerificationFailure(self):
156 """Test failure to disable rootfs verification."""
Luigi Semenzato1bc79b22016-11-22 16:32:17 -0800157 #pylint: disable=unused-argument
158 def RaiseRunCommandError(timeout_sec=None):
159 raise cros_build_lib.RunCommandError('Mock RunCommandError', 0)
160 self.remote_reboot_mock.side_effect = RaiseRunCommandError
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700161 self.assertRaises(cros_build_lib.RunCommandError,
David James88e6f032013-03-02 08:13:20 -0800162 self.deploy._DisableRootfsVerification)
Luigi Semenzato1bc79b22016-11-22 16:32:17 -0800163 self.remote_reboot_mock.side_effect = None
Robert Flack1dc7ea82014-11-26 13:50:24 -0500164 self.assertFalse(self.deploy._target_dir_is_still_readonly.is_set())
David James88e6f032013-03-02 08:13:20 -0800165
166
167class TestMount(DeployTest):
168 """Testing mount success and failure."""
169
170 def testSuccess(self):
171 """Test case where we are able to mount as writable."""
Robert Flack1dc7ea82014-11-26 13:50:24 -0500172 self.assertFalse(self.deploy._target_dir_is_still_readonly.is_set())
David James88e6f032013-03-02 08:13:20 -0800173 self.deploy_mock.MockMountCmd(0)
174 self.deploy._MountRootfsAsWritable()
Robert Flack1dc7ea82014-11-26 13:50:24 -0500175 self.assertFalse(self.deploy._target_dir_is_still_readonly.is_set())
David James88e6f032013-03-02 08:13:20 -0800176
177 def testMountError(self):
178 """Test that mount failure doesn't raise an exception by default."""
Robert Flack1dc7ea82014-11-26 13:50:24 -0500179 self.assertFalse(self.deploy._target_dir_is_still_readonly.is_set())
Mike Frysinger74ccd572015-05-21 21:18:20 -0400180 self.PatchObject(remote_access.RemoteDevice, 'IsDirWritable',
Robert Flack1dc7ea82014-11-26 13:50:24 -0500181 return_value=False, autospec=True)
David James88e6f032013-03-02 08:13:20 -0800182 self.deploy._MountRootfsAsWritable()
Robert Flack1dc7ea82014-11-26 13:50:24 -0500183 self.assertTrue(self.deploy._target_dir_is_still_readonly.is_set())
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700184
185 def testMountRwFailure(self):
David James88e6f032013-03-02 08:13:20 -0800186 """Test that mount failure raises an exception if error_code_ok=False."""
187 self.assertRaises(cros_build_lib.RunCommandError,
188 self.deploy._MountRootfsAsWritable, error_code_ok=False)
Robert Flack1dc7ea82014-11-26 13:50:24 -0500189 self.assertFalse(self.deploy._target_dir_is_still_readonly.is_set())
190
191 def testMountTempDir(self):
192 """Test that mount succeeds if target dir is writable."""
193 self.assertFalse(self.deploy._target_dir_is_still_readonly.is_set())
Mike Frysinger74ccd572015-05-21 21:18:20 -0400194 self.PatchObject(remote_access.RemoteDevice, 'IsDirWritable',
Robert Flack1dc7ea82014-11-26 13:50:24 -0500195 return_value=True, autospec=True)
196 self.deploy._MountRootfsAsWritable()
197 self.assertFalse(self.deploy._target_dir_is_still_readonly.is_set())
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700198
199
Ryan Cuief91e702013-02-04 12:06:36 -0800200class TestUiJobStarted(DeployTest):
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700201 """Test detection of a running 'ui' job."""
202
Ryan Cuif2d1a582013-02-19 14:08:13 -0800203 def MockStatusUiCmd(self, **kwargs):
David Haddock3151d912017-10-24 03:50:32 +0000204 self.deploy_mock.rsh_mock.AddCmdResult('status ui', **kwargs)
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700205
206 def testUiJobStartedFalse(self):
207 """Correct results with a stopped job."""
Ryan Cuif2d1a582013-02-19 14:08:13 -0800208 self.MockStatusUiCmd(output='ui stop/waiting')
209 self.assertFalse(self.deploy._CheckUiJobStarted())
210
211 def testNoUiJob(self):
212 """Correct results when the job doesn't exist."""
213 self.MockStatusUiCmd(error='start: Unknown job: ui', returncode=1)
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700214 self.assertFalse(self.deploy._CheckUiJobStarted())
215
216 def testCheckRootfsWriteableTrue(self):
217 """Correct results with a running job."""
Ryan Cuif2d1a582013-02-19 14:08:13 -0800218 self.MockStatusUiCmd(output='ui start/running, process 297')
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700219 self.assertTrue(self.deploy._CheckUiJobStarted())
220
221
Ryan Cuief91e702013-02-04 12:06:36 -0800222class StagingTest(cros_test_lib.MockTempDirTestCase):
223 """Test user-mode and ebuild-mode staging functionality."""
224
225 def setUp(self):
Ryan Cuief91e702013-02-04 12:06:36 -0800226 self.staging_dir = os.path.join(self.tempdir, 'staging')
227 self.build_dir = os.path.join(self.tempdir, 'build_dir')
Ryan Cui686ec052013-02-12 16:39:41 -0800228 self.common_flags = ['--build-dir', self.build_dir,
229 '--board=lumpy', '--staging-only', '--cache-dir',
230 self.tempdir]
Ryan Cuia0215a72013-02-14 16:20:45 -0800231 self.sdk_mock = self.StartPatcher(cros_chrome_sdk_unittest.SDKFetcherMock())
Ryan Cui686ec052013-02-12 16:39:41 -0800232 self.PatchObject(
233 osutils, 'SourceEnvironment', autospec=True,
234 return_value={'STRIP': 'x86_64-cros-linux-gnu-strip'})
Ryan Cuief91e702013-02-04 12:06:36 -0800235
David Jamesa6e08892013-03-01 13:34:11 -0800236 def testSingleFileDeployFailure(self):
237 """Default staging enforces that mandatory files are copied"""
Mike Frysingerc3061a62015-06-04 04:16:18 -0400238 options = _ParseCommandLine(self.common_flags)
David Jamesa6e08892013-03-01 13:34:11 -0800239 osutils.Touch(os.path.join(self.build_dir, 'chrome'), makedirs=True)
240 self.assertRaises(
241 chrome_util.MissingPathError, deploy_chrome._PrepareStagingDir,
Daniel Eratc89829c2014-05-12 17:24:21 -0700242 options, self.tempdir, self.staging_dir, chrome_util._COPY_PATHS_CHROME)
Ryan Cuief91e702013-02-04 12:06:36 -0800243
David Jamesa6e08892013-03-01 13:34:11 -0800244 def testSloppyDeployFailure(self):
245 """Sloppy staging enforces that at least one file is copied."""
Mike Frysingerc3061a62015-06-04 04:16:18 -0400246 options = _ParseCommandLine(self.common_flags + ['--sloppy'])
David Jamesa6e08892013-03-01 13:34:11 -0800247 self.assertRaises(
248 chrome_util.MissingPathError, deploy_chrome._PrepareStagingDir,
Daniel Eratc89829c2014-05-12 17:24:21 -0700249 options, self.tempdir, self.staging_dir, chrome_util._COPY_PATHS_CHROME)
David Jamesa6e08892013-03-01 13:34:11 -0800250
251 def testSloppyDeploySuccess(self):
252 """Sloppy staging - stage one file."""
Mike Frysingerc3061a62015-06-04 04:16:18 -0400253 options = _ParseCommandLine(self.common_flags + ['--sloppy'])
David Jamesa6e08892013-03-01 13:34:11 -0800254 osutils.Touch(os.path.join(self.build_dir, 'chrome'), makedirs=True)
Steve Funge984a532013-11-25 17:09:25 -0800255 deploy_chrome._PrepareStagingDir(options, self.tempdir, self.staging_dir,
Daniel Eratc89829c2014-05-12 17:24:21 -0700256 chrome_util._COPY_PATHS_CHROME)
David Jamesa6e08892013-03-01 13:34:11 -0800257
Steve Funge984a532013-11-25 17:09:25 -0800258
259class DeployTestBuildDir(cros_test_lib.MockTempDirTestCase):
Daniel Erat1ae46382014-08-14 10:23:39 -0700260 """Set up a deploy object with a build-dir for use in deployment type tests"""
Steve Funge984a532013-11-25 17:09:25 -0800261
262 def _GetDeployChrome(self, args):
Mike Frysingerc3061a62015-06-04 04:16:18 -0400263 options = _ParseCommandLine(args)
Steve Funge984a532013-11-25 17:09:25 -0800264 return deploy_chrome.DeployChrome(
265 options, self.tempdir, os.path.join(self.tempdir, 'staging'))
266
267 def setUp(self):
268 self.staging_dir = os.path.join(self.tempdir, 'staging')
269 self.build_dir = os.path.join(self.tempdir, 'build_dir')
270 self.deploy_mock = self.StartPatcher(DeployChromeMock())
271 self.deploy = self._GetDeployChrome(
272 list(_REGULAR_TO) + ['--build-dir', self.build_dir,
273 '--board=lumpy', '--staging-only', '--cache-dir',
274 self.tempdir, '--sloppy'])
275
Daniel Erat1ae46382014-08-14 10:23:39 -0700276 def getCopyPath(self, source_path):
277 """Return a chrome_util.Path or None if not present."""
278 paths = [p for p in self.deploy.copy_paths if p.src == source_path]
279 return paths[0] if paths else None
Steve Funge984a532013-11-25 17:09:25 -0800280
Daniel Erat1ae46382014-08-14 10:23:39 -0700281class TestDeploymentType(DeployTestBuildDir):
Steve Funge984a532013-11-25 17:09:25 -0800282 """Test detection of deployment type using build dir."""
283
Daniel Erat1ae46382014-08-14 10:23:39 -0700284 def testAppShellDetection(self):
285 """Check for an app_shell deployment"""
286 osutils.Touch(os.path.join(self.deploy.options.build_dir, 'app_shell'),
Steve Funge984a532013-11-25 17:09:25 -0800287 makedirs=True)
288 self.deploy._CheckDeployType()
Daniel Erat1ae46382014-08-14 10:23:39 -0700289 self.assertTrue(self.getCopyPath('app_shell'))
290 self.assertFalse(self.getCopyPath('chrome'))
Steve Funge984a532013-11-25 17:09:25 -0800291
Daniel Erat1ae46382014-08-14 10:23:39 -0700292 def testChromeAndAppShellDetection(self):
Daniel Eratf53bd3a2016-12-02 11:28:36 -0700293 """Check for a chrome deployment when app_shell also exists."""
Steve Fung63d705d2014-03-16 03:14:03 -0700294 osutils.Touch(os.path.join(self.deploy.options.build_dir, 'chrome'),
295 makedirs=True)
Daniel Erat1ae46382014-08-14 10:23:39 -0700296 osutils.Touch(os.path.join(self.deploy.options.build_dir, 'app_shell'),
Steve Fung63d705d2014-03-16 03:14:03 -0700297 makedirs=True)
298 self.deploy._CheckDeployType()
Daniel Erat1ae46382014-08-14 10:23:39 -0700299 self.assertTrue(self.getCopyPath('chrome'))
Daniel Erat9813f0e2014-11-12 11:00:28 -0700300 self.assertFalse(self.getCopyPath('app_shell'))
Steve Fung63d705d2014-03-16 03:14:03 -0700301
Steve Funge984a532013-11-25 17:09:25 -0800302 def testChromeDetection(self):
303 """Check for a regular chrome deployment"""
304 osutils.Touch(os.path.join(self.deploy.options.build_dir, 'chrome'),
305 makedirs=True)
306 self.deploy._CheckDeployType()
Daniel Erat1ae46382014-08-14 10:23:39 -0700307 self.assertTrue(self.getCopyPath('chrome'))
Daniel Erat9813f0e2014-11-12 11:00:28 -0700308 self.assertFalse(self.getCopyPath('app_shell'))