blob: 1eb41e1f208c545da6c5d8986f183363ae653ea1 [file] [log] [blame]
David Pursellf1d16a62015-03-25 13:31:04 -07001# Copyright 2015 The Chromium OS Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""Unit tests for the flash module."""
6
7from __future__ import print_function
8
9import mock
10import os
11
12from chromite.cli import flash
13from chromite.lib import brick_lib
14from chromite.lib import commandline
15from chromite.lib import cros_build_lib
16from chromite.lib import cros_test_lib
17from chromite.lib import dev_server_wrapper
Bertrand SIMONNET56f773d2015-05-04 14:02:39 -070018from chromite.lib import osutils
David Pursellf1d16a62015-03-25 13:31:04 -070019from chromite.lib import partial_mock
20from chromite.lib import remote_access
Gilad Arnold8ecd42a2015-04-27 11:47:05 -070021from chromite.lib import workspace_lib
David Pursellf1d16a62015-03-25 13:31:04 -070022
23
24class RemoteDeviceUpdaterMock(partial_mock.PartialCmdMock):
25 """Mock out RemoteDeviceUpdater."""
26 TARGET = 'chromite.cli.flash.RemoteDeviceUpdater'
27 ATTRS = ('UpdateStateful', 'UpdateRootfs', 'SetupRootfsUpdate', 'Verify')
28
29 def __init__(self):
30 partial_mock.PartialCmdMock.__init__(self)
31
32 def UpdateStateful(self, _inst, *_args, **_kwargs):
33 """Mock out UpdateStateful."""
34
35 def UpdateRootfs(self, _inst, *_args, **_kwargs):
36 """Mock out UpdateRootfs."""
37
38 def SetupRootfsUpdate(self, _inst, *_args, **_kwargs):
39 """Mock out SetupRootfsUpdate."""
40
41 def Verify(self, _inst, *_args, **_kwargs):
42 """Mock out SetupRootfsUpdate."""
43
44
David Pursellf1d16a62015-03-25 13:31:04 -070045class RemoteDeviceUpdaterTest(cros_test_lib.MockTempDirTestCase):
46 """Test the flow of flash.Flash() with RemoteDeviceUpdater."""
47
48 IMAGE = '/path/to/image'
49 DEVICE = commandline.Device(scheme=commandline.DEVICE_SCHEME_SSH,
50 hostname='1.1.1.1')
51
52 def setUp(self):
53 """Patches objects."""
54 self.updater_mock = self.StartPatcher(RemoteDeviceUpdaterMock())
55 self.PatchObject(dev_server_wrapper, 'GenerateXbuddyRequest',
56 return_value='xbuddy/local/latest')
57 self.PatchObject(dev_server_wrapper, 'DevServerWrapper')
58 self.PatchObject(dev_server_wrapper, 'GetImagePathWithXbuddy',
Gilad Arnolde62ec902015-04-24 14:41:02 -070059 return_value=('taco-paladin/R36/chromiumos_test_image.bin',
60 'remote/taco-paladin/R36/test'))
David Pursellf1d16a62015-03-25 13:31:04 -070061 self.PatchObject(dev_server_wrapper, 'GetUpdatePayloads')
62 self.PatchObject(remote_access, 'CHECK_INTERVAL', new=0)
63 self.PatchObject(remote_access, 'ChromiumOSDevice')
Gilad Arnold8ecd42a2015-04-27 11:47:05 -070064 self.PatchObject(workspace_lib, 'WorkspacePath', return_value=None)
David Pursellf1d16a62015-03-25 13:31:04 -070065
66 def testUpdateAll(self):
67 """Tests that update methods are called correctly."""
David Pursellf1d16a62015-03-25 13:31:04 -070068 with mock.patch('os.path.exists', return_value=True):
Bertrand SIMONNETb34a98b2015-04-22 14:30:04 -070069 flash.Flash(self.DEVICE, self.IMAGE)
70 self.assertTrue(self.updater_mock.patched['UpdateStateful'].called)
71 self.assertTrue(self.updater_mock.patched['UpdateRootfs'].called)
David Pursellf1d16a62015-03-25 13:31:04 -070072
73 def testUpdateStateful(self):
74 """Tests that update methods are called correctly."""
David Pursellf1d16a62015-03-25 13:31:04 -070075 with mock.patch('os.path.exists', return_value=True):
Bertrand SIMONNETb34a98b2015-04-22 14:30:04 -070076 flash.Flash(self.DEVICE, self.IMAGE, rootfs_update=False)
77 self.assertTrue(self.updater_mock.patched['UpdateStateful'].called)
78 self.assertFalse(self.updater_mock.patched['UpdateRootfs'].called)
David Pursellf1d16a62015-03-25 13:31:04 -070079
80 def testUpdateRootfs(self):
81 """Tests that update methods are called correctly."""
David Pursellf1d16a62015-03-25 13:31:04 -070082 with mock.patch('os.path.exists', return_value=True):
Bertrand SIMONNETb34a98b2015-04-22 14:30:04 -070083 flash.Flash(self.DEVICE, self.IMAGE, stateful_update=False)
84 self.assertFalse(self.updater_mock.patched['UpdateStateful'].called)
85 self.assertTrue(self.updater_mock.patched['UpdateRootfs'].called)
David Pursellf1d16a62015-03-25 13:31:04 -070086
87 def testMissingPayloads(self):
88 """Tests we raise FlashError when payloads are missing."""
89 with mock.patch('os.path.exists', return_value=False):
90 self.assertRaises(flash.FlashError, flash.Flash, self.DEVICE, self.IMAGE)
91
92 def testProjectSdk(self):
93 """Tests that Project SDK flashing invoked as expected."""
David Pursellf1d16a62015-03-25 13:31:04 -070094 with mock.patch('os.path.exists', return_value=True):
Bertrand SIMONNETb34a98b2015-04-22 14:30:04 -070095 with mock.patch('chromite.lib.project_sdk.FindVersion',
96 return_value='1.2.3'):
97 flash.Flash(self.DEVICE, self.IMAGE, project_sdk_image=True)
98 dev_server_wrapper.GetImagePathWithXbuddy.assert_called_with(
99 'project_sdk', mock.ANY, version='1.2.3', static_dir=mock.ANY,
100 lookup_only=True)
101 self.assertTrue(self.updater_mock.patched['UpdateStateful'].called)
102 self.assertTrue(self.updater_mock.patched['UpdateRootfs'].called)
David Pursellf1d16a62015-03-25 13:31:04 -0700103
104
105class USBImagerMock(partial_mock.PartialCmdMock):
106 """Mock out USBImager."""
107 TARGET = 'chromite.cli.flash.USBImager'
108 ATTRS = ('CopyImageToDevice', 'InstallImageToDevice',
109 'ChooseRemovableDevice', 'ListAllRemovableDevices',
Bertrand SIMONNET56f773d2015-05-04 14:02:39 -0700110 'GetRemovableDeviceDescription')
David Pursellf1d16a62015-03-25 13:31:04 -0700111 VALID_IMAGE = True
112
113 def __init__(self):
114 partial_mock.PartialCmdMock.__init__(self)
115
116 def CopyImageToDevice(self, _inst, *_args, **_kwargs):
117 """Mock out CopyImageToDevice."""
118
119 def InstallImageToDevice(self, _inst, *_args, **_kwargs):
120 """Mock out InstallImageToDevice."""
121
122 def ChooseRemovableDevice(self, _inst, *_args, **_kwargs):
123 """Mock out ChooseRemovableDevice."""
124
125 def ListAllRemovableDevices(self, _inst, *_args, **_kwargs):
126 """Mock out ListAllRemovableDevices."""
127 return ['foo', 'taco', 'milk']
128
129 def GetRemovableDeviceDescription(self, _inst, *_args, **_kwargs):
130 """Mock out GetRemovableDeviceDescription."""
131
David Pursellf1d16a62015-03-25 13:31:04 -0700132
133class USBImagerTest(cros_test_lib.MockTempDirTestCase):
134 """Test the flow of flash.Flash() with USBImager."""
135 IMAGE = '/path/to/image'
136
137 def Device(self, path):
138 """Create a USB device for passing to flash.Flash()."""
139 return commandline.Device(scheme=commandline.DEVICE_SCHEME_USB,
140 path=path)
141
142 def setUp(self):
143 """Patches objects."""
144 self.usb_mock = USBImagerMock()
145 self.imager_mock = self.StartPatcher(self.usb_mock)
146 self.PatchObject(dev_server_wrapper, 'GenerateXbuddyRequest',
147 return_value='xbuddy/local/latest')
148 self.PatchObject(dev_server_wrapper, 'DevServerWrapper')
149 self.PatchObject(dev_server_wrapper, 'GetImagePathWithXbuddy',
Gilad Arnolde62ec902015-04-24 14:41:02 -0700150 return_value=('taco-paladin/R36/chromiumos_test_image.bin',
151 'remote/taco-paladin/R36/test'))
David Pursellf1d16a62015-03-25 13:31:04 -0700152 self.PatchObject(os.path, 'exists', return_value=True)
153 self.PatchObject(brick_lib, 'FindBrickInPath', return_value=None)
Bertrand SIMONNET56f773d2015-05-04 14:02:39 -0700154 self.isgpt_mock = self.PatchObject(flash, '_IsFilePathGPTDiskImage',
155 return_value=True)
Gilad Arnold8ecd42a2015-04-27 11:47:05 -0700156 self.PatchObject(workspace_lib, 'WorkspacePath', return_value=None)
David Pursellf1d16a62015-03-25 13:31:04 -0700157
158 def testLocalImagePathCopy(self):
159 """Tests that imaging methods are called correctly."""
160 with mock.patch('os.path.isfile', return_value=True):
161 flash.Flash(self.Device('/dev/foo'), self.IMAGE)
162 self.assertTrue(self.imager_mock.patched['CopyImageToDevice'].called)
163
164 def testLocalImagePathInstall(self):
165 """Tests that imaging methods are called correctly."""
166 with mock.patch('os.path.isfile', return_value=True):
167 flash.Flash(self.Device('/dev/foo'), self.IMAGE, board='taco',
168 install=True)
169 self.assertTrue(self.imager_mock.patched['InstallImageToDevice'].called)
170
171 def testLocalBadImagePath(self):
172 """Tests that using an image not having the magic bytes has prompt."""
Bertrand SIMONNET56f773d2015-05-04 14:02:39 -0700173 self.isgpt_mock.return_value = False
David Pursellf1d16a62015-03-25 13:31:04 -0700174 with mock.patch('os.path.isfile', return_value=True):
175 with mock.patch.object(cros_build_lib, 'BooleanPrompt') as mock_prompt:
176 mock_prompt.return_value = False
177 flash.Flash(self.Device('/dev/foo'), self.IMAGE)
178 self.assertTrue(mock_prompt.called)
179
180 def testNonLocalImagePath(self):
181 """Tests that we try to get the image path using xbuddy."""
182 with mock.patch.object(
183 dev_server_wrapper,
184 'GetImagePathWithXbuddy',
Gilad Arnolde62ec902015-04-24 14:41:02 -0700185 return_value=('translated/xbuddy/path',
186 'resolved/xbuddy/path')) as mock_xbuddy:
David Pursellf1d16a62015-03-25 13:31:04 -0700187 with mock.patch('os.path.isfile', return_value=False):
188 with mock.patch('os.path.isdir', return_value=False):
189 flash.Flash(self.Device('/dev/foo'), self.IMAGE)
190 self.assertTrue(mock_xbuddy.called)
191
192 def testConfirmNonRemovableDevice(self):
193 """Tests that we ask user to confirm if the device is not removable."""
194 with mock.patch.object(cros_build_lib, 'BooleanPrompt') as mock_prompt:
195 flash.Flash(self.Device('/dev/dummy'), self.IMAGE)
196 self.assertTrue(mock_prompt.called)
197
198 def testSkipPromptNonRemovableDevice(self):
199 """Tests that we skip the prompt for non-removable with --yes."""
200 with mock.patch.object(cros_build_lib, 'BooleanPrompt') as mock_prompt:
201 flash.Flash(self.Device('/dev/dummy'), self.IMAGE, yes=True)
202 self.assertFalse(mock_prompt.called)
203
204 def testChooseRemovableDevice(self):
205 """Tests that we ask user to choose a device if none is given."""
206 flash.Flash(self.Device(''), self.IMAGE)
207 self.assertTrue(self.imager_mock.patched['ChooseRemovableDevice'].called)
Bertrand SIMONNET56f773d2015-05-04 14:02:39 -0700208
209
210class FlashUtilTest(cros_test_lib.MockTempDirTestCase):
211 """Tests the helpers from cli.flash."""
212
213 def testChooseImage(self):
214 """Tests that we can detect a GPT image."""
215 # pylint: disable=protected-access
216
217 with self.PatchObject(flash, '_IsFilePathGPTDiskImage', return_value=True):
218 # No images defined. Choosing the image should raise an error.
219 with self.assertRaises(ValueError):
220 flash._ChooseImageFromDirectory(self.tempdir)
221
222 file_a = os.path.join(self.tempdir, 'a')
223 osutils.Touch(file_a)
224 # Only one image available, it should be selected automatically.
225 self.assertEqual(file_a, flash._ChooseImageFromDirectory(self.tempdir))
226
227 osutils.Touch(os.path.join(self.tempdir, 'b'))
228 file_c = os.path.join(self.tempdir, 'c')
229 osutils.Touch(file_c)
230 osutils.Touch(os.path.join(self.tempdir, 'd'))
231
232 # Multiple images available, we should ask the user to select the right
233 # image.
234 with self.PatchObject(cros_build_lib, 'GetChoice', return_value=2):
235 self.assertEqual(file_c, flash._ChooseImageFromDirectory(self.tempdir))