blob: 5472b31313e2a8a8162c6e00c274c680f9af4a97 [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
Ryan Cuiafd6c5c2012-07-30 17:48:22 -07008import os
9import sys
David James88e6f032013-03-02 08:13:20 -080010import time
Ryan Cuiafd6c5c2012-07-30 17:48:22 -070011
12sys.path.insert(0, os.path.join(os.path.dirname(os.path.realpath(__file__)),
13 '..', '..'))
Ryan Cuief91e702013-02-04 12:06:36 -080014
Ryan Cui686ec052013-02-12 16:39:41 -080015from chromite.cros.commands import cros_chrome_sdk_unittest
Ryan Cuief91e702013-02-04 12:06:36 -080016from chromite.lib import chrome_util
Ryan Cuiafd6c5c2012-07-30 17:48:22 -070017from chromite.lib import cros_build_lib
18from chromite.lib import cros_test_lib
Ryan Cui686ec052013-02-12 16:39:41 -080019from chromite.lib import osutils
Ryan Cuiafd6c5c2012-07-30 17:48:22 -070020from chromite.lib import partial_mock
21from chromite.lib import remote_access_unittest
Ryan Cuicbd9bb62013-04-30 11:17:02 -070022from chromite.lib import stats
23from chromite.lib import stats_unittest
24
Ryan Cuiafd6c5c2012-07-30 17:48:22 -070025from chromite.scripts import deploy_chrome
26
Ryan Cuief91e702013-02-04 12:06:36 -080027
Brian Harringe7524372012-12-23 02:02:56 -080028# TODO(build): Finish test wrapper (http://crosbug.com/37517).
29# Until then, this has to be after the chromite imports.
30import mock
31
Ryan Cuiafd6c5c2012-07-30 17:48:22 -070032
33# pylint: disable=W0212
34
35_REGULAR_TO = ('--to', 'monkey')
36_GS_PATH = 'gs://foon'
37
38
39def _ParseCommandLine(argv):
40 return deploy_chrome._ParseCommandLine(['--log-level', 'debug'] + argv)
41
42
43class InterfaceTest(cros_test_lib.OutputTestCase):
44 """Tests the commandline interface of the script."""
45
Ryan Cui686ec052013-02-12 16:39:41 -080046 BOARD = 'lumpy'
47
Ryan Cuiafd6c5c2012-07-30 17:48:22 -070048 def testGsLocalPathUnSpecified(self):
49 """Test no chrome path specified."""
50 with self.OutputCapturer():
51 self.assertRaises2(SystemExit, _ParseCommandLine, list(_REGULAR_TO),
52 check_attrs={'code': 2})
53
54 def testGsPathSpecified(self):
55 """Test case of GS path specified."""
56 argv = list(_REGULAR_TO) + ['--gs-path', _GS_PATH]
57 _ParseCommandLine(argv)
58
59 def testLocalPathSpecified(self):
60 """Test case of local path specified."""
Ryan Cuia56a71e2012-10-18 18:40:35 -070061 argv = list(_REGULAR_TO) + ['--local-pkg-path', '/path/to/chrome']
Ryan Cuiafd6c5c2012-07-30 17:48:22 -070062 _ParseCommandLine(argv)
63
64 def testNoTarget(self):
65 """Test no target specified."""
66 argv = ['--gs-path', _GS_PATH]
Ryan Cuief91e702013-02-04 12:06:36 -080067 self.assertParseError(argv)
68
69 def assertParseError(self, argv):
Ryan Cuiafd6c5c2012-07-30 17:48:22 -070070 with self.OutputCapturer():
71 self.assertRaises2(SystemExit, _ParseCommandLine, argv,
72 check_attrs={'code': 2})
73
Ryan Cuief91e702013-02-04 12:06:36 -080074 def testStagingFlagsNoStrict(self):
75 """Errors out when --staging-flags is set without --strict."""
76 argv = ['--staging-only', '--build-dir=/path/to/nowhere',
Ryan Cui686ec052013-02-12 16:39:41 -080077 '--board=%s' % self.BOARD, '--staging-flags=highdpi']
Ryan Cuief91e702013-02-04 12:06:36 -080078 self.assertParseError(argv)
79
80 def testStrictNoBuildDir(self):
81 """Errors out when --strict is set without --build-dir."""
82 argv = ['--staging-only', '--strict', '--gs-path', _GS_PATH]
83 self.assertParseError(argv)
84
Ryan Cui686ec052013-02-12 16:39:41 -080085 def testNoBoardBuildDir(self):
86 argv = ['--staging-only', '--build-dir=/path/to/nowhere']
87 self.assertParseError(argv)
88
Thiago Goncales12793312013-05-23 11:26:17 -070089 def testMountOptionSetsTargetDir(self):
90 argv = list(_REGULAR_TO) + ['--gs-path', _GS_PATH, '--mount']
91 options, _ = _ParseCommandLine(argv)
92 self.assertIsNot(options.target_dir, None)
93
94 def testMountOptionSetsMountDir(self):
95 argv = list(_REGULAR_TO) + ['--gs-path', _GS_PATH, '--mount']
96 options, _ = _ParseCommandLine(argv)
97 self.assertIsNot(options.mount_dir, None)
98
99 def testMountOptionDoesNotOverrideTargetDir(self):
100 argv = list(_REGULAR_TO) + ['--gs-path', _GS_PATH, '--mount',
101 '--target-dir', '/foo/bar/cow']
102 options, _ = _ParseCommandLine(argv)
103 self.assertEqual(options.target_dir, '/foo/bar/cow')
104
105 def testMountOptionDoesNotOverrideMountDir(self):
106 argv = list(_REGULAR_TO) + ['--gs-path', _GS_PATH, '--mount',
107 '--mount-dir', '/foo/bar/cow']
108 options, _ = _ParseCommandLine(argv)
109 self.assertEqual(options.mount_dir, '/foo/bar/cow')
110
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700111
112class DeployChromeMock(partial_mock.PartialMock):
Steve Funge984a532013-11-25 17:09:25 -0800113 """Deploy Chrome Mock Class."""
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700114
115 TARGET = 'chromite.scripts.deploy_chrome.DeployChrome'
David James88e6f032013-03-02 08:13:20 -0800116 ATTRS = ('_KillProcsIfNeeded', '_DisableRootfsVerification')
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700117
David James88e6f032013-03-02 08:13:20 -0800118 def __init__(self):
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700119 partial_mock.PartialMock.__init__(self)
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700120 # Target starts off as having rootfs verification enabled.
Ryan Cuie18f24f2012-12-03 18:39:55 -0800121 self.rsh_mock = remote_access_unittest.RemoteShMock()
David James88e6f032013-03-02 08:13:20 -0800122 self.rsh_mock.SetDefaultCmdResult(0)
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700123 self.MockMountCmd(1)
Pawel Osciak577773a2013-03-05 10:52:12 -0800124 self.rsh_mock.AddCmdResult(
125 deploy_chrome.LSOF_COMMAND % (deploy_chrome._CHROME_DIR,), 1)
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700126
127 def MockMountCmd(self, returnvalue):
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700128 self.rsh_mock.AddCmdResult(deploy_chrome.MOUNT_RW_COMMAND,
David James88e6f032013-03-02 08:13:20 -0800129 returnvalue)
130
131 def _DisableRootfsVerification(self, inst):
132 with mock.patch.object(time, 'sleep'):
133 self.backup['_DisableRootfsVerification'](inst)
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700134
Ryan Cui4d6fca92012-12-13 16:41:56 -0800135 def PreStart(self):
136 self.rsh_mock.start()
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700137
Ryan Cui4d6fca92012-12-13 16:41:56 -0800138 def PreStop(self):
139 self.rsh_mock.stop()
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700140
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700141 def _KillProcsIfNeeded(self, _inst):
142 # Fully stub out for now.
143 pass
144
145
Ryan Cuicbd9bb62013-04-30 11:17:02 -0700146class MainTest(cros_test_lib.MockLoggingTestCase):
Steve Funge984a532013-11-25 17:09:25 -0800147 """Main tests."""
Ryan Cuicbd9bb62013-04-30 11:17:02 -0700148
149 def setUp(self):
150 self.PatchObject(deploy_chrome.DeployChrome, 'Perform', autospec=True)
151 self.stats_module_mock = stats_unittest.StatsModuleMock()
152 self.StartPatcher(self.stats_module_mock)
153
154 def testStatsUpload(self, call_count=1):
155 """The stats upload path."""
156 deploy_chrome.main(['--board=lumpy', '--staging-only',
157 '--build-dir=/tmp/abc'])
158 self.assertEquals(stats.StatsUploader._Upload.call_count, call_count)
159
160 def testStatsUploadError(self):
161 """Don't upload stats if we fail to create it."""
162 self.stats_module_mock.stats_mock.init_exception = True
163 with cros_test_lib.LoggingCapturer():
164 self.testStatsUpload(call_count=0)
165
166
Ryan Cuief91e702013-02-04 12:06:36 -0800167class DeployTest(cros_test_lib.MockTempDirTestCase):
Steve Funge984a532013-11-25 17:09:25 -0800168 """Setup a deploy object with a GS-path for use in tests."""
169
Ryan Cuief91e702013-02-04 12:06:36 -0800170 def _GetDeployChrome(self, args):
171 options, _ = _ParseCommandLine(args)
Ryan Cuia56a71e2012-10-18 18:40:35 -0700172 return deploy_chrome.DeployChrome(
173 options, self.tempdir, os.path.join(self.tempdir, 'staging'))
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700174
175 def setUp(self):
Ryan Cuif1416f32013-01-22 18:43:41 -0800176 self.deploy_mock = self.StartPatcher(DeployChromeMock())
Ryan Cuief91e702013-02-04 12:06:36 -0800177 self.deploy = self._GetDeployChrome(
David James88e6f032013-03-02 08:13:20 -0800178 list(_REGULAR_TO) + ['--gs-path', _GS_PATH, '--force'])
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700179
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700180
David James88e6f032013-03-02 08:13:20 -0800181class TestDisableRootfsVerification(DeployTest):
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700182 """Testing disabling of rootfs verification and RO mode."""
183
David James88e6f032013-03-02 08:13:20 -0800184 def testDisableRootfsVerificationSuccess(self):
185 """Test the working case, disabling rootfs verification."""
186 self.deploy_mock.MockMountCmd(0)
187 self.deploy._DisableRootfsVerification()
188 self.assertFalse(self.deploy._rootfs_is_still_readonly.is_set())
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700189
190 def testDisableRootfsVerificationFailure(self):
191 """Test failure to disable rootfs verification."""
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700192 self.assertRaises(cros_build_lib.RunCommandError,
David James88e6f032013-03-02 08:13:20 -0800193 self.deploy._DisableRootfsVerification)
194 self.assertFalse(self.deploy._rootfs_is_still_readonly.is_set())
195
196
197class TestMount(DeployTest):
198 """Testing mount success and failure."""
199
200 def testSuccess(self):
201 """Test case where we are able to mount as writable."""
202 self.assertFalse(self.deploy._rootfs_is_still_readonly.is_set())
203 self.deploy_mock.MockMountCmd(0)
204 self.deploy._MountRootfsAsWritable()
205 self.assertFalse(self.deploy._rootfs_is_still_readonly.is_set())
206
207 def testMountError(self):
208 """Test that mount failure doesn't raise an exception by default."""
209 self.assertFalse(self.deploy._rootfs_is_still_readonly.is_set())
210 self.deploy._MountRootfsAsWritable()
211 self.assertTrue(self.deploy._rootfs_is_still_readonly.is_set())
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700212
213 def testMountRwFailure(self):
David James88e6f032013-03-02 08:13:20 -0800214 """Test that mount failure raises an exception if error_code_ok=False."""
215 self.assertRaises(cros_build_lib.RunCommandError,
216 self.deploy._MountRootfsAsWritable, error_code_ok=False)
217 self.assertFalse(self.deploy._rootfs_is_still_readonly.is_set())
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700218
219
Ryan Cuief91e702013-02-04 12:06:36 -0800220class TestUiJobStarted(DeployTest):
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700221 """Test detection of a running 'ui' job."""
222
Ryan Cuif2d1a582013-02-19 14:08:13 -0800223 def MockStatusUiCmd(self, **kwargs):
224 self.deploy_mock.rsh_mock.AddCmdResult('status ui', **kwargs)
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700225
226 def testUiJobStartedFalse(self):
227 """Correct results with a stopped job."""
Ryan Cuif2d1a582013-02-19 14:08:13 -0800228 self.MockStatusUiCmd(output='ui stop/waiting')
229 self.assertFalse(self.deploy._CheckUiJobStarted())
230
231 def testNoUiJob(self):
232 """Correct results when the job doesn't exist."""
233 self.MockStatusUiCmd(error='start: Unknown job: ui', returncode=1)
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700234 self.assertFalse(self.deploy._CheckUiJobStarted())
235
236 def testCheckRootfsWriteableTrue(self):
237 """Correct results with a running job."""
Ryan Cuif2d1a582013-02-19 14:08:13 -0800238 self.MockStatusUiCmd(output='ui start/running, process 297')
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700239 self.assertTrue(self.deploy._CheckUiJobStarted())
240
241
Ryan Cuief91e702013-02-04 12:06:36 -0800242class StagingTest(cros_test_lib.MockTempDirTestCase):
243 """Test user-mode and ebuild-mode staging functionality."""
244
245 def setUp(self):
Ryan Cuief91e702013-02-04 12:06:36 -0800246 self.staging_dir = os.path.join(self.tempdir, 'staging')
247 self.build_dir = os.path.join(self.tempdir, 'build_dir')
Ryan Cui686ec052013-02-12 16:39:41 -0800248 self.common_flags = ['--build-dir', self.build_dir,
249 '--board=lumpy', '--staging-only', '--cache-dir',
250 self.tempdir]
Ryan Cuia0215a72013-02-14 16:20:45 -0800251 self.sdk_mock = self.StartPatcher(cros_chrome_sdk_unittest.SDKFetcherMock())
Ryan Cui686ec052013-02-12 16:39:41 -0800252 self.PatchObject(
253 osutils, 'SourceEnvironment', autospec=True,
254 return_value={'STRIP': 'x86_64-cros-linux-gnu-strip'})
Ryan Cuief91e702013-02-04 12:06:36 -0800255
David Jamesa6e08892013-03-01 13:34:11 -0800256 def testSingleFileDeployFailure(self):
257 """Default staging enforces that mandatory files are copied"""
Ryan Cuief91e702013-02-04 12:06:36 -0800258 options, _ = _ParseCommandLine(self.common_flags)
David Jamesa6e08892013-03-01 13:34:11 -0800259 osutils.Touch(os.path.join(self.build_dir, 'chrome'), makedirs=True)
260 self.assertRaises(
261 chrome_util.MissingPathError, deploy_chrome._PrepareStagingDir,
Steve Funge984a532013-11-25 17:09:25 -0800262 options, self.tempdir, self.staging_dir, chrome_util._COPY_PATHS)
Ryan Cuief91e702013-02-04 12:06:36 -0800263
David Jamesa6e08892013-03-01 13:34:11 -0800264 def testSloppyDeployFailure(self):
265 """Sloppy staging enforces that at least one file is copied."""
266 options, _ = _ParseCommandLine(self.common_flags + ['--sloppy'])
267 self.assertRaises(
268 chrome_util.MissingPathError, deploy_chrome._PrepareStagingDir,
Steve Funge984a532013-11-25 17:09:25 -0800269 options, self.tempdir, self.staging_dir, chrome_util._COPY_PATHS)
David Jamesa6e08892013-03-01 13:34:11 -0800270
271 def testSloppyDeploySuccess(self):
272 """Sloppy staging - stage one file."""
273 options, _ = _ParseCommandLine(self.common_flags + ['--sloppy'])
274 osutils.Touch(os.path.join(self.build_dir, 'chrome'), makedirs=True)
Steve Funge984a532013-11-25 17:09:25 -0800275 deploy_chrome._PrepareStagingDir(options, self.tempdir, self.staging_dir,
276 chrome_util._COPY_PATHS)
David Jamesa6e08892013-03-01 13:34:11 -0800277
Ryan Cuief91e702013-02-04 12:06:36 -0800278 def testEmptyDeployStrict(self):
David Jamesa6e08892013-03-01 13:34:11 -0800279 """Strict staging fails when there are no files."""
Ryan Cuief91e702013-02-04 12:06:36 -0800280 options, _ = _ParseCommandLine(
281 self.common_flags + ['--gyp-defines', 'chromeos=1', '--strict'])
Ryan Cui686ec052013-02-12 16:39:41 -0800282
Ryan Cuief91e702013-02-04 12:06:36 -0800283 self.assertRaises(
284 chrome_util.MissingPathError, deploy_chrome._PrepareStagingDir,
Steve Funge984a532013-11-25 17:09:25 -0800285 options, self.tempdir, self.staging_dir, chrome_util._COPY_PATHS)
286
287
288class DeployTestBuildDir(cros_test_lib.MockTempDirTestCase):
289 """Setup a deploy object with a build-dir for use in Content Shell tests"""
290
291 def _GetDeployChrome(self, args):
292 options, _ = _ParseCommandLine(args)
293 return deploy_chrome.DeployChrome(
294 options, self.tempdir, os.path.join(self.tempdir, 'staging'))
295
296 def setUp(self):
297 self.staging_dir = os.path.join(self.tempdir, 'staging')
298 self.build_dir = os.path.join(self.tempdir, 'build_dir')
299 self.deploy_mock = self.StartPatcher(DeployChromeMock())
300 self.deploy = self._GetDeployChrome(
301 list(_REGULAR_TO) + ['--build-dir', self.build_dir,
302 '--board=lumpy', '--staging-only', '--cache-dir',
303 self.tempdir, '--sloppy'])
304
305
306class TestContentDeploymentType(DeployTestBuildDir):
307 """Test detection of deployment type using build dir."""
308
309 def testContentShellDetection(self):
310 """Check for a content_shell deployment"""
311 osutils.Touch(os.path.join(self.deploy.options.build_dir,
312 'system.unand/chrome/eureka_shell'),
313 makedirs=True)
314 self.deploy._CheckDeployType()
315 self.assertTrue(self.deploy.content_shell)
316
317 def testChromeDetection(self):
318 """Check for a regular chrome deployment"""
319 osutils.Touch(os.path.join(self.deploy.options.build_dir, 'chrome'),
320 makedirs=True)
321 self.deploy._CheckDeployType()
322 self.assertFalse(self.deploy.content_shell)
Ryan Cuief91e702013-02-04 12:06:36 -0800323
324
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700325if __name__ == '__main__':
326 cros_test_lib.main()