blob: 739ef05d2626a3e6beb3c2c650c0609739c9eed6 [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
21
22
23class RemoteDeviceUpdaterMock(partial_mock.PartialCmdMock):
24 """Mock out RemoteDeviceUpdater."""
25 TARGET = 'chromite.cli.flash.RemoteDeviceUpdater'
26 ATTRS = ('UpdateStateful', 'UpdateRootfs', 'SetupRootfsUpdate', 'Verify')
27
28 def __init__(self):
29 partial_mock.PartialCmdMock.__init__(self)
30
31 def UpdateStateful(self, _inst, *_args, **_kwargs):
32 """Mock out UpdateStateful."""
33
34 def UpdateRootfs(self, _inst, *_args, **_kwargs):
35 """Mock out UpdateRootfs."""
36
37 def SetupRootfsUpdate(self, _inst, *_args, **_kwargs):
38 """Mock out SetupRootfsUpdate."""
39
40 def Verify(self, _inst, *_args, **_kwargs):
41 """Mock out SetupRootfsUpdate."""
42
43
David Pursellf1d16a62015-03-25 13:31:04 -070044class RemoteDeviceUpdaterTest(cros_test_lib.MockTempDirTestCase):
45 """Test the flow of flash.Flash() with RemoteDeviceUpdater."""
46
47 IMAGE = '/path/to/image'
48 DEVICE = commandline.Device(scheme=commandline.DEVICE_SCHEME_SSH,
49 hostname='1.1.1.1')
50
51 def setUp(self):
52 """Patches objects."""
53 self.updater_mock = self.StartPatcher(RemoteDeviceUpdaterMock())
54 self.PatchObject(dev_server_wrapper, 'GenerateXbuddyRequest',
55 return_value='xbuddy/local/latest')
56 self.PatchObject(dev_server_wrapper, 'DevServerWrapper')
57 self.PatchObject(dev_server_wrapper, 'GetImagePathWithXbuddy',
Gilad Arnolde62ec902015-04-24 14:41:02 -070058 return_value=('taco-paladin/R36/chromiumos_test_image.bin',
59 'remote/taco-paladin/R36/test'))
David Pursellf1d16a62015-03-25 13:31:04 -070060 self.PatchObject(dev_server_wrapper, 'GetUpdatePayloads')
61 self.PatchObject(remote_access, 'CHECK_INTERVAL', new=0)
62 self.PatchObject(remote_access, 'ChromiumOSDevice')
63
64 def testUpdateAll(self):
65 """Tests that update methods are called correctly."""
David Pursellf1d16a62015-03-25 13:31:04 -070066 with mock.patch('os.path.exists', return_value=True):
Bertrand SIMONNETb34a98b2015-04-22 14:30:04 -070067 flash.Flash(self.DEVICE, self.IMAGE)
68 self.assertTrue(self.updater_mock.patched['UpdateStateful'].called)
69 self.assertTrue(self.updater_mock.patched['UpdateRootfs'].called)
David Pursellf1d16a62015-03-25 13:31:04 -070070
71 def testUpdateStateful(self):
72 """Tests that update methods are called correctly."""
David Pursellf1d16a62015-03-25 13:31:04 -070073 with mock.patch('os.path.exists', return_value=True):
Bertrand SIMONNETb34a98b2015-04-22 14:30:04 -070074 flash.Flash(self.DEVICE, self.IMAGE, rootfs_update=False)
75 self.assertTrue(self.updater_mock.patched['UpdateStateful'].called)
76 self.assertFalse(self.updater_mock.patched['UpdateRootfs'].called)
David Pursellf1d16a62015-03-25 13:31:04 -070077
78 def testUpdateRootfs(self):
79 """Tests that update methods are called correctly."""
David Pursellf1d16a62015-03-25 13:31:04 -070080 with mock.patch('os.path.exists', return_value=True):
Bertrand SIMONNETb34a98b2015-04-22 14:30:04 -070081 flash.Flash(self.DEVICE, self.IMAGE, stateful_update=False)
82 self.assertFalse(self.updater_mock.patched['UpdateStateful'].called)
83 self.assertTrue(self.updater_mock.patched['UpdateRootfs'].called)
David Pursellf1d16a62015-03-25 13:31:04 -070084
85 def testMissingPayloads(self):
86 """Tests we raise FlashError when payloads are missing."""
87 with mock.patch('os.path.exists', return_value=False):
88 self.assertRaises(flash.FlashError, flash.Flash, self.DEVICE, self.IMAGE)
89
90 def testProjectSdk(self):
91 """Tests that Project SDK flashing invoked as expected."""
David Pursellf1d16a62015-03-25 13:31:04 -070092 with mock.patch('os.path.exists', return_value=True):
Bertrand SIMONNETb34a98b2015-04-22 14:30:04 -070093 with mock.patch('chromite.lib.project_sdk.FindVersion',
94 return_value='1.2.3'):
95 flash.Flash(self.DEVICE, self.IMAGE, project_sdk_image=True)
96 dev_server_wrapper.GetImagePathWithXbuddy.assert_called_with(
97 'project_sdk', mock.ANY, version='1.2.3', static_dir=mock.ANY,
98 lookup_only=True)
99 self.assertTrue(self.updater_mock.patched['UpdateStateful'].called)
100 self.assertTrue(self.updater_mock.patched['UpdateRootfs'].called)
David Pursellf1d16a62015-03-25 13:31:04 -0700101
102
103class USBImagerMock(partial_mock.PartialCmdMock):
104 """Mock out USBImager."""
105 TARGET = 'chromite.cli.flash.USBImager'
106 ATTRS = ('CopyImageToDevice', 'InstallImageToDevice',
107 'ChooseRemovableDevice', 'ListAllRemovableDevices',
Bertrand SIMONNET56f773d2015-05-04 14:02:39 -0700108 'GetRemovableDeviceDescription')
David Pursellf1d16a62015-03-25 13:31:04 -0700109 VALID_IMAGE = True
110
111 def __init__(self):
112 partial_mock.PartialCmdMock.__init__(self)
113
114 def CopyImageToDevice(self, _inst, *_args, **_kwargs):
115 """Mock out CopyImageToDevice."""
116
117 def InstallImageToDevice(self, _inst, *_args, **_kwargs):
118 """Mock out InstallImageToDevice."""
119
120 def ChooseRemovableDevice(self, _inst, *_args, **_kwargs):
121 """Mock out ChooseRemovableDevice."""
122
123 def ListAllRemovableDevices(self, _inst, *_args, **_kwargs):
124 """Mock out ListAllRemovableDevices."""
125 return ['foo', 'taco', 'milk']
126
127 def GetRemovableDeviceDescription(self, _inst, *_args, **_kwargs):
128 """Mock out GetRemovableDeviceDescription."""
129
David Pursellf1d16a62015-03-25 13:31:04 -0700130
131class USBImagerTest(cros_test_lib.MockTempDirTestCase):
132 """Test the flow of flash.Flash() with USBImager."""
133 IMAGE = '/path/to/image'
134
135 def Device(self, path):
136 """Create a USB device for passing to flash.Flash()."""
137 return commandline.Device(scheme=commandline.DEVICE_SCHEME_USB,
138 path=path)
139
140 def setUp(self):
141 """Patches objects."""
142 self.usb_mock = USBImagerMock()
143 self.imager_mock = self.StartPatcher(self.usb_mock)
144 self.PatchObject(dev_server_wrapper, 'GenerateXbuddyRequest',
145 return_value='xbuddy/local/latest')
146 self.PatchObject(dev_server_wrapper, 'DevServerWrapper')
147 self.PatchObject(dev_server_wrapper, 'GetImagePathWithXbuddy',
Gilad Arnolde62ec902015-04-24 14:41:02 -0700148 return_value=('taco-paladin/R36/chromiumos_test_image.bin',
149 'remote/taco-paladin/R36/test'))
David Pursellf1d16a62015-03-25 13:31:04 -0700150 self.PatchObject(os.path, 'exists', return_value=True)
151 self.PatchObject(brick_lib, 'FindBrickInPath', return_value=None)
Bertrand SIMONNET56f773d2015-05-04 14:02:39 -0700152 self.isgpt_mock = self.PatchObject(flash, '_IsFilePathGPTDiskImage',
153 return_value=True)
David Pursellf1d16a62015-03-25 13:31:04 -0700154
155 def testLocalImagePathCopy(self):
156 """Tests that imaging methods are called correctly."""
157 with mock.patch('os.path.isfile', return_value=True):
158 flash.Flash(self.Device('/dev/foo'), self.IMAGE)
159 self.assertTrue(self.imager_mock.patched['CopyImageToDevice'].called)
160
161 def testLocalImagePathInstall(self):
162 """Tests that imaging methods are called correctly."""
163 with mock.patch('os.path.isfile', return_value=True):
164 flash.Flash(self.Device('/dev/foo'), self.IMAGE, board='taco',
165 install=True)
166 self.assertTrue(self.imager_mock.patched['InstallImageToDevice'].called)
167
168 def testLocalBadImagePath(self):
169 """Tests that using an image not having the magic bytes has prompt."""
Bertrand SIMONNET56f773d2015-05-04 14:02:39 -0700170 self.isgpt_mock.return_value = False
David Pursellf1d16a62015-03-25 13:31:04 -0700171 with mock.patch('os.path.isfile', return_value=True):
172 with mock.patch.object(cros_build_lib, 'BooleanPrompt') as mock_prompt:
173 mock_prompt.return_value = False
174 flash.Flash(self.Device('/dev/foo'), self.IMAGE)
175 self.assertTrue(mock_prompt.called)
176
177 def testNonLocalImagePath(self):
178 """Tests that we try to get the image path using xbuddy."""
179 with mock.patch.object(
180 dev_server_wrapper,
181 'GetImagePathWithXbuddy',
Gilad Arnolde62ec902015-04-24 14:41:02 -0700182 return_value=('translated/xbuddy/path',
183 'resolved/xbuddy/path')) as mock_xbuddy:
David Pursellf1d16a62015-03-25 13:31:04 -0700184 with mock.patch('os.path.isfile', return_value=False):
185 with mock.patch('os.path.isdir', return_value=False):
186 flash.Flash(self.Device('/dev/foo'), self.IMAGE)
187 self.assertTrue(mock_xbuddy.called)
188
189 def testConfirmNonRemovableDevice(self):
190 """Tests that we ask user to confirm if the device is not removable."""
191 with mock.patch.object(cros_build_lib, 'BooleanPrompt') as mock_prompt:
192 flash.Flash(self.Device('/dev/dummy'), self.IMAGE)
193 self.assertTrue(mock_prompt.called)
194
195 def testSkipPromptNonRemovableDevice(self):
196 """Tests that we skip the prompt for non-removable with --yes."""
197 with mock.patch.object(cros_build_lib, 'BooleanPrompt') as mock_prompt:
198 flash.Flash(self.Device('/dev/dummy'), self.IMAGE, yes=True)
199 self.assertFalse(mock_prompt.called)
200
201 def testChooseRemovableDevice(self):
202 """Tests that we ask user to choose a device if none is given."""
203 flash.Flash(self.Device(''), self.IMAGE)
204 self.assertTrue(self.imager_mock.patched['ChooseRemovableDevice'].called)
Bertrand SIMONNET56f773d2015-05-04 14:02:39 -0700205
206
207class FlashUtilTest(cros_test_lib.MockTempDirTestCase):
208 """Tests the helpers from cli.flash."""
209
210 def testChooseImage(self):
211 """Tests that we can detect a GPT image."""
212 # pylint: disable=protected-access
213
214 with self.PatchObject(flash, '_IsFilePathGPTDiskImage', return_value=True):
215 # No images defined. Choosing the image should raise an error.
216 with self.assertRaises(ValueError):
217 flash._ChooseImageFromDirectory(self.tempdir)
218
219 file_a = os.path.join(self.tempdir, 'a')
220 osutils.Touch(file_a)
221 # Only one image available, it should be selected automatically.
222 self.assertEqual(file_a, flash._ChooseImageFromDirectory(self.tempdir))
223
224 osutils.Touch(os.path.join(self.tempdir, 'b'))
225 file_c = os.path.join(self.tempdir, 'c')
226 osutils.Touch(file_c)
227 osutils.Touch(os.path.join(self.tempdir, 'd'))
228
229 # Multiple images available, we should ask the user to select the right
230 # image.
231 with self.PatchObject(cros_build_lib, 'GetChoice', return_value=2):
232 self.assertEqual(file_c, flash._ChooseImageFromDirectory(self.tempdir))