blob: 87898a94a6cecca48c9d7160b2125f85faf4ef3f [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 Frysinger383367e2014-09-16 15:06:17 -04008from __future__ import print_function
9
Ryan Cuiafd6c5c2012-07-30 17:48:22 -070010import os
11import sys
David James88e6f032013-03-02 08:13:20 -080012import time
Ryan Cuiafd6c5c2012-07-30 17:48:22 -070013
14sys.path.insert(0, os.path.join(os.path.dirname(os.path.realpath(__file__)),
15 '..', '..'))
Ryan Cuief91e702013-02-04 12:06:36 -080016
Ryan Cui686ec052013-02-12 16:39:41 -080017from chromite.cros.commands import cros_chrome_sdk_unittest
Ryan Cuief91e702013-02-04 12:06:36 -080018from chromite.lib import chrome_util
Ryan Cuiafd6c5c2012-07-30 17:48:22 -070019from chromite.lib import cros_build_lib
20from chromite.lib import cros_test_lib
Ryan Cui686ec052013-02-12 16:39:41 -080021from chromite.lib import osutils
Ryan Cuiafd6c5c2012-07-30 17:48:22 -070022from chromite.lib import partial_mock
23from chromite.lib import remote_access_unittest
Ryan Cuicbd9bb62013-04-30 11:17:02 -070024from chromite.lib import stats
25from chromite.lib import stats_unittest
26
Ryan Cuiafd6c5c2012-07-30 17:48:22 -070027from chromite.scripts import deploy_chrome
28
Ryan Cuief91e702013-02-04 12:06:36 -080029
Brian Harringe7524372012-12-23 02:02:56 -080030# TODO(build): Finish test wrapper (http://crosbug.com/37517).
31# Until then, this has to be after the chromite imports.
32import mock
33
Ryan Cuiafd6c5c2012-07-30 17:48:22 -070034
35# pylint: disable=W0212
36
37_REGULAR_TO = ('--to', 'monkey')
38_GS_PATH = 'gs://foon'
39
40
41def _ParseCommandLine(argv):
42 return deploy_chrome._ParseCommandLine(['--log-level', 'debug'] + argv)
43
44
45class InterfaceTest(cros_test_lib.OutputTestCase):
46 """Tests the commandline interface of the script."""
47
Ryan Cui686ec052013-02-12 16:39:41 -080048 BOARD = 'lumpy'
49
Ryan Cuiafd6c5c2012-07-30 17:48:22 -070050 def testGsLocalPathUnSpecified(self):
51 """Test no chrome path specified."""
52 with self.OutputCapturer():
53 self.assertRaises2(SystemExit, _ParseCommandLine, list(_REGULAR_TO),
54 check_attrs={'code': 2})
55
56 def testGsPathSpecified(self):
57 """Test case of GS path specified."""
58 argv = list(_REGULAR_TO) + ['--gs-path', _GS_PATH]
59 _ParseCommandLine(argv)
60
61 def testLocalPathSpecified(self):
62 """Test case of local path specified."""
Ryan Cuia56a71e2012-10-18 18:40:35 -070063 argv = list(_REGULAR_TO) + ['--local-pkg-path', '/path/to/chrome']
Ryan Cuiafd6c5c2012-07-30 17:48:22 -070064 _ParseCommandLine(argv)
65
66 def testNoTarget(self):
67 """Test no target specified."""
68 argv = ['--gs-path', _GS_PATH]
Ryan Cuief91e702013-02-04 12:06:36 -080069 self.assertParseError(argv)
70
71 def assertParseError(self, argv):
Ryan Cuiafd6c5c2012-07-30 17:48:22 -070072 with self.OutputCapturer():
73 self.assertRaises2(SystemExit, _ParseCommandLine, argv,
74 check_attrs={'code': 2})
75
Ryan Cuief91e702013-02-04 12:06:36 -080076 def testStagingFlagsNoStrict(self):
77 """Errors out when --staging-flags is set without --strict."""
78 argv = ['--staging-only', '--build-dir=/path/to/nowhere',
Ryan Cui686ec052013-02-12 16:39:41 -080079 '--board=%s' % self.BOARD, '--staging-flags=highdpi']
Ryan Cuief91e702013-02-04 12:06:36 -080080 self.assertParseError(argv)
81
82 def testStrictNoBuildDir(self):
83 """Errors out when --strict is set without --build-dir."""
84 argv = ['--staging-only', '--strict', '--gs-path', _GS_PATH]
85 self.assertParseError(argv)
86
Ryan Cui686ec052013-02-12 16:39:41 -080087 def testNoBoardBuildDir(self):
88 argv = ['--staging-only', '--build-dir=/path/to/nowhere']
89 self.assertParseError(argv)
90
Thiago Goncales12793312013-05-23 11:26:17 -070091 def testMountOptionSetsTargetDir(self):
92 argv = list(_REGULAR_TO) + ['--gs-path', _GS_PATH, '--mount']
93 options, _ = _ParseCommandLine(argv)
94 self.assertIsNot(options.target_dir, None)
95
96 def testMountOptionSetsMountDir(self):
97 argv = list(_REGULAR_TO) + ['--gs-path', _GS_PATH, '--mount']
98 options, _ = _ParseCommandLine(argv)
99 self.assertIsNot(options.mount_dir, None)
100
101 def testMountOptionDoesNotOverrideTargetDir(self):
102 argv = list(_REGULAR_TO) + ['--gs-path', _GS_PATH, '--mount',
103 '--target-dir', '/foo/bar/cow']
104 options, _ = _ParseCommandLine(argv)
105 self.assertEqual(options.target_dir, '/foo/bar/cow')
106
107 def testMountOptionDoesNotOverrideMountDir(self):
108 argv = list(_REGULAR_TO) + ['--gs-path', _GS_PATH, '--mount',
109 '--mount-dir', '/foo/bar/cow']
110 options, _ = _ParseCommandLine(argv)
111 self.assertEqual(options.mount_dir, '/foo/bar/cow')
112
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700113
114class DeployChromeMock(partial_mock.PartialMock):
Steve Funge984a532013-11-25 17:09:25 -0800115 """Deploy Chrome Mock Class."""
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700116
117 TARGET = 'chromite.scripts.deploy_chrome.DeployChrome'
David James88e6f032013-03-02 08:13:20 -0800118 ATTRS = ('_KillProcsIfNeeded', '_DisableRootfsVerification')
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700119
David James88e6f032013-03-02 08:13:20 -0800120 def __init__(self):
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700121 partial_mock.PartialMock.__init__(self)
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700122 # Target starts off as having rootfs verification enabled.
Ryan Cuie18f24f2012-12-03 18:39:55 -0800123 self.rsh_mock = remote_access_unittest.RemoteShMock()
David James88e6f032013-03-02 08:13:20 -0800124 self.rsh_mock.SetDefaultCmdResult(0)
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700125 self.MockMountCmd(1)
Pawel Osciak577773a2013-03-05 10:52:12 -0800126 self.rsh_mock.AddCmdResult(
127 deploy_chrome.LSOF_COMMAND % (deploy_chrome._CHROME_DIR,), 1)
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700128
129 def MockMountCmd(self, returnvalue):
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700130 self.rsh_mock.AddCmdResult(deploy_chrome.MOUNT_RW_COMMAND,
David James88e6f032013-03-02 08:13:20 -0800131 returnvalue)
132
133 def _DisableRootfsVerification(self, inst):
134 with mock.patch.object(time, 'sleep'):
135 self.backup['_DisableRootfsVerification'](inst)
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700136
Ryan Cui4d6fca92012-12-13 16:41:56 -0800137 def PreStart(self):
138 self.rsh_mock.start()
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700139
Ryan Cui4d6fca92012-12-13 16:41:56 -0800140 def PreStop(self):
141 self.rsh_mock.stop()
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700142
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700143 def _KillProcsIfNeeded(self, _inst):
144 # Fully stub out for now.
145 pass
146
147
Ryan Cuicbd9bb62013-04-30 11:17:02 -0700148class MainTest(cros_test_lib.MockLoggingTestCase):
Steve Funge984a532013-11-25 17:09:25 -0800149 """Main tests."""
Ryan Cuicbd9bb62013-04-30 11:17:02 -0700150
151 def setUp(self):
152 self.PatchObject(deploy_chrome.DeployChrome, 'Perform', autospec=True)
153 self.stats_module_mock = stats_unittest.StatsModuleMock()
154 self.StartPatcher(self.stats_module_mock)
155
156 def testStatsUpload(self, call_count=1):
157 """The stats upload path."""
158 deploy_chrome.main(['--board=lumpy', '--staging-only',
159 '--build-dir=/tmp/abc'])
160 self.assertEquals(stats.StatsUploader._Upload.call_count, call_count)
161
162 def testStatsUploadError(self):
163 """Don't upload stats if we fail to create it."""
164 self.stats_module_mock.stats_mock.init_exception = True
165 with cros_test_lib.LoggingCapturer():
166 self.testStatsUpload(call_count=0)
167
168
Ryan Cuief91e702013-02-04 12:06:36 -0800169class DeployTest(cros_test_lib.MockTempDirTestCase):
Steve Funge984a532013-11-25 17:09:25 -0800170 """Setup a deploy object with a GS-path for use in tests."""
171
Ryan Cuief91e702013-02-04 12:06:36 -0800172 def _GetDeployChrome(self, args):
173 options, _ = _ParseCommandLine(args)
Ryan Cuia56a71e2012-10-18 18:40:35 -0700174 return deploy_chrome.DeployChrome(
175 options, self.tempdir, os.path.join(self.tempdir, 'staging'))
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700176
177 def setUp(self):
Ryan Cuif1416f32013-01-22 18:43:41 -0800178 self.deploy_mock = self.StartPatcher(DeployChromeMock())
Ryan Cuief91e702013-02-04 12:06:36 -0800179 self.deploy = self._GetDeployChrome(
David James88e6f032013-03-02 08:13:20 -0800180 list(_REGULAR_TO) + ['--gs-path', _GS_PATH, '--force'])
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700181
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700182
David James88e6f032013-03-02 08:13:20 -0800183class TestDisableRootfsVerification(DeployTest):
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700184 """Testing disabling of rootfs verification and RO mode."""
185
David James88e6f032013-03-02 08:13:20 -0800186 def testDisableRootfsVerificationSuccess(self):
187 """Test the working case, disabling rootfs verification."""
188 self.deploy_mock.MockMountCmd(0)
189 self.deploy._DisableRootfsVerification()
190 self.assertFalse(self.deploy._rootfs_is_still_readonly.is_set())
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700191
192 def testDisableRootfsVerificationFailure(self):
193 """Test failure to disable rootfs verification."""
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700194 self.assertRaises(cros_build_lib.RunCommandError,
David James88e6f032013-03-02 08:13:20 -0800195 self.deploy._DisableRootfsVerification)
196 self.assertFalse(self.deploy._rootfs_is_still_readonly.is_set())
197
198
199class TestMount(DeployTest):
200 """Testing mount success and failure."""
201
202 def testSuccess(self):
203 """Test case where we are able to mount as writable."""
204 self.assertFalse(self.deploy._rootfs_is_still_readonly.is_set())
205 self.deploy_mock.MockMountCmd(0)
206 self.deploy._MountRootfsAsWritable()
207 self.assertFalse(self.deploy._rootfs_is_still_readonly.is_set())
208
209 def testMountError(self):
210 """Test that mount failure doesn't raise an exception by default."""
211 self.assertFalse(self.deploy._rootfs_is_still_readonly.is_set())
212 self.deploy._MountRootfsAsWritable()
213 self.assertTrue(self.deploy._rootfs_is_still_readonly.is_set())
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700214
215 def testMountRwFailure(self):
David James88e6f032013-03-02 08:13:20 -0800216 """Test that mount failure raises an exception if error_code_ok=False."""
217 self.assertRaises(cros_build_lib.RunCommandError,
218 self.deploy._MountRootfsAsWritable, error_code_ok=False)
219 self.assertFalse(self.deploy._rootfs_is_still_readonly.is_set())
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700220
221
Ryan Cuief91e702013-02-04 12:06:36 -0800222class TestUiJobStarted(DeployTest):
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700223 """Test detection of a running 'ui' job."""
224
Ryan Cuif2d1a582013-02-19 14:08:13 -0800225 def MockStatusUiCmd(self, **kwargs):
226 self.deploy_mock.rsh_mock.AddCmdResult('status ui', **kwargs)
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700227
228 def testUiJobStartedFalse(self):
229 """Correct results with a stopped job."""
Ryan Cuif2d1a582013-02-19 14:08:13 -0800230 self.MockStatusUiCmd(output='ui stop/waiting')
231 self.assertFalse(self.deploy._CheckUiJobStarted())
232
233 def testNoUiJob(self):
234 """Correct results when the job doesn't exist."""
235 self.MockStatusUiCmd(error='start: Unknown job: ui', returncode=1)
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700236 self.assertFalse(self.deploy._CheckUiJobStarted())
237
238 def testCheckRootfsWriteableTrue(self):
239 """Correct results with a running job."""
Ryan Cuif2d1a582013-02-19 14:08:13 -0800240 self.MockStatusUiCmd(output='ui start/running, process 297')
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700241 self.assertTrue(self.deploy._CheckUiJobStarted())
242
243
Ryan Cuief91e702013-02-04 12:06:36 -0800244class StagingTest(cros_test_lib.MockTempDirTestCase):
245 """Test user-mode and ebuild-mode staging functionality."""
246
247 def setUp(self):
Ryan Cuief91e702013-02-04 12:06:36 -0800248 self.staging_dir = os.path.join(self.tempdir, 'staging')
249 self.build_dir = os.path.join(self.tempdir, 'build_dir')
Ryan Cui686ec052013-02-12 16:39:41 -0800250 self.common_flags = ['--build-dir', self.build_dir,
251 '--board=lumpy', '--staging-only', '--cache-dir',
252 self.tempdir]
Ryan Cuia0215a72013-02-14 16:20:45 -0800253 self.sdk_mock = self.StartPatcher(cros_chrome_sdk_unittest.SDKFetcherMock())
Ryan Cui686ec052013-02-12 16:39:41 -0800254 self.PatchObject(
255 osutils, 'SourceEnvironment', autospec=True,
256 return_value={'STRIP': 'x86_64-cros-linux-gnu-strip'})
Ryan Cuief91e702013-02-04 12:06:36 -0800257
David Jamesa6e08892013-03-01 13:34:11 -0800258 def testSingleFileDeployFailure(self):
259 """Default staging enforces that mandatory files are copied"""
Ryan Cuief91e702013-02-04 12:06:36 -0800260 options, _ = _ParseCommandLine(self.common_flags)
David Jamesa6e08892013-03-01 13:34:11 -0800261 osutils.Touch(os.path.join(self.build_dir, 'chrome'), makedirs=True)
262 self.assertRaises(
263 chrome_util.MissingPathError, deploy_chrome._PrepareStagingDir,
Daniel Eratc89829c2014-05-12 17:24:21 -0700264 options, self.tempdir, self.staging_dir, chrome_util._COPY_PATHS_CHROME)
Ryan Cuief91e702013-02-04 12:06:36 -0800265
David Jamesa6e08892013-03-01 13:34:11 -0800266 def testSloppyDeployFailure(self):
267 """Sloppy staging enforces that at least one file is copied."""
268 options, _ = _ParseCommandLine(self.common_flags + ['--sloppy'])
269 self.assertRaises(
270 chrome_util.MissingPathError, deploy_chrome._PrepareStagingDir,
Daniel Eratc89829c2014-05-12 17:24:21 -0700271 options, self.tempdir, self.staging_dir, chrome_util._COPY_PATHS_CHROME)
David Jamesa6e08892013-03-01 13:34:11 -0800272
273 def testSloppyDeploySuccess(self):
274 """Sloppy staging - stage one file."""
275 options, _ = _ParseCommandLine(self.common_flags + ['--sloppy'])
276 osutils.Touch(os.path.join(self.build_dir, 'chrome'), makedirs=True)
Steve Funge984a532013-11-25 17:09:25 -0800277 deploy_chrome._PrepareStagingDir(options, self.tempdir, self.staging_dir,
Daniel Eratc89829c2014-05-12 17:24:21 -0700278 chrome_util._COPY_PATHS_CHROME)
David Jamesa6e08892013-03-01 13:34:11 -0800279
Ryan Cuief91e702013-02-04 12:06:36 -0800280 def testEmptyDeployStrict(self):
David Jamesa6e08892013-03-01 13:34:11 -0800281 """Strict staging fails when there are no files."""
Ryan Cuief91e702013-02-04 12:06:36 -0800282 options, _ = _ParseCommandLine(
283 self.common_flags + ['--gyp-defines', 'chromeos=1', '--strict'])
Ryan Cui686ec052013-02-12 16:39:41 -0800284
Ryan Cuief91e702013-02-04 12:06:36 -0800285 self.assertRaises(
286 chrome_util.MissingPathError, deploy_chrome._PrepareStagingDir,
Daniel Eratc89829c2014-05-12 17:24:21 -0700287 options, self.tempdir, self.staging_dir, chrome_util._COPY_PATHS_CHROME)
Steve Funge984a532013-11-25 17:09:25 -0800288
289
290class DeployTestBuildDir(cros_test_lib.MockTempDirTestCase):
Daniel Erat1ae46382014-08-14 10:23:39 -0700291 """Set up a deploy object with a build-dir for use in deployment type tests"""
Steve Funge984a532013-11-25 17:09:25 -0800292
293 def _GetDeployChrome(self, args):
294 options, _ = _ParseCommandLine(args)
295 return deploy_chrome.DeployChrome(
296 options, self.tempdir, os.path.join(self.tempdir, 'staging'))
297
298 def setUp(self):
299 self.staging_dir = os.path.join(self.tempdir, 'staging')
300 self.build_dir = os.path.join(self.tempdir, 'build_dir')
301 self.deploy_mock = self.StartPatcher(DeployChromeMock())
302 self.deploy = self._GetDeployChrome(
303 list(_REGULAR_TO) + ['--build-dir', self.build_dir,
304 '--board=lumpy', '--staging-only', '--cache-dir',
305 self.tempdir, '--sloppy'])
306
Daniel Erat1ae46382014-08-14 10:23:39 -0700307 def getCopyPath(self, source_path):
308 """Return a chrome_util.Path or None if not present."""
309 paths = [p for p in self.deploy.copy_paths if p.src == source_path]
310 return paths[0] if paths else None
Steve Funge984a532013-11-25 17:09:25 -0800311
Daniel Erat1ae46382014-08-14 10:23:39 -0700312class TestDeploymentType(DeployTestBuildDir):
Steve Funge984a532013-11-25 17:09:25 -0800313 """Test detection of deployment type using build dir."""
314
Daniel Erat1ae46382014-08-14 10:23:39 -0700315 def testAppShellDetection(self):
316 """Check for an app_shell deployment"""
317 osutils.Touch(os.path.join(self.deploy.options.build_dir, 'app_shell'),
Steve Funge984a532013-11-25 17:09:25 -0800318 makedirs=True)
319 self.deploy._CheckDeployType()
Daniel Erat1ae46382014-08-14 10:23:39 -0700320 self.assertTrue(self.getCopyPath('app_shell'))
321 self.assertFalse(self.getCopyPath('chrome'))
Steve Funge984a532013-11-25 17:09:25 -0800322
Daniel Erat1ae46382014-08-14 10:23:39 -0700323 def testChromeAndAppShellDetection(self):
324 """Check for a regular chrome deployment when app_shell also exists."""
Steve Fung63d705d2014-03-16 03:14:03 -0700325 osutils.Touch(os.path.join(self.deploy.options.build_dir, 'chrome'),
326 makedirs=True)
Daniel Erat1ae46382014-08-14 10:23:39 -0700327 osutils.Touch(os.path.join(self.deploy.options.build_dir, 'app_shell'),
Steve Fung63d705d2014-03-16 03:14:03 -0700328 makedirs=True)
329 self.deploy._CheckDeployType()
Daniel Erat1ae46382014-08-14 10:23:39 -0700330 self.assertFalse(self.getCopyPath('app_shell'))
331 self.assertTrue(self.getCopyPath('chrome'))
Steve Fung63d705d2014-03-16 03:14:03 -0700332
Steve Funge984a532013-11-25 17:09:25 -0800333 def testChromeDetection(self):
334 """Check for a regular chrome deployment"""
335 osutils.Touch(os.path.join(self.deploy.options.build_dir, 'chrome'),
336 makedirs=True)
337 self.deploy._CheckDeployType()
Daniel Erat1ae46382014-08-14 10:23:39 -0700338 self.assertFalse(self.getCopyPath('app_shell'))
339 self.assertTrue(self.getCopyPath('chrome'))
Ryan Cuief91e702013-02-04 12:06:36 -0800340
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700341if __name__ == '__main__':
342 cros_test_lib.main()