blob: 9591f49a7b2e3d6112f676c1df1f92fce07df3cc [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
21from chromite.scripts import deploy_chrome
22
Ryan Cuief91e702013-02-04 12:06:36 -080023
Brian Harringe7524372012-12-23 02:02:56 -080024# TODO(build): Finish test wrapper (http://crosbug.com/37517).
25# Until then, this has to be after the chromite imports.
26import mock
27
Ryan Cuiafd6c5c2012-07-30 17:48:22 -070028
29# pylint: disable=W0212
30
31_REGULAR_TO = ('--to', 'monkey')
32_GS_PATH = 'gs://foon'
33
34
35def _ParseCommandLine(argv):
36 return deploy_chrome._ParseCommandLine(['--log-level', 'debug'] + argv)
37
38
39class InterfaceTest(cros_test_lib.OutputTestCase):
40 """Tests the commandline interface of the script."""
41
Ryan Cui686ec052013-02-12 16:39:41 -080042 BOARD = 'lumpy'
43
Ryan Cuiafd6c5c2012-07-30 17:48:22 -070044 def testGsLocalPathUnSpecified(self):
45 """Test no chrome path specified."""
46 with self.OutputCapturer():
47 self.assertRaises2(SystemExit, _ParseCommandLine, list(_REGULAR_TO),
48 check_attrs={'code': 2})
49
50 def testGsPathSpecified(self):
51 """Test case of GS path specified."""
52 argv = list(_REGULAR_TO) + ['--gs-path', _GS_PATH]
53 _ParseCommandLine(argv)
54
55 def testLocalPathSpecified(self):
56 """Test case of local path specified."""
Ryan Cuia56a71e2012-10-18 18:40:35 -070057 argv = list(_REGULAR_TO) + ['--local-pkg-path', '/path/to/chrome']
Ryan Cuiafd6c5c2012-07-30 17:48:22 -070058 _ParseCommandLine(argv)
59
60 def testNoTarget(self):
61 """Test no target specified."""
62 argv = ['--gs-path', _GS_PATH]
Ryan Cuief91e702013-02-04 12:06:36 -080063 self.assertParseError(argv)
64
65 def assertParseError(self, argv):
Ryan Cuiafd6c5c2012-07-30 17:48:22 -070066 with self.OutputCapturer():
67 self.assertRaises2(SystemExit, _ParseCommandLine, argv,
68 check_attrs={'code': 2})
69
Ryan Cuief91e702013-02-04 12:06:36 -080070 def testStagingFlagsNoStrict(self):
71 """Errors out when --staging-flags is set without --strict."""
72 argv = ['--staging-only', '--build-dir=/path/to/nowhere',
Ryan Cui686ec052013-02-12 16:39:41 -080073 '--board=%s' % self.BOARD, '--staging-flags=highdpi']
Ryan Cuief91e702013-02-04 12:06:36 -080074 self.assertParseError(argv)
75
76 def testStrictNoBuildDir(self):
77 """Errors out when --strict is set without --build-dir."""
78 argv = ['--staging-only', '--strict', '--gs-path', _GS_PATH]
79 self.assertParseError(argv)
80
Ryan Cui686ec052013-02-12 16:39:41 -080081 def testNoBoardBuildDir(self):
82 argv = ['--staging-only', '--build-dir=/path/to/nowhere']
83 self.assertParseError(argv)
84
Ryan Cuiafd6c5c2012-07-30 17:48:22 -070085
86class DeployChromeMock(partial_mock.PartialMock):
87
88 TARGET = 'chromite.scripts.deploy_chrome.DeployChrome'
David James88e6f032013-03-02 08:13:20 -080089 ATTRS = ('_KillProcsIfNeeded', '_DisableRootfsVerification')
Ryan Cuiafd6c5c2012-07-30 17:48:22 -070090
David James88e6f032013-03-02 08:13:20 -080091 def __init__(self):
Ryan Cuiafd6c5c2012-07-30 17:48:22 -070092 partial_mock.PartialMock.__init__(self)
Ryan Cuiafd6c5c2012-07-30 17:48:22 -070093 # Target starts off as having rootfs verification enabled.
Ryan Cuie18f24f2012-12-03 18:39:55 -080094 self.rsh_mock = remote_access_unittest.RemoteShMock()
David James88e6f032013-03-02 08:13:20 -080095 self.rsh_mock.SetDefaultCmdResult(0)
Ryan Cuiafd6c5c2012-07-30 17:48:22 -070096 self.MockMountCmd(1)
David James88e6f032013-03-02 08:13:20 -080097 self.rsh_mock.AddCmdResult(deploy_chrome.LSOF_COMMAND, 1)
Ryan Cuiafd6c5c2012-07-30 17:48:22 -070098
99 def MockMountCmd(self, returnvalue):
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700100 self.rsh_mock.AddCmdResult(deploy_chrome.MOUNT_RW_COMMAND,
David James88e6f032013-03-02 08:13:20 -0800101 returnvalue)
102
103 def _DisableRootfsVerification(self, inst):
104 with mock.patch.object(time, 'sleep'):
105 self.backup['_DisableRootfsVerification'](inst)
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700106
Ryan Cui4d6fca92012-12-13 16:41:56 -0800107 def PreStart(self):
108 self.rsh_mock.start()
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700109
Ryan Cui4d6fca92012-12-13 16:41:56 -0800110 def PreStop(self):
111 self.rsh_mock.stop()
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700112
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700113 def _KillProcsIfNeeded(self, _inst):
114 # Fully stub out for now.
115 pass
116
117
Ryan Cuief91e702013-02-04 12:06:36 -0800118class DeployTest(cros_test_lib.MockTempDirTestCase):
119 def _GetDeployChrome(self, args):
120 options, _ = _ParseCommandLine(args)
Ryan Cuia56a71e2012-10-18 18:40:35 -0700121 return deploy_chrome.DeployChrome(
122 options, self.tempdir, os.path.join(self.tempdir, 'staging'))
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700123
124 def setUp(self):
Ryan Cuif1416f32013-01-22 18:43:41 -0800125 self.deploy_mock = self.StartPatcher(DeployChromeMock())
Ryan Cuief91e702013-02-04 12:06:36 -0800126 self.deploy = self._GetDeployChrome(
David James88e6f032013-03-02 08:13:20 -0800127 list(_REGULAR_TO) + ['--gs-path', _GS_PATH, '--force'])
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700128
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700129
David James88e6f032013-03-02 08:13:20 -0800130class TestDisableRootfsVerification(DeployTest):
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700131 """Testing disabling of rootfs verification and RO mode."""
132
David James88e6f032013-03-02 08:13:20 -0800133 def testDisableRootfsVerificationSuccess(self):
134 """Test the working case, disabling rootfs verification."""
135 self.deploy_mock.MockMountCmd(0)
136 self.deploy._DisableRootfsVerification()
137 self.assertFalse(self.deploy._rootfs_is_still_readonly.is_set())
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700138
139 def testDisableRootfsVerificationFailure(self):
140 """Test failure to disable rootfs verification."""
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700141 self.assertRaises(cros_build_lib.RunCommandError,
David James88e6f032013-03-02 08:13:20 -0800142 self.deploy._DisableRootfsVerification)
143 self.assertFalse(self.deploy._rootfs_is_still_readonly.is_set())
144
145
146class TestMount(DeployTest):
147 """Testing mount success and failure."""
148
149 def testSuccess(self):
150 """Test case where we are able to mount as writable."""
151 self.assertFalse(self.deploy._rootfs_is_still_readonly.is_set())
152 self.deploy_mock.MockMountCmd(0)
153 self.deploy._MountRootfsAsWritable()
154 self.assertFalse(self.deploy._rootfs_is_still_readonly.is_set())
155
156 def testMountError(self):
157 """Test that mount failure doesn't raise an exception by default."""
158 self.assertFalse(self.deploy._rootfs_is_still_readonly.is_set())
159 self.deploy._MountRootfsAsWritable()
160 self.assertTrue(self.deploy._rootfs_is_still_readonly.is_set())
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700161
162 def testMountRwFailure(self):
David James88e6f032013-03-02 08:13:20 -0800163 """Test that mount failure raises an exception if error_code_ok=False."""
164 self.assertRaises(cros_build_lib.RunCommandError,
165 self.deploy._MountRootfsAsWritable, error_code_ok=False)
166 self.assertFalse(self.deploy._rootfs_is_still_readonly.is_set())
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700167
168
Ryan Cuief91e702013-02-04 12:06:36 -0800169class TestUiJobStarted(DeployTest):
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700170 """Test detection of a running 'ui' job."""
171
Ryan Cuif2d1a582013-02-19 14:08:13 -0800172 def MockStatusUiCmd(self, **kwargs):
173 self.deploy_mock.rsh_mock.AddCmdResult('status ui', **kwargs)
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700174
175 def testUiJobStartedFalse(self):
176 """Correct results with a stopped job."""
Ryan Cuif2d1a582013-02-19 14:08:13 -0800177 self.MockStatusUiCmd(output='ui stop/waiting')
178 self.assertFalse(self.deploy._CheckUiJobStarted())
179
180 def testNoUiJob(self):
181 """Correct results when the job doesn't exist."""
182 self.MockStatusUiCmd(error='start: Unknown job: ui', returncode=1)
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700183 self.assertFalse(self.deploy._CheckUiJobStarted())
184
185 def testCheckRootfsWriteableTrue(self):
186 """Correct results with a running job."""
Ryan Cuif2d1a582013-02-19 14:08:13 -0800187 self.MockStatusUiCmd(output='ui start/running, process 297')
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700188 self.assertTrue(self.deploy._CheckUiJobStarted())
189
190
Ryan Cuief91e702013-02-04 12:06:36 -0800191class StagingTest(cros_test_lib.MockTempDirTestCase):
192 """Test user-mode and ebuild-mode staging functionality."""
193
194 def setUp(self):
Ryan Cuief91e702013-02-04 12:06:36 -0800195 self.staging_dir = os.path.join(self.tempdir, 'staging')
196 self.build_dir = os.path.join(self.tempdir, 'build_dir')
Ryan Cui686ec052013-02-12 16:39:41 -0800197 self.common_flags = ['--build-dir', self.build_dir,
198 '--board=lumpy', '--staging-only', '--cache-dir',
199 self.tempdir]
Ryan Cuia0215a72013-02-14 16:20:45 -0800200 self.sdk_mock = self.StartPatcher(cros_chrome_sdk_unittest.SDKFetcherMock())
Ryan Cui686ec052013-02-12 16:39:41 -0800201 self.PatchObject(
202 osutils, 'SourceEnvironment', autospec=True,
203 return_value={'STRIP': 'x86_64-cros-linux-gnu-strip'})
Ryan Cuief91e702013-02-04 12:06:36 -0800204
David Jamesa6e08892013-03-01 13:34:11 -0800205 def testSingleFileDeployFailure(self):
206 """Default staging enforces that mandatory files are copied"""
Ryan Cuief91e702013-02-04 12:06:36 -0800207 options, _ = _ParseCommandLine(self.common_flags)
David Jamesa6e08892013-03-01 13:34:11 -0800208 osutils.Touch(os.path.join(self.build_dir, 'chrome'), makedirs=True)
209 self.assertRaises(
210 chrome_util.MissingPathError, deploy_chrome._PrepareStagingDir,
Ryan Cuief91e702013-02-04 12:06:36 -0800211 options, self.tempdir, self.staging_dir)
212
David Jamesa6e08892013-03-01 13:34:11 -0800213 def testSloppyDeployFailure(self):
214 """Sloppy staging enforces that at least one file is copied."""
215 options, _ = _ParseCommandLine(self.common_flags + ['--sloppy'])
216 self.assertRaises(
217 chrome_util.MissingPathError, deploy_chrome._PrepareStagingDir,
218 options, self.tempdir, self.staging_dir)
219
220 def testSloppyDeploySuccess(self):
221 """Sloppy staging - stage one file."""
222 options, _ = _ParseCommandLine(self.common_flags + ['--sloppy'])
223 osutils.Touch(os.path.join(self.build_dir, 'chrome'), makedirs=True)
224 deploy_chrome._PrepareStagingDir(options, self.tempdir, self.staging_dir)
225
Ryan Cuief91e702013-02-04 12:06:36 -0800226 def testEmptyDeployStrict(self):
David Jamesa6e08892013-03-01 13:34:11 -0800227 """Strict staging fails when there are no files."""
Ryan Cuief91e702013-02-04 12:06:36 -0800228 options, _ = _ParseCommandLine(
229 self.common_flags + ['--gyp-defines', 'chromeos=1', '--strict'])
Ryan Cui686ec052013-02-12 16:39:41 -0800230 chrome_util.MissingPathError(deploy_chrome._PrepareStagingDir,
231 options, self.tempdir, self.staging_dir)
232
Ryan Cuief91e702013-02-04 12:06:36 -0800233 self.assertRaises(
234 chrome_util.MissingPathError, deploy_chrome._PrepareStagingDir,
235 options, self.tempdir, self.staging_dir)
236
237
Ryan Cuiafd6c5c2012-07-30 17:48:22 -0700238if __name__ == '__main__':
239 cros_test_lib.main()