blob: 8901e959f3b22e9510f2de990d7b772c56fafe4b [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
6
Ryan Cuiafd6c5c2012-07-30 17:48:22 -07007import os
8import sys
David James88e6f032013-03-02 08:13:20 -08009import time
Ryan Cuiafd6c5c2012-07-30 17:48:22 -070010
11sys.path.insert(0, os.path.join(os.path.dirname(os.path.realpath(__file__)),
12 '..', '..'))
Ryan Cuief91e702013-02-04 12:06:36 -080013
Ryan Cui686ec052013-02-12 16:39:41 -080014from chromite.cros.commands 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
20from chromite.lib import remote_access_unittest
Ryan Cuicbd9bb62013-04-30 11:17:02 -070021from chromite.lib import stats
22from chromite.lib import stats_unittest
23
Ryan Cuiafd6c5c2012-07-30 17:48:22 -070024from chromite.scripts import deploy_chrome
25
Ryan Cuief91e702013-02-04 12:06:36 -080026
Brian Harringe7524372012-12-23 02:02:56 -080027# TODO(build): Finish test wrapper (http://crosbug.com/37517).
28# Until then, this has to be after the chromite imports.
29import mock
30
Ryan Cuiafd6c5c2012-07-30 17:48:22 -070031
32# pylint: disable=W0212
33
34_REGULAR_TO = ('--to', 'monkey')
35_GS_PATH = 'gs://foon'
36
37
38def _ParseCommandLine(argv):
39 return deploy_chrome._ParseCommandLine(['--log-level', 'debug'] + argv)
40
41
42class InterfaceTest(cros_test_lib.OutputTestCase):
43 """Tests the commandline interface of the script."""
44
Ryan Cui686ec052013-02-12 16:39:41 -080045 BOARD = 'lumpy'
46
Ryan Cuiafd6c5c2012-07-30 17:48:22 -070047 def testGsLocalPathUnSpecified(self):
48 """Test no chrome path specified."""
49 with self.OutputCapturer():
50 self.assertRaises2(SystemExit, _ParseCommandLine, list(_REGULAR_TO),
51 check_attrs={'code': 2})
52
53 def testGsPathSpecified(self):
54 """Test case of GS path specified."""
55 argv = list(_REGULAR_TO) + ['--gs-path', _GS_PATH]
56 _ParseCommandLine(argv)
57
58 def testLocalPathSpecified(self):
59 """Test case of local path specified."""
Ryan Cuia56a71e2012-10-18 18:40:35 -070060 argv = list(_REGULAR_TO) + ['--local-pkg-path', '/path/to/chrome']
Ryan Cuiafd6c5c2012-07-30 17:48:22 -070061 _ParseCommandLine(argv)
62
63 def testNoTarget(self):
64 """Test no target specified."""
65 argv = ['--gs-path', _GS_PATH]
Ryan Cuief91e702013-02-04 12:06:36 -080066 self.assertParseError(argv)
67
68 def assertParseError(self, argv):
Ryan Cuiafd6c5c2012-07-30 17:48:22 -070069 with self.OutputCapturer():
70 self.assertRaises2(SystemExit, _ParseCommandLine, argv,
71 check_attrs={'code': 2})
72
Ryan Cuief91e702013-02-04 12:06:36 -080073 def testStagingFlagsNoStrict(self):
74 """Errors out when --staging-flags is set without --strict."""
75 argv = ['--staging-only', '--build-dir=/path/to/nowhere',
Ryan Cui686ec052013-02-12 16:39:41 -080076 '--board=%s' % self.BOARD, '--staging-flags=highdpi']
Ryan Cuief91e702013-02-04 12:06:36 -080077 self.assertParseError(argv)
78
79 def testStrictNoBuildDir(self):
80 """Errors out when --strict is set without --build-dir."""
81 argv = ['--staging-only', '--strict', '--gs-path', _GS_PATH]
82 self.assertParseError(argv)
83
Ryan Cui686ec052013-02-12 16:39:41 -080084 def testNoBoardBuildDir(self):
85 argv = ['--staging-only', '--build-dir=/path/to/nowhere']
86 self.assertParseError(argv)
87
Ryan Cuiafd6c5c2012-07-30 17:48:22 -070088
89class DeployChromeMock(partial_mock.PartialMock):
90
91 TARGET = 'chromite.scripts.deploy_chrome.DeployChrome'
David James88e6f032013-03-02 08:13:20 -080092 ATTRS = ('_KillProcsIfNeeded', '_DisableRootfsVerification')
Ryan Cuiafd6c5c2012-07-30 17:48:22 -070093
David James88e6f032013-03-02 08:13:20 -080094 def __init__(self):
Ryan Cuiafd6c5c2012-07-30 17:48:22 -070095 partial_mock.PartialMock.__init__(self)
Ryan Cuiafd6c5c2012-07-30 17:48:22 -070096 # Target starts off as having rootfs verification enabled.
Ryan Cuie18f24f2012-12-03 18:39:55 -080097 self.rsh_mock = remote_access_unittest.RemoteShMock()
David James88e6f032013-03-02 08:13:20 -080098 self.rsh_mock.SetDefaultCmdResult(0)
Ryan Cuiafd6c5c2012-07-30 17:48:22 -070099 self.MockMountCmd(1)
Pawel Osciak577773a2013-03-05 10:52:12 -0800100 self.rsh_mock.AddCmdResult(
101 deploy_chrome.LSOF_COMMAND % (deploy_chrome._CHROME_DIR,), 1)
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700102
103 def MockMountCmd(self, returnvalue):
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700104 self.rsh_mock.AddCmdResult(deploy_chrome.MOUNT_RW_COMMAND,
David James88e6f032013-03-02 08:13:20 -0800105 returnvalue)
106
107 def _DisableRootfsVerification(self, inst):
108 with mock.patch.object(time, 'sleep'):
109 self.backup['_DisableRootfsVerification'](inst)
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700110
Ryan Cui4d6fca92012-12-13 16:41:56 -0800111 def PreStart(self):
112 self.rsh_mock.start()
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700113
Ryan Cui4d6fca92012-12-13 16:41:56 -0800114 def PreStop(self):
115 self.rsh_mock.stop()
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700116
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700117 def _KillProcsIfNeeded(self, _inst):
118 # Fully stub out for now.
119 pass
120
121
Ryan Cuicbd9bb62013-04-30 11:17:02 -0700122class MainTest(cros_test_lib.MockLoggingTestCase):
123
124 def setUp(self):
125 self.PatchObject(deploy_chrome.DeployChrome, 'Perform', autospec=True)
126 self.stats_module_mock = stats_unittest.StatsModuleMock()
127 self.StartPatcher(self.stats_module_mock)
128
129 def testStatsUpload(self, call_count=1):
130 """The stats upload path."""
131 deploy_chrome.main(['--board=lumpy', '--staging-only',
132 '--build-dir=/tmp/abc'])
133 self.assertEquals(stats.StatsUploader._Upload.call_count, call_count)
134
135 def testStatsUploadError(self):
136 """Don't upload stats if we fail to create it."""
137 self.stats_module_mock.stats_mock.init_exception = True
138 with cros_test_lib.LoggingCapturer():
139 self.testStatsUpload(call_count=0)
140
141
Ryan Cuief91e702013-02-04 12:06:36 -0800142class DeployTest(cros_test_lib.MockTempDirTestCase):
143 def _GetDeployChrome(self, args):
144 options, _ = _ParseCommandLine(args)
Ryan Cuia56a71e2012-10-18 18:40:35 -0700145 return deploy_chrome.DeployChrome(
146 options, self.tempdir, os.path.join(self.tempdir, 'staging'))
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700147
148 def setUp(self):
Ryan Cuif1416f32013-01-22 18:43:41 -0800149 self.deploy_mock = self.StartPatcher(DeployChromeMock())
Ryan Cuief91e702013-02-04 12:06:36 -0800150 self.deploy = self._GetDeployChrome(
David James88e6f032013-03-02 08:13:20 -0800151 list(_REGULAR_TO) + ['--gs-path', _GS_PATH, '--force'])
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700152
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700153
David James88e6f032013-03-02 08:13:20 -0800154class TestDisableRootfsVerification(DeployTest):
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700155 """Testing disabling of rootfs verification and RO mode."""
156
David James88e6f032013-03-02 08:13:20 -0800157 def testDisableRootfsVerificationSuccess(self):
158 """Test the working case, disabling rootfs verification."""
159 self.deploy_mock.MockMountCmd(0)
160 self.deploy._DisableRootfsVerification()
161 self.assertFalse(self.deploy._rootfs_is_still_readonly.is_set())
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700162
163 def testDisableRootfsVerificationFailure(self):
164 """Test failure to disable rootfs verification."""
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700165 self.assertRaises(cros_build_lib.RunCommandError,
David James88e6f032013-03-02 08:13:20 -0800166 self.deploy._DisableRootfsVerification)
167 self.assertFalse(self.deploy._rootfs_is_still_readonly.is_set())
168
169
170class TestMount(DeployTest):
171 """Testing mount success and failure."""
172
173 def testSuccess(self):
174 """Test case where we are able to mount as writable."""
175 self.assertFalse(self.deploy._rootfs_is_still_readonly.is_set())
176 self.deploy_mock.MockMountCmd(0)
177 self.deploy._MountRootfsAsWritable()
178 self.assertFalse(self.deploy._rootfs_is_still_readonly.is_set())
179
180 def testMountError(self):
181 """Test that mount failure doesn't raise an exception by default."""
182 self.assertFalse(self.deploy._rootfs_is_still_readonly.is_set())
183 self.deploy._MountRootfsAsWritable()
184 self.assertTrue(self.deploy._rootfs_is_still_readonly.is_set())
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700185
186 def testMountRwFailure(self):
David James88e6f032013-03-02 08:13:20 -0800187 """Test that mount failure raises an exception if error_code_ok=False."""
188 self.assertRaises(cros_build_lib.RunCommandError,
189 self.deploy._MountRootfsAsWritable, error_code_ok=False)
190 self.assertFalse(self.deploy._rootfs_is_still_readonly.is_set())
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700191
192
Ryan Cuief91e702013-02-04 12:06:36 -0800193class TestUiJobStarted(DeployTest):
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700194 """Test detection of a running 'ui' job."""
195
Ryan Cuif2d1a582013-02-19 14:08:13 -0800196 def MockStatusUiCmd(self, **kwargs):
197 self.deploy_mock.rsh_mock.AddCmdResult('status ui', **kwargs)
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700198
199 def testUiJobStartedFalse(self):
200 """Correct results with a stopped job."""
Ryan Cuif2d1a582013-02-19 14:08:13 -0800201 self.MockStatusUiCmd(output='ui stop/waiting')
202 self.assertFalse(self.deploy._CheckUiJobStarted())
203
204 def testNoUiJob(self):
205 """Correct results when the job doesn't exist."""
206 self.MockStatusUiCmd(error='start: Unknown job: ui', returncode=1)
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700207 self.assertFalse(self.deploy._CheckUiJobStarted())
208
209 def testCheckRootfsWriteableTrue(self):
210 """Correct results with a running job."""
Ryan Cuif2d1a582013-02-19 14:08:13 -0800211 self.MockStatusUiCmd(output='ui start/running, process 297')
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700212 self.assertTrue(self.deploy._CheckUiJobStarted())
213
214
Ryan Cuief91e702013-02-04 12:06:36 -0800215class StagingTest(cros_test_lib.MockTempDirTestCase):
216 """Test user-mode and ebuild-mode staging functionality."""
217
218 def setUp(self):
Ryan Cuief91e702013-02-04 12:06:36 -0800219 self.staging_dir = os.path.join(self.tempdir, 'staging')
220 self.build_dir = os.path.join(self.tempdir, 'build_dir')
Ryan Cui686ec052013-02-12 16:39:41 -0800221 self.common_flags = ['--build-dir', self.build_dir,
222 '--board=lumpy', '--staging-only', '--cache-dir',
223 self.tempdir]
Ryan Cuia0215a72013-02-14 16:20:45 -0800224 self.sdk_mock = self.StartPatcher(cros_chrome_sdk_unittest.SDKFetcherMock())
Ryan Cui686ec052013-02-12 16:39:41 -0800225 self.PatchObject(
226 osutils, 'SourceEnvironment', autospec=True,
227 return_value={'STRIP': 'x86_64-cros-linux-gnu-strip'})
Ryan Cuief91e702013-02-04 12:06:36 -0800228
David Jamesa6e08892013-03-01 13:34:11 -0800229 def testSingleFileDeployFailure(self):
230 """Default staging enforces that mandatory files are copied"""
Ryan Cuief91e702013-02-04 12:06:36 -0800231 options, _ = _ParseCommandLine(self.common_flags)
David Jamesa6e08892013-03-01 13:34:11 -0800232 osutils.Touch(os.path.join(self.build_dir, 'chrome'), makedirs=True)
233 self.assertRaises(
234 chrome_util.MissingPathError, deploy_chrome._PrepareStagingDir,
Ryan Cuief91e702013-02-04 12:06:36 -0800235 options, self.tempdir, self.staging_dir)
236
David Jamesa6e08892013-03-01 13:34:11 -0800237 def testSloppyDeployFailure(self):
238 """Sloppy staging enforces that at least one file is copied."""
239 options, _ = _ParseCommandLine(self.common_flags + ['--sloppy'])
240 self.assertRaises(
241 chrome_util.MissingPathError, deploy_chrome._PrepareStagingDir,
242 options, self.tempdir, self.staging_dir)
243
244 def testSloppyDeploySuccess(self):
245 """Sloppy staging - stage one file."""
246 options, _ = _ParseCommandLine(self.common_flags + ['--sloppy'])
247 osutils.Touch(os.path.join(self.build_dir, 'chrome'), makedirs=True)
248 deploy_chrome._PrepareStagingDir(options, self.tempdir, self.staging_dir)
249
Ryan Cuief91e702013-02-04 12:06:36 -0800250 def testEmptyDeployStrict(self):
David Jamesa6e08892013-03-01 13:34:11 -0800251 """Strict staging fails when there are no files."""
Ryan Cuief91e702013-02-04 12:06:36 -0800252 options, _ = _ParseCommandLine(
253 self.common_flags + ['--gyp-defines', 'chromeos=1', '--strict'])
Ryan Cui686ec052013-02-12 16:39:41 -0800254 chrome_util.MissingPathError(deploy_chrome._PrepareStagingDir,
255 options, self.tempdir, self.staging_dir)
256
Ryan Cuief91e702013-02-04 12:06:36 -0800257 self.assertRaises(
258 chrome_util.MissingPathError, deploy_chrome._PrepareStagingDir,
259 options, self.tempdir, self.staging_dir)
260
261
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700262if __name__ == '__main__':
263 cros_test_lib.main()