blob: 8a0077f9e8306ff124bc5a4a0d5ecab2fac831af [file] [log] [blame]
Mike Frysingere58c0e22017-10-04 15:43:30 -04001# -*- coding: utf-8 -*-
David Pursellf1d16a62015-03-25 13:31:04 -07002# Copyright 2015 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"""Unit tests for the flash module."""
7
8from __future__ import print_function
9
David Pursellf1d16a62015-03-25 13:31:04 -070010import os
11
Mike Frysinger6db648e2018-07-24 19:57:58 -040012import mock
13
David Pursellf1d16a62015-03-25 13:31:04 -070014from chromite.cli import flash
Sanika Kulkarnia8c4e3a2019-09-20 16:47:25 -070015from chromite.lib import auto_updater_transfer
David Pursellf1d16a62015-03-25 13:31:04 -070016from chromite.lib import commandline
17from chromite.lib import cros_build_lib
Ralph Nathan9b997232015-05-15 13:13:12 -070018from chromite.lib import cros_logging as logging
David Pursellf1d16a62015-03-25 13:31:04 -070019from chromite.lib import cros_test_lib
20from chromite.lib import dev_server_wrapper
Bertrand SIMONNET56f773d2015-05-04 14:02:39 -070021from chromite.lib import osutils
David Pursellf1d16a62015-03-25 13:31:04 -070022from chromite.lib import partial_mock
23from chromite.lib import remote_access
Mike Frysingerdda695b2019-11-23 20:58:59 -050024from chromite.lib import remote_access_unittest
David Pursellf1d16a62015-03-25 13:31:04 -070025
Amin Hassanic0f06fa2019-01-28 15:24:47 -080026from chromite.lib.paygen import paygen_payload_lib
27from chromite.lib.paygen import paygen_stateful_payload_lib
28
David Pursellf1d16a62015-03-25 13:31:04 -070029
30class RemoteDeviceUpdaterMock(partial_mock.PartialCmdMock):
31 """Mock out RemoteDeviceUpdater."""
Amin Hassani9800d432019-07-24 14:23:39 -070032 TARGET = 'chromite.lib.auto_updater.ChromiumOSUpdater'
xixuane851dfb2016-05-02 18:02:37 -070033 ATTRS = ('UpdateStateful', 'UpdateRootfs', 'SetupRootfsUpdate',
Sanika Kulkarnie3b177b2019-11-26 14:42:48 -080034 'RebootAndVerify', 'PreparePayloadPropsFile',
35 '_FixPayloadPropertiesFile')
David Pursellf1d16a62015-03-25 13:31:04 -070036
37 def __init__(self):
38 partial_mock.PartialCmdMock.__init__(self)
39
40 def UpdateStateful(self, _inst, *_args, **_kwargs):
41 """Mock out UpdateStateful."""
42
43 def UpdateRootfs(self, _inst, *_args, **_kwargs):
44 """Mock out UpdateRootfs."""
45
46 def SetupRootfsUpdate(self, _inst, *_args, **_kwargs):
47 """Mock out SetupRootfsUpdate."""
48
xixuane851dfb2016-05-02 18:02:37 -070049 def RebootAndVerify(self, _inst, *_args, **_kwargs):
50 """Mock out RebootAndVerify."""
David Pursellf1d16a62015-03-25 13:31:04 -070051
Sanika Kulkarni00b9d682019-11-26 09:43:20 -080052 def PreparePayloadPropsFile(self, _inst, *_args, **_kwargs):
53 """Mock out PreparePayloadPropsFile."""
Achuith Bhandarkar4d4275f2019-10-01 17:07:23 +020054
Sanika Kulkarnie3b177b2019-11-26 14:42:48 -080055 def _FixPayloadPropertiesFile(self, _inst, *_args, **_kwargs):
56 """Mock out _FixPayloadPropertiesFile."""
57
58
Mike Frysingerdda695b2019-11-23 20:58:59 -050059class RemoteAccessMock(remote_access_unittest.RemoteShMock):
60 """Mock out RemoteAccess."""
61
62 ATTRS = ('RemoteSh', 'Rsync', 'Scp')
63
64 def Rsync(self, *_args, **_kwargs):
65 return cros_build_lib.CommandResult(returncode=0)
66
67 def Scp(self, *_args, **_kwargs):
68 return cros_build_lib.CommandResult(returncode=0)
69
70
David Pursellf1d16a62015-03-25 13:31:04 -070071class RemoteDeviceUpdaterTest(cros_test_lib.MockTempDirTestCase):
72 """Test the flow of flash.Flash() with RemoteDeviceUpdater."""
73
74 IMAGE = '/path/to/image'
75 DEVICE = commandline.Device(scheme=commandline.DEVICE_SCHEME_SSH,
Mike Frysingerb5a297f2019-11-23 21:17:41 -050076 hostname=remote_access.TEST_IP)
David Pursellf1d16a62015-03-25 13:31:04 -070077
78 def setUp(self):
79 """Patches objects."""
80 self.updater_mock = self.StartPatcher(RemoteDeviceUpdaterMock())
81 self.PatchObject(dev_server_wrapper, 'GenerateXbuddyRequest',
82 return_value='xbuddy/local/latest')
David Pursellf1d16a62015-03-25 13:31:04 -070083 self.PatchObject(dev_server_wrapper, 'GetImagePathWithXbuddy',
Gilad Arnolde62ec902015-04-24 14:41:02 -070084 return_value=('taco-paladin/R36/chromiumos_test_image.bin',
85 'remote/taco-paladin/R36/test'))
Amin Hassanic0f06fa2019-01-28 15:24:47 -080086 self.PatchObject(paygen_payload_lib, 'GenerateUpdatePayload')
87 self.PatchObject(paygen_stateful_payload_lib, 'GenerateStatefulPayload')
David Pursellf1d16a62015-03-25 13:31:04 -070088 self.PatchObject(remote_access, 'CHECK_INTERVAL', new=0)
Mike Frysingerdda695b2019-11-23 20:58:59 -050089 self.PatchObject(remote_access.ChromiumOSDevice, 'Pingable',
90 return_value=True)
91 m = self.StartPatcher(RemoteAccessMock())
92 m.AddCmdResult(['cat', '/etc/lsb-release'],
93 stdout='CHROMEOS_RELEASE_BOARD=board')
94 m.SetDefaultCmdResult()
David Pursellf1d16a62015-03-25 13:31:04 -070095
Achuith Bhandarkar1f54a212019-12-09 12:08:35 -080096 def _ExistsMock(self, path, ret=True):
97 """Mock function for os.path.exists.
98
99 os.path.exists is used a lot; we only want to mock it for devserver/static,
100 and actually check if the file exists in all other cases (using os.access).
101
102 Args:
103 path: path to check.
104 ret: return value of mock.
105
106 Returns:
107 ret for paths under devserver/static, and the expected value of
108 os.path.exists otherwise.
109 """
110 if path.startswith(flash.DEVSERVER_STATIC_DIR):
111 return ret
112 return os.access(path, os.F_OK)
113
David Pursellf1d16a62015-03-25 13:31:04 -0700114 def testUpdateAll(self):
115 """Tests that update methods are called correctly."""
Achuith Bhandarkar1f54a212019-12-09 12:08:35 -0800116 with mock.patch('os.path.exists', side_effect=self._ExistsMock):
Bertrand SIMONNETb34a98b2015-04-22 14:30:04 -0700117 flash.Flash(self.DEVICE, self.IMAGE)
118 self.assertTrue(self.updater_mock.patched['UpdateStateful'].called)
119 self.assertTrue(self.updater_mock.patched['UpdateRootfs'].called)
David Pursellf1d16a62015-03-25 13:31:04 -0700120
121 def testUpdateStateful(self):
122 """Tests that update methods are called correctly."""
Achuith Bhandarkar1f54a212019-12-09 12:08:35 -0800123 with mock.patch('os.path.exists', side_effect=self._ExistsMock):
Bertrand SIMONNETb34a98b2015-04-22 14:30:04 -0700124 flash.Flash(self.DEVICE, self.IMAGE, rootfs_update=False)
125 self.assertTrue(self.updater_mock.patched['UpdateStateful'].called)
126 self.assertFalse(self.updater_mock.patched['UpdateRootfs'].called)
David Pursellf1d16a62015-03-25 13:31:04 -0700127
128 def testUpdateRootfs(self):
129 """Tests that update methods are called correctly."""
Achuith Bhandarkar1f54a212019-12-09 12:08:35 -0800130 with mock.patch('os.path.exists', side_effect=self._ExistsMock):
Bertrand SIMONNETb34a98b2015-04-22 14:30:04 -0700131 flash.Flash(self.DEVICE, self.IMAGE, stateful_update=False)
132 self.assertFalse(self.updater_mock.patched['UpdateStateful'].called)
133 self.assertTrue(self.updater_mock.patched['UpdateRootfs'].called)
David Pursellf1d16a62015-03-25 13:31:04 -0700134
135 def testMissingPayloads(self):
136 """Tests we raise FlashError when payloads are missing."""
Achuith Bhandarkar1f54a212019-12-09 12:08:35 -0800137 with mock.patch('os.path.exists',
138 side_effect=lambda p: self._ExistsMock(p, ret=False)):
Sanika Kulkarnia8c4e3a2019-09-20 16:47:25 -0700139 self.assertRaises(auto_updater_transfer.ChromiumOSTransferError,
140 flash.Flash, self.DEVICE, self.IMAGE)
David Pursellf1d16a62015-03-25 13:31:04 -0700141
Achuith Bhandarkar4d4275f2019-10-01 17:07:23 +0200142 def testFullPayload(self):
143 """Tests that we download full_payload and stateful using xBuddy."""
144 with mock.patch.object(
145 dev_server_wrapper,
146 'GetImagePathWithXbuddy',
147 return_value=('translated/xbuddy/path',
148 'resolved/xbuddy/path')) as mock_xbuddy:
Achuith Bhandarkar1f54a212019-12-09 12:08:35 -0800149 with mock.patch('os.path.exists', side_effect=self._ExistsMock):
Achuith Bhandarkar4d4275f2019-10-01 17:07:23 +0200150 flash.Flash(self.DEVICE, self.IMAGE)
151
152 # Call to download full_payload and stateful. No other calls.
153 mock_xbuddy.assert_has_calls(
154 [mock.call('/path/to/image/full_payload', mock.ANY,
Achuith Bhandarkar12f43c72019-11-21 16:44:24 -0800155 static_dir=flash.DEVSERVER_STATIC_DIR, silent=True),
Achuith Bhandarkar4d4275f2019-10-01 17:07:23 +0200156 mock.call('/path/to/image/stateful', mock.ANY,
Achuith Bhandarkar12f43c72019-11-21 16:44:24 -0800157 static_dir=flash.DEVSERVER_STATIC_DIR, silent=True)])
Achuith Bhandarkar4d4275f2019-10-01 17:07:23 +0200158 self.assertEqual(mock_xbuddy.call_count, 2)
159
160 def testTestImage(self):
161 """Tests that we download the test image when the full payload fails."""
162 with mock.patch.object(
163 dev_server_wrapper,
164 'GetImagePathWithXbuddy',
165 side_effect=(dev_server_wrapper.ImagePathError,
166 ('translated/xbuddy/path',
167 'resolved/xbuddy/path'))) as mock_xbuddy:
Achuith Bhandarkar1f54a212019-12-09 12:08:35 -0800168 with mock.patch('os.path.exists', side_effect=self._ExistsMock):
Achuith Bhandarkar4d4275f2019-10-01 17:07:23 +0200169 flash.Flash(self.DEVICE, self.IMAGE)
170
171 # Call to download full_payload and image. No other calls.
172 mock_xbuddy.assert_has_calls(
173 [mock.call('/path/to/image/full_payload', mock.ANY,
Achuith Bhandarkar12f43c72019-11-21 16:44:24 -0800174 static_dir=flash.DEVSERVER_STATIC_DIR, silent=True),
Achuith Bhandarkar4d4275f2019-10-01 17:07:23 +0200175 mock.call('/path/to/image', mock.ANY,
176 static_dir=flash.DEVSERVER_STATIC_DIR)])
177 self.assertEqual(mock_xbuddy.call_count, 2)
178
David Pursellf1d16a62015-03-25 13:31:04 -0700179
180class USBImagerMock(partial_mock.PartialCmdMock):
181 """Mock out USBImager."""
182 TARGET = 'chromite.cli.flash.USBImager'
183 ATTRS = ('CopyImageToDevice', 'InstallImageToDevice',
184 'ChooseRemovableDevice', 'ListAllRemovableDevices',
Bertrand SIMONNET56f773d2015-05-04 14:02:39 -0700185 'GetRemovableDeviceDescription')
David Pursellf1d16a62015-03-25 13:31:04 -0700186 VALID_IMAGE = True
187
188 def __init__(self):
189 partial_mock.PartialCmdMock.__init__(self)
190
191 def CopyImageToDevice(self, _inst, *_args, **_kwargs):
192 """Mock out CopyImageToDevice."""
193
194 def InstallImageToDevice(self, _inst, *_args, **_kwargs):
195 """Mock out InstallImageToDevice."""
196
197 def ChooseRemovableDevice(self, _inst, *_args, **_kwargs):
198 """Mock out ChooseRemovableDevice."""
199
200 def ListAllRemovableDevices(self, _inst, *_args, **_kwargs):
201 """Mock out ListAllRemovableDevices."""
202 return ['foo', 'taco', 'milk']
203
204 def GetRemovableDeviceDescription(self, _inst, *_args, **_kwargs):
205 """Mock out GetRemovableDeviceDescription."""
206
David Pursellf1d16a62015-03-25 13:31:04 -0700207
208class USBImagerTest(cros_test_lib.MockTempDirTestCase):
209 """Test the flow of flash.Flash() with USBImager."""
210 IMAGE = '/path/to/image'
211
212 def Device(self, path):
213 """Create a USB device for passing to flash.Flash()."""
214 return commandline.Device(scheme=commandline.DEVICE_SCHEME_USB,
215 path=path)
216
217 def setUp(self):
218 """Patches objects."""
219 self.usb_mock = USBImagerMock()
220 self.imager_mock = self.StartPatcher(self.usb_mock)
221 self.PatchObject(dev_server_wrapper, 'GenerateXbuddyRequest',
222 return_value='xbuddy/local/latest')
David Pursellf1d16a62015-03-25 13:31:04 -0700223 self.PatchObject(dev_server_wrapper, 'GetImagePathWithXbuddy',
Gilad Arnolde62ec902015-04-24 14:41:02 -0700224 return_value=('taco-paladin/R36/chromiumos_test_image.bin',
225 'remote/taco-paladin/R36/test'))
David Pursellf1d16a62015-03-25 13:31:04 -0700226 self.PatchObject(os.path, 'exists', return_value=True)
Bertrand SIMONNET56f773d2015-05-04 14:02:39 -0700227 self.isgpt_mock = self.PatchObject(flash, '_IsFilePathGPTDiskImage',
228 return_value=True)
David Pursellf1d16a62015-03-25 13:31:04 -0700229
230 def testLocalImagePathCopy(self):
231 """Tests that imaging methods are called correctly."""
232 with mock.patch('os.path.isfile', return_value=True):
233 flash.Flash(self.Device('/dev/foo'), self.IMAGE)
234 self.assertTrue(self.imager_mock.patched['CopyImageToDevice'].called)
235
236 def testLocalImagePathInstall(self):
237 """Tests that imaging methods are called correctly."""
238 with mock.patch('os.path.isfile', return_value=True):
239 flash.Flash(self.Device('/dev/foo'), self.IMAGE, board='taco',
240 install=True)
241 self.assertTrue(self.imager_mock.patched['InstallImageToDevice'].called)
242
243 def testLocalBadImagePath(self):
244 """Tests that using an image not having the magic bytes has prompt."""
Bertrand SIMONNET56f773d2015-05-04 14:02:39 -0700245 self.isgpt_mock.return_value = False
David Pursellf1d16a62015-03-25 13:31:04 -0700246 with mock.patch('os.path.isfile', return_value=True):
247 with mock.patch.object(cros_build_lib, 'BooleanPrompt') as mock_prompt:
248 mock_prompt.return_value = False
249 flash.Flash(self.Device('/dev/foo'), self.IMAGE)
250 self.assertTrue(mock_prompt.called)
251
252 def testNonLocalImagePath(self):
253 """Tests that we try to get the image path using xbuddy."""
254 with mock.patch.object(
255 dev_server_wrapper,
256 'GetImagePathWithXbuddy',
Gilad Arnolde62ec902015-04-24 14:41:02 -0700257 return_value=('translated/xbuddy/path',
258 'resolved/xbuddy/path')) as mock_xbuddy:
David Pursellf1d16a62015-03-25 13:31:04 -0700259 with mock.patch('os.path.isfile', return_value=False):
260 with mock.patch('os.path.isdir', return_value=False):
261 flash.Flash(self.Device('/dev/foo'), self.IMAGE)
262 self.assertTrue(mock_xbuddy.called)
263
264 def testConfirmNonRemovableDevice(self):
265 """Tests that we ask user to confirm if the device is not removable."""
266 with mock.patch.object(cros_build_lib, 'BooleanPrompt') as mock_prompt:
267 flash.Flash(self.Device('/dev/dummy'), self.IMAGE)
268 self.assertTrue(mock_prompt.called)
269
270 def testSkipPromptNonRemovableDevice(self):
271 """Tests that we skip the prompt for non-removable with --yes."""
272 with mock.patch.object(cros_build_lib, 'BooleanPrompt') as mock_prompt:
273 flash.Flash(self.Device('/dev/dummy'), self.IMAGE, yes=True)
274 self.assertFalse(mock_prompt.called)
275
276 def testChooseRemovableDevice(self):
277 """Tests that we ask user to choose a device if none is given."""
278 flash.Flash(self.Device(''), self.IMAGE)
279 self.assertTrue(self.imager_mock.patched['ChooseRemovableDevice'].called)
Bertrand SIMONNET56f773d2015-05-04 14:02:39 -0700280
281
Benjamin Gordon121a2aa2018-05-04 16:24:45 -0600282class UsbImagerOperationTest(cros_test_lib.RunCommandTestCase):
Ralph Nathan9b997232015-05-15 13:13:12 -0700283 """Tests for flash.UsbImagerOperation."""
284 # pylint: disable=protected-access
285
286 def setUp(self):
287 self.PatchObject(flash.UsbImagerOperation, '__init__', return_value=None)
288
289 def testUsbImagerOperationCalled(self):
290 """Test that flash.UsbImagerOperation is called when log level <= NOTICE."""
291 expected_cmd = ['dd', 'if=foo', 'of=bar', 'bs=4M', 'iflag=fullblock',
Frank Huang8e626432019-06-24 19:51:08 +0800292 'oflag=direct', 'conv=fdatasync']
Ralph Nathan9b997232015-05-15 13:13:12 -0700293 usb_imager = flash.USBImager('dummy_device', 'board', 'foo')
294 run_mock = self.PatchObject(flash.UsbImagerOperation, 'Run')
295 self.PatchObject(logging.Logger, 'getEffectiveLevel',
296 return_value=logging.NOTICE)
297 usb_imager.CopyImageToDevice('foo', 'bar')
298
299 # Check that flash.UsbImagerOperation.Run() is called correctly.
Mike Frysinger45602c72019-09-22 02:15:11 -0400300 run_mock.assert_called_with(cros_build_lib.sudo_run, expected_cmd,
Mike Frysinger3d5de8f2019-10-23 00:48:39 -0400301 debug_level=logging.NOTICE, encoding='utf-8',
302 update_period=0.5)
Ralph Nathan9b997232015-05-15 13:13:12 -0700303
304 def testSudoRunCommandCalled(self):
Mike Frysinger45602c72019-09-22 02:15:11 -0400305 """Test that sudo_run is called when log level > NOTICE."""
Ralph Nathan9b997232015-05-15 13:13:12 -0700306 expected_cmd = ['dd', 'if=foo', 'of=bar', 'bs=4M', 'iflag=fullblock',
Frank Huang8e626432019-06-24 19:51:08 +0800307 'oflag=direct', 'conv=fdatasync']
Ralph Nathan9b997232015-05-15 13:13:12 -0700308 usb_imager = flash.USBImager('dummy_device', 'board', 'foo')
Mike Frysinger45602c72019-09-22 02:15:11 -0400309 run_mock = self.PatchObject(cros_build_lib, 'sudo_run')
Ralph Nathan9b997232015-05-15 13:13:12 -0700310 self.PatchObject(logging.Logger, 'getEffectiveLevel',
311 return_value=logging.WARNING)
312 usb_imager.CopyImageToDevice('foo', 'bar')
313
Mike Frysinger45602c72019-09-22 02:15:11 -0400314 # Check that sudo_run() is called correctly.
Ralph Nathan9b997232015-05-15 13:13:12 -0700315 run_mock.assert_any_call(expected_cmd, debug_level=logging.NOTICE,
316 print_cmd=False)
317
318 def testPingDD(self):
319 """Test that UsbImagerOperation._PingDD() sends the correct signal."""
320 expected_cmd = ['kill', '-USR1', '5']
Mike Frysinger45602c72019-09-22 02:15:11 -0400321 run_mock = self.PatchObject(cros_build_lib, 'sudo_run')
Ralph Nathan9b997232015-05-15 13:13:12 -0700322 op = flash.UsbImagerOperation('foo')
323 op._PingDD(5)
324
Mike Frysinger45602c72019-09-22 02:15:11 -0400325 # Check that sudo_run was called correctly.
Ralph Nathan9b997232015-05-15 13:13:12 -0700326 run_mock.assert_called_with(expected_cmd, print_cmd=False)
327
328 def testGetDDPidFound(self):
329 """Check that the expected pid is returned for _GetDDPid()."""
330 expected_pid = 5
331 op = flash.UsbImagerOperation('foo')
332 self.PatchObject(osutils, 'IsChildProcess', return_value=True)
333 self.rc.AddCmdResult(partial_mock.Ignore(),
334 output='%d\n10\n' % expected_pid)
335
336 pid = op._GetDDPid()
337
338 # Check that the correct pid was returned.
339 self.assertEqual(pid, expected_pid)
340
341 def testGetDDPidNotFound(self):
342 """Check that -1 is returned for _GetDDPid() if the pids aren't valid."""
343 expected_pid = -1
344 op = flash.UsbImagerOperation('foo')
345 self.PatchObject(osutils, 'IsChildProcess', return_value=False)
346 self.rc.AddCmdResult(partial_mock.Ignore(), output='5\n10\n')
347
348 pid = op._GetDDPid()
349
350 # Check that the correct pid was returned.
351 self.assertEqual(pid, expected_pid)
352
353
Bertrand SIMONNET56f773d2015-05-04 14:02:39 -0700354class FlashUtilTest(cros_test_lib.MockTempDirTestCase):
355 """Tests the helpers from cli.flash."""
356
357 def testChooseImage(self):
358 """Tests that we can detect a GPT image."""
359 # pylint: disable=protected-access
360
361 with self.PatchObject(flash, '_IsFilePathGPTDiskImage', return_value=True):
362 # No images defined. Choosing the image should raise an error.
363 with self.assertRaises(ValueError):
364 flash._ChooseImageFromDirectory(self.tempdir)
365
366 file_a = os.path.join(self.tempdir, 'a')
367 osutils.Touch(file_a)
368 # Only one image available, it should be selected automatically.
369 self.assertEqual(file_a, flash._ChooseImageFromDirectory(self.tempdir))
370
371 osutils.Touch(os.path.join(self.tempdir, 'b'))
372 file_c = os.path.join(self.tempdir, 'c')
373 osutils.Touch(file_c)
374 osutils.Touch(os.path.join(self.tempdir, 'd'))
375
376 # Multiple images available, we should ask the user to select the right
377 # image.
378 with self.PatchObject(cros_build_lib, 'GetChoice', return_value=2):
379 self.assertEqual(file_c, flash._ChooseImageFromDirectory(self.tempdir))
Mike Frysinger32759e42016-12-21 18:40:16 -0500380
381 def testIsFilePathGPTDiskImage(self):
382 """Tests the GPT image probing."""
383 # pylint: disable=protected-access
384
Mike Frysinger3d5de8f2019-10-23 00:48:39 -0400385 INVALID_PMBR = b' ' * 0x200
386 INVALID_GPT = b' ' * 0x200
387 VALID_PMBR = (b' ' * 0x1fe) + b'\x55\xaa'
388 VALID_GPT = b'EFI PART' + (b' ' * 0x1f8)
Mike Frysinger32759e42016-12-21 18:40:16 -0500389 TESTCASES = (
390 (False, False, INVALID_PMBR + INVALID_GPT),
391 (False, False, VALID_PMBR + INVALID_GPT),
392 (False, True, INVALID_PMBR + VALID_GPT),
393 (True, True, VALID_PMBR + VALID_GPT),
394 )
395
396 img = os.path.join(self.tempdir, 'img.bin')
397 for exp_pmbr_t, exp_pmbr_f, data in TESTCASES:
Mike Frysinger3d5de8f2019-10-23 00:48:39 -0400398 osutils.WriteFile(img, data, mode='wb')
Mike Frysinger32759e42016-12-21 18:40:16 -0500399 self.assertEqual(
400 flash._IsFilePathGPTDiskImage(img, require_pmbr=True), exp_pmbr_t)
401 self.assertEqual(
402 flash._IsFilePathGPTDiskImage(img, require_pmbr=False), exp_pmbr_f)