blob: 48816539ef407521df266b2df65650574802a67c [file] [log] [blame]
Gilad Arnoldf583a7d2015-02-05 13:23:55 -08001#!/usr/bin/python2
Gilad Arnold5502b562013-03-08 13:22:31 -08002#
Amin Hassanif94b6432018-01-26 17:39:47 -08003# Copyright (C) 2013 The Android Open Source Project
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16#
Gilad Arnold5502b562013-03-08 13:22:31 -080017
18"""Unit testing checker.py."""
19
Gilad Arnoldf583a7d2015-02-05 13:23:55 -080020from __future__ import print_function
21
Gilad Arnold5502b562013-03-08 13:22:31 -080022import array
23import collections
24import cStringIO
25import hashlib
26import itertools
27import os
28import unittest
29
Gilad Arnoldcb638912013-06-24 04:57:11 -070030# pylint cannot find mox.
Gilad Arnold5502b562013-03-08 13:22:31 -080031# pylint: disable=F0401
32import mox
33
Amin Hassanib05a65a2017-12-18 15:15:32 -080034from update_payload import checker
35from update_payload import common
36from update_payload import test_utils
37from update_payload import update_metadata_pb2
38from update_payload.error import PayloadError
39from update_payload.payload import Payload # Avoid name conflicts later.
Gilad Arnold5502b562013-03-08 13:22:31 -080040
41
Gilad Arnold5502b562013-03-08 13:22:31 -080042def _OpTypeByName(op_name):
Amin Hassanib05a65a2017-12-18 15:15:32 -080043 """Returns the type of an operation from itsname."""
Gilad Arnold5502b562013-03-08 13:22:31 -080044 op_name_to_type = {
45 'REPLACE': common.OpType.REPLACE,
46 'REPLACE_BZ': common.OpType.REPLACE_BZ,
Allie Woodf5c4f3e2015-02-20 16:57:46 -080047 'SOURCE_COPY': common.OpType.SOURCE_COPY,
48 'SOURCE_BSDIFF': common.OpType.SOURCE_BSDIFF,
Alex Deymo28466772015-09-11 17:16:44 -070049 'ZERO': common.OpType.ZERO,
50 'DISCARD': common.OpType.DISCARD,
51 'REPLACE_XZ': common.OpType.REPLACE_XZ,
Amin Hassani5ef5d452017-08-04 13:10:59 -070052 'PUFFDIFF': common.OpType.PUFFDIFF,
Amin Hassaniefa62d92017-11-09 13:46:56 -080053 'BROTLI_BSDIFF': common.OpType.BROTLI_BSDIFF,
Gilad Arnold5502b562013-03-08 13:22:31 -080054 }
55 return op_name_to_type[op_name]
56
57
Gilad Arnoldeaed0d12013-04-30 15:38:22 -070058def _GetPayloadChecker(payload_gen_write_to_file_func, payload_gen_dargs=None,
59 checker_init_dargs=None):
Gilad Arnold5502b562013-03-08 13:22:31 -080060 """Returns a payload checker from a given payload generator."""
Gilad Arnoldeaed0d12013-04-30 15:38:22 -070061 if payload_gen_dargs is None:
62 payload_gen_dargs = {}
63 if checker_init_dargs is None:
64 checker_init_dargs = {}
65
Gilad Arnold5502b562013-03-08 13:22:31 -080066 payload_file = cStringIO.StringIO()
Gilad Arnoldeaed0d12013-04-30 15:38:22 -070067 payload_gen_write_to_file_func(payload_file, **payload_gen_dargs)
Gilad Arnold5502b562013-03-08 13:22:31 -080068 payload_file.seek(0)
Amin Hassanib05a65a2017-12-18 15:15:32 -080069 payload = Payload(payload_file)
Gilad Arnold5502b562013-03-08 13:22:31 -080070 payload.Init()
Gilad Arnoldeaed0d12013-04-30 15:38:22 -070071 return checker.PayloadChecker(payload, **checker_init_dargs)
Gilad Arnold5502b562013-03-08 13:22:31 -080072
73
74def _GetPayloadCheckerWithData(payload_gen):
75 """Returns a payload checker from a given payload generator."""
76 payload_file = cStringIO.StringIO()
77 payload_gen.WriteToFile(payload_file)
78 payload_file.seek(0)
Amin Hassanib05a65a2017-12-18 15:15:32 -080079 payload = Payload(payload_file)
Gilad Arnold5502b562013-03-08 13:22:31 -080080 payload.Init()
81 return checker.PayloadChecker(payload)
82
83
Gilad Arnoldcb638912013-06-24 04:57:11 -070084# This class doesn't need an __init__().
Gilad Arnold5502b562013-03-08 13:22:31 -080085# pylint: disable=W0232
Gilad Arnoldcb638912013-06-24 04:57:11 -070086# Unit testing is all about running protected methods.
Gilad Arnold5502b562013-03-08 13:22:31 -080087# pylint: disable=W0212
Gilad Arnoldcb638912013-06-24 04:57:11 -070088# Don't bark about missing members of classes you cannot import.
Gilad Arnold5502b562013-03-08 13:22:31 -080089# pylint: disable=E1101
90class PayloadCheckerTest(mox.MoxTestBase):
91 """Tests the PayloadChecker class.
92
93 In addition to ordinary testFoo() methods, which are automatically invoked by
94 the unittest framework, in this class we make use of DoBarTest() calls that
95 implement parametric tests of certain features. In order to invoke each test,
96 which embodies a unique combination of parameter values, as a complete unit
97 test, we perform explicit enumeration of the parameter space and create
98 individual invocation contexts for each, which are then bound as
99 testBar__param1=val1__param2=val2(). The enumeration of parameter spaces for
100 all such tests is done in AddAllParametricTests().
Gilad Arnold5502b562013-03-08 13:22:31 -0800101 """
102
103 def MockPayload(self):
Allie Woodf5c4f3e2015-02-20 16:57:46 -0800104 """Create a mock payload object, complete with a mock manifest."""
Amin Hassanib05a65a2017-12-18 15:15:32 -0800105 payload = self.mox.CreateMock(Payload)
Gilad Arnold5502b562013-03-08 13:22:31 -0800106 payload.is_init = True
107 payload.manifest = self.mox.CreateMock(
108 update_metadata_pb2.DeltaArchiveManifest)
109 return payload
110
111 @staticmethod
112 def NewExtent(start_block, num_blocks):
113 """Returns an Extent message.
114
115 Each of the provided fields is set iff it is >= 0; otherwise, it's left at
116 its default state.
117
118 Args:
Gilad Arnoldcb638912013-06-24 04:57:11 -0700119 start_block: The starting block of the extent.
120 num_blocks: The number of blocks in the extent.
Gilad Arnoldf583a7d2015-02-05 13:23:55 -0800121
Gilad Arnold5502b562013-03-08 13:22:31 -0800122 Returns:
123 An Extent message.
Gilad Arnold5502b562013-03-08 13:22:31 -0800124 """
125 ex = update_metadata_pb2.Extent()
126 if start_block >= 0:
127 ex.start_block = start_block
128 if num_blocks >= 0:
129 ex.num_blocks = num_blocks
130 return ex
131
132 @staticmethod
133 def NewExtentList(*args):
134 """Returns an list of extents.
135
136 Args:
Gilad Arnoldcb638912013-06-24 04:57:11 -0700137 *args: (start_block, num_blocks) pairs defining the extents.
Gilad Arnoldf583a7d2015-02-05 13:23:55 -0800138
Gilad Arnold5502b562013-03-08 13:22:31 -0800139 Returns:
140 A list of Extent objects.
Gilad Arnold5502b562013-03-08 13:22:31 -0800141 """
142 ex_list = []
143 for start_block, num_blocks in args:
144 ex_list.append(PayloadCheckerTest.NewExtent(start_block, num_blocks))
145 return ex_list
146
147 @staticmethod
148 def AddToMessage(repeated_field, field_vals):
149 for field_val in field_vals:
150 new_field = repeated_field.add()
151 new_field.CopyFrom(field_val)
152
Gilad Arnold5502b562013-03-08 13:22:31 -0800153 def SetupAddElemTest(self, is_present, is_submsg, convert=str,
154 linebreak=False, indent=0):
155 """Setup for testing of _CheckElem() and its derivatives.
156
157 Args:
Gilad Arnoldcb638912013-06-24 04:57:11 -0700158 is_present: Whether or not the element is found in the message.
159 is_submsg: Whether the element is a sub-message itself.
160 convert: A representation conversion function.
161 linebreak: Whether or not a linebreak is to be used in the report.
162 indent: Indentation used for the report.
Gilad Arnoldf583a7d2015-02-05 13:23:55 -0800163
Gilad Arnold5502b562013-03-08 13:22:31 -0800164 Returns:
Gilad Arnoldcb638912013-06-24 04:57:11 -0700165 msg: A mock message object.
166 report: A mock report object.
167 subreport: A mock sub-report object.
168 name: An element name to check.
169 val: Expected element value.
Gilad Arnold5502b562013-03-08 13:22:31 -0800170 """
171 name = 'foo'
172 val = 'fake submsg' if is_submsg else 'fake field'
173 subreport = 'fake subreport'
174
175 # Create a mock message.
Alex Deymo28466772015-09-11 17:16:44 -0700176 msg = self.mox.CreateMock(update_metadata_pb2._message.Message)
Gilad Arnold5502b562013-03-08 13:22:31 -0800177 msg.HasField(name).AndReturn(is_present)
178 setattr(msg, name, val)
179
180 # Create a mock report.
181 report = self.mox.CreateMock(checker._PayloadReport)
182 if is_present:
183 if is_submsg:
184 report.AddSubReport(name).AndReturn(subreport)
185 else:
186 report.AddField(name, convert(val), linebreak=linebreak, indent=indent)
187
188 self.mox.ReplayAll()
189 return (msg, report, subreport, name, val)
190
191 def DoAddElemTest(self, is_present, is_mandatory, is_submsg, convert,
192 linebreak, indent):
193 """Parametric testing of _CheckElem().
194
195 Args:
Gilad Arnoldcb638912013-06-24 04:57:11 -0700196 is_present: Whether or not the element is found in the message.
197 is_mandatory: Whether or not it's a mandatory element.
198 is_submsg: Whether the element is a sub-message itself.
199 convert: A representation conversion function.
200 linebreak: Whether or not a linebreak is to be used in the report.
201 indent: Indentation used for the report.
Gilad Arnold5502b562013-03-08 13:22:31 -0800202 """
203 msg, report, subreport, name, val = self.SetupAddElemTest(
204 is_present, is_submsg, convert, linebreak, indent)
205
Gilad Arnoldcb638912013-06-24 04:57:11 -0700206 args = (msg, name, report, is_mandatory, is_submsg)
207 kwargs = {'convert': convert, 'linebreak': linebreak, 'indent': indent}
Gilad Arnold5502b562013-03-08 13:22:31 -0800208 if is_mandatory and not is_present:
Amin Hassanib05a65a2017-12-18 15:15:32 -0800209 self.assertRaises(PayloadError,
Gilad Arnoldcb638912013-06-24 04:57:11 -0700210 checker.PayloadChecker._CheckElem, *args, **kwargs)
Gilad Arnold5502b562013-03-08 13:22:31 -0800211 else:
Gilad Arnoldcb638912013-06-24 04:57:11 -0700212 ret_val, ret_subreport = checker.PayloadChecker._CheckElem(*args,
213 **kwargs)
214 self.assertEquals(val if is_present else None, ret_val)
215 self.assertEquals(subreport if is_present and is_submsg else None,
216 ret_subreport)
Gilad Arnold5502b562013-03-08 13:22:31 -0800217
218 def DoAddFieldTest(self, is_mandatory, is_present, convert, linebreak,
219 indent):
220 """Parametric testing of _Check{Mandatory,Optional}Field().
221
222 Args:
Gilad Arnoldcb638912013-06-24 04:57:11 -0700223 is_mandatory: Whether we're testing a mandatory call.
224 is_present: Whether or not the element is found in the message.
225 convert: A representation conversion function.
226 linebreak: Whether or not a linebreak is to be used in the report.
227 indent: Indentation used for the report.
Gilad Arnold5502b562013-03-08 13:22:31 -0800228 """
229 msg, report, _, name, val = self.SetupAddElemTest(
230 is_present, False, convert, linebreak, indent)
231
232 # Prepare for invocation of the tested method.
Gilad Arnoldcb638912013-06-24 04:57:11 -0700233 args = [msg, name, report]
234 kwargs = {'convert': convert, 'linebreak': linebreak, 'indent': indent}
Gilad Arnold5502b562013-03-08 13:22:31 -0800235 if is_mandatory:
Gilad Arnoldcb638912013-06-24 04:57:11 -0700236 args.append('bar')
Gilad Arnold5502b562013-03-08 13:22:31 -0800237 tested_func = checker.PayloadChecker._CheckMandatoryField
238 else:
239 tested_func = checker.PayloadChecker._CheckOptionalField
240
241 # Test the method call.
242 if is_mandatory and not is_present:
Amin Hassanib05a65a2017-12-18 15:15:32 -0800243 self.assertRaises(PayloadError, tested_func, *args, **kwargs)
Gilad Arnold5502b562013-03-08 13:22:31 -0800244 else:
Gilad Arnoldcb638912013-06-24 04:57:11 -0700245 ret_val = tested_func(*args, **kwargs)
246 self.assertEquals(val if is_present else None, ret_val)
Gilad Arnold5502b562013-03-08 13:22:31 -0800247
248 def DoAddSubMsgTest(self, is_mandatory, is_present):
249 """Parametrized testing of _Check{Mandatory,Optional}SubMsg().
250
251 Args:
Gilad Arnoldcb638912013-06-24 04:57:11 -0700252 is_mandatory: Whether we're testing a mandatory call.
253 is_present: Whether or not the element is found in the message.
Gilad Arnold5502b562013-03-08 13:22:31 -0800254 """
255 msg, report, subreport, name, val = self.SetupAddElemTest(is_present, True)
256
257 # Prepare for invocation of the tested method.
Gilad Arnoldcb638912013-06-24 04:57:11 -0700258 args = [msg, name, report]
Gilad Arnold5502b562013-03-08 13:22:31 -0800259 if is_mandatory:
Gilad Arnoldcb638912013-06-24 04:57:11 -0700260 args.append('bar')
Gilad Arnold5502b562013-03-08 13:22:31 -0800261 tested_func = checker.PayloadChecker._CheckMandatorySubMsg
262 else:
263 tested_func = checker.PayloadChecker._CheckOptionalSubMsg
264
265 # Test the method call.
266 if is_mandatory and not is_present:
Amin Hassanib05a65a2017-12-18 15:15:32 -0800267 self.assertRaises(PayloadError, tested_func, *args)
Gilad Arnold5502b562013-03-08 13:22:31 -0800268 else:
Gilad Arnoldcb638912013-06-24 04:57:11 -0700269 ret_val, ret_subreport = tested_func(*args)
270 self.assertEquals(val if is_present else None, ret_val)
271 self.assertEquals(subreport if is_present else None, ret_subreport)
Gilad Arnold5502b562013-03-08 13:22:31 -0800272
273 def testCheckPresentIff(self):
274 """Tests _CheckPresentIff()."""
275 self.assertIsNone(checker.PayloadChecker._CheckPresentIff(
276 None, None, 'foo', 'bar', 'baz'))
277 self.assertIsNone(checker.PayloadChecker._CheckPresentIff(
278 'a', 'b', 'foo', 'bar', 'baz'))
Amin Hassanib05a65a2017-12-18 15:15:32 -0800279 self.assertRaises(PayloadError, checker.PayloadChecker._CheckPresentIff,
Gilad Arnold5502b562013-03-08 13:22:31 -0800280 'a', None, 'foo', 'bar', 'baz')
Amin Hassanib05a65a2017-12-18 15:15:32 -0800281 self.assertRaises(PayloadError, checker.PayloadChecker._CheckPresentIff,
Gilad Arnold5502b562013-03-08 13:22:31 -0800282 None, 'b', 'foo', 'bar', 'baz')
283
284 def DoCheckSha256SignatureTest(self, expect_pass, expect_subprocess_call,
285 sig_data, sig_asn1_header,
286 returned_signed_hash, expected_signed_hash):
287 """Parametric testing of _CheckSha256SignatureTest().
288
289 Args:
Gilad Arnoldcb638912013-06-24 04:57:11 -0700290 expect_pass: Whether or not it should pass.
291 expect_subprocess_call: Whether to expect the openssl call to happen.
292 sig_data: The signature raw data.
293 sig_asn1_header: The ASN1 header.
294 returned_signed_hash: The signed hash data retuned by openssl.
295 expected_signed_hash: The signed hash data to compare against.
Gilad Arnold5502b562013-03-08 13:22:31 -0800296 """
Gilad Arnoldcb638912013-06-24 04:57:11 -0700297 try:
298 # Stub out the subprocess invocation.
299 self.mox.StubOutWithMock(checker.PayloadChecker, '_Run')
300 if expect_subprocess_call:
301 checker.PayloadChecker._Run(
302 mox.IsA(list), send_data=sig_data).AndReturn(
303 (sig_asn1_header + returned_signed_hash, None))
Gilad Arnold5502b562013-03-08 13:22:31 -0800304
Gilad Arnoldcb638912013-06-24 04:57:11 -0700305 self.mox.ReplayAll()
306 if expect_pass:
307 self.assertIsNone(checker.PayloadChecker._CheckSha256Signature(
308 sig_data, 'foo', expected_signed_hash, 'bar'))
309 else:
Amin Hassanib05a65a2017-12-18 15:15:32 -0800310 self.assertRaises(PayloadError,
Gilad Arnoldcb638912013-06-24 04:57:11 -0700311 checker.PayloadChecker._CheckSha256Signature,
312 sig_data, 'foo', expected_signed_hash, 'bar')
313 finally:
314 self.mox.UnsetStubs()
Gilad Arnold5502b562013-03-08 13:22:31 -0800315
316 def testCheckSha256Signature_Pass(self):
317 """Tests _CheckSha256Signature(); pass case."""
318 sig_data = 'fake-signature'.ljust(256)
319 signed_hash = hashlib.sha256('fake-data').digest()
320 self.DoCheckSha256SignatureTest(True, True, sig_data,
321 common.SIG_ASN1_HEADER, signed_hash,
322 signed_hash)
323
324 def testCheckSha256Signature_FailBadSignature(self):
325 """Tests _CheckSha256Signature(); fails due to malformed signature."""
Gilad Arnoldcb638912013-06-24 04:57:11 -0700326 sig_data = 'fake-signature' # Malformed (not 256 bytes in length).
Gilad Arnold5502b562013-03-08 13:22:31 -0800327 signed_hash = hashlib.sha256('fake-data').digest()
328 self.DoCheckSha256SignatureTest(False, False, sig_data,
329 common.SIG_ASN1_HEADER, signed_hash,
330 signed_hash)
331
332 def testCheckSha256Signature_FailBadOutputLength(self):
333 """Tests _CheckSha256Signature(); fails due to unexpected output length."""
334 sig_data = 'fake-signature'.ljust(256)
Gilad Arnoldcb638912013-06-24 04:57:11 -0700335 signed_hash = 'fake-hash' # Malformed (not 32 bytes in length).
Gilad Arnold5502b562013-03-08 13:22:31 -0800336 self.DoCheckSha256SignatureTest(False, True, sig_data,
337 common.SIG_ASN1_HEADER, signed_hash,
338 signed_hash)
339
340 def testCheckSha256Signature_FailBadAsnHeader(self):
341 """Tests _CheckSha256Signature(); fails due to bad ASN1 header."""
342 sig_data = 'fake-signature'.ljust(256)
343 signed_hash = hashlib.sha256('fake-data').digest()
344 bad_asn1_header = 'bad-asn-header'.ljust(len(common.SIG_ASN1_HEADER))
345 self.DoCheckSha256SignatureTest(False, True, sig_data, bad_asn1_header,
346 signed_hash, signed_hash)
347
348 def testCheckSha256Signature_FailBadHash(self):
349 """Tests _CheckSha256Signature(); fails due to bad hash returned."""
350 sig_data = 'fake-signature'.ljust(256)
351 expected_signed_hash = hashlib.sha256('fake-data').digest()
352 returned_signed_hash = hashlib.sha256('bad-fake-data').digest()
353 self.DoCheckSha256SignatureTest(False, True, sig_data,
354 common.SIG_ASN1_HEADER,
355 expected_signed_hash, returned_signed_hash)
356
357 def testCheckBlocksFitLength_Pass(self):
358 """Tests _CheckBlocksFitLength(); pass case."""
359 self.assertIsNone(checker.PayloadChecker._CheckBlocksFitLength(
360 64, 4, 16, 'foo'))
361 self.assertIsNone(checker.PayloadChecker._CheckBlocksFitLength(
362 60, 4, 16, 'foo'))
363 self.assertIsNone(checker.PayloadChecker._CheckBlocksFitLength(
364 49, 4, 16, 'foo'))
365 self.assertIsNone(checker.PayloadChecker._CheckBlocksFitLength(
366 48, 3, 16, 'foo'))
367
368 def testCheckBlocksFitLength_TooManyBlocks(self):
369 """Tests _CheckBlocksFitLength(); fails due to excess blocks."""
Amin Hassanib05a65a2017-12-18 15:15:32 -0800370 self.assertRaises(PayloadError,
Gilad Arnold5502b562013-03-08 13:22:31 -0800371 checker.PayloadChecker._CheckBlocksFitLength,
372 64, 5, 16, 'foo')
Amin Hassanib05a65a2017-12-18 15:15:32 -0800373 self.assertRaises(PayloadError,
Gilad Arnold5502b562013-03-08 13:22:31 -0800374 checker.PayloadChecker._CheckBlocksFitLength,
375 60, 5, 16, 'foo')
Amin Hassanib05a65a2017-12-18 15:15:32 -0800376 self.assertRaises(PayloadError,
Gilad Arnold5502b562013-03-08 13:22:31 -0800377 checker.PayloadChecker._CheckBlocksFitLength,
378 49, 5, 16, 'foo')
Amin Hassanib05a65a2017-12-18 15:15:32 -0800379 self.assertRaises(PayloadError,
Gilad Arnold5502b562013-03-08 13:22:31 -0800380 checker.PayloadChecker._CheckBlocksFitLength,
381 48, 4, 16, 'foo')
382
383 def testCheckBlocksFitLength_TooFewBlocks(self):
384 """Tests _CheckBlocksFitLength(); fails due to insufficient blocks."""
Amin Hassanib05a65a2017-12-18 15:15:32 -0800385 self.assertRaises(PayloadError,
Gilad Arnold5502b562013-03-08 13:22:31 -0800386 checker.PayloadChecker._CheckBlocksFitLength,
387 64, 3, 16, 'foo')
Amin Hassanib05a65a2017-12-18 15:15:32 -0800388 self.assertRaises(PayloadError,
Gilad Arnold5502b562013-03-08 13:22:31 -0800389 checker.PayloadChecker._CheckBlocksFitLength,
390 60, 3, 16, 'foo')
Amin Hassanib05a65a2017-12-18 15:15:32 -0800391 self.assertRaises(PayloadError,
Gilad Arnold5502b562013-03-08 13:22:31 -0800392 checker.PayloadChecker._CheckBlocksFitLength,
393 49, 3, 16, 'foo')
Amin Hassanib05a65a2017-12-18 15:15:32 -0800394 self.assertRaises(PayloadError,
Gilad Arnold5502b562013-03-08 13:22:31 -0800395 checker.PayloadChecker._CheckBlocksFitLength,
396 48, 2, 16, 'foo')
397
398 def DoCheckManifestTest(self, fail_mismatched_block_size, fail_bad_sigs,
399 fail_mismatched_oki_ori, fail_bad_oki, fail_bad_ori,
Gilad Arnold5bc7fbe2015-02-05 13:01:09 -0800400 fail_bad_nki, fail_bad_nri, fail_old_kernel_fs_size,
401 fail_old_rootfs_fs_size, fail_new_kernel_fs_size,
402 fail_new_rootfs_fs_size):
Gilad Arnold5502b562013-03-08 13:22:31 -0800403 """Parametric testing of _CheckManifest().
404
405 Args:
Gilad Arnoldcb638912013-06-24 04:57:11 -0700406 fail_mismatched_block_size: Simulate a missing block_size field.
407 fail_bad_sigs: Make signatures descriptor inconsistent.
408 fail_mismatched_oki_ori: Make old rootfs/kernel info partially present.
409 fail_bad_oki: Tamper with old kernel info.
410 fail_bad_ori: Tamper with old rootfs info.
411 fail_bad_nki: Tamper with new kernel info.
412 fail_bad_nri: Tamper with new rootfs info.
Gilad Arnoldcb638912013-06-24 04:57:11 -0700413 fail_old_kernel_fs_size: Make old kernel fs size too big.
414 fail_old_rootfs_fs_size: Make old rootfs fs size too big.
415 fail_new_kernel_fs_size: Make new kernel fs size too big.
416 fail_new_rootfs_fs_size: Make new rootfs fs size too big.
Gilad Arnold5502b562013-03-08 13:22:31 -0800417 """
418 # Generate a test payload. For this test, we only care about the manifest
419 # and don't need any data blobs, hence we can use a plain paylaod generator
420 # (which also gives us more control on things that can be screwed up).
421 payload_gen = test_utils.PayloadGenerator()
422
423 # Tamper with block size, if required.
424 if fail_mismatched_block_size:
Gilad Arnold18f4f9f2013-04-02 16:24:41 -0700425 payload_gen.SetBlockSize(test_utils.KiB(1))
Gilad Arnold5502b562013-03-08 13:22:31 -0800426 else:
Gilad Arnold18f4f9f2013-04-02 16:24:41 -0700427 payload_gen.SetBlockSize(test_utils.KiB(4))
Gilad Arnold5502b562013-03-08 13:22:31 -0800428
429 # Add some operations.
Amin Hassani55c75412019-10-07 11:20:39 -0700430 payload_gen.AddOperation(common.ROOTFS, common.OpType.SOURCE_COPY,
Gilad Arnold5bc7fbe2015-02-05 13:01:09 -0800431 src_extents=[(0, 16), (16, 497)],
432 dst_extents=[(16, 496), (0, 16)])
Amin Hassani55c75412019-10-07 11:20:39 -0700433 payload_gen.AddOperation(common.KERNEL, common.OpType.SOURCE_COPY,
Gilad Arnold5bc7fbe2015-02-05 13:01:09 -0800434 src_extents=[(0, 8), (8, 8)],
435 dst_extents=[(8, 8), (0, 8)])
Gilad Arnold5502b562013-03-08 13:22:31 -0800436
437 # Set an invalid signatures block (offset but no size), if required.
438 if fail_bad_sigs:
439 payload_gen.SetSignatures(32, None)
440
Gilad Arnold382df5c2013-05-03 12:49:28 -0700441 # Set partition / filesystem sizes.
Gilad Arnold18f4f9f2013-04-02 16:24:41 -0700442 rootfs_part_size = test_utils.MiB(8)
443 kernel_part_size = test_utils.KiB(512)
Gilad Arnold382df5c2013-05-03 12:49:28 -0700444 old_rootfs_fs_size = new_rootfs_fs_size = rootfs_part_size
445 old_kernel_fs_size = new_kernel_fs_size = kernel_part_size
446 if fail_old_kernel_fs_size:
447 old_kernel_fs_size += 100
448 if fail_old_rootfs_fs_size:
449 old_rootfs_fs_size += 100
450 if fail_new_kernel_fs_size:
451 new_kernel_fs_size += 100
452 if fail_new_rootfs_fs_size:
453 new_rootfs_fs_size += 100
454
Gilad Arnold5502b562013-03-08 13:22:31 -0800455 # Add old kernel/rootfs partition info, as required.
Gilad Arnold382df5c2013-05-03 12:49:28 -0700456 if fail_mismatched_oki_ori or fail_old_kernel_fs_size or fail_bad_oki:
Gilad Arnold5502b562013-03-08 13:22:31 -0800457 oki_hash = (None if fail_bad_oki
458 else hashlib.sha256('fake-oki-content').digest())
Amin Hassani55c75412019-10-07 11:20:39 -0700459 payload_gen.SetPartInfo(common.KERNEL, False, old_kernel_fs_size,
460 oki_hash)
Gilad Arnold382df5c2013-05-03 12:49:28 -0700461 if not fail_mismatched_oki_ori and (fail_old_rootfs_fs_size or
462 fail_bad_ori):
463 ori_hash = (None if fail_bad_ori
464 else hashlib.sha256('fake-ori-content').digest())
Amin Hassani55c75412019-10-07 11:20:39 -0700465 payload_gen.SetPartInfo(common.ROOTFS, False, old_rootfs_fs_size,
466 ori_hash)
Gilad Arnold5502b562013-03-08 13:22:31 -0800467
468 # Add new kernel/rootfs partition info.
469 payload_gen.SetPartInfo(
Amin Hassani55c75412019-10-07 11:20:39 -0700470 common.KERNEL, True, new_kernel_fs_size,
Gilad Arnold5502b562013-03-08 13:22:31 -0800471 None if fail_bad_nki else hashlib.sha256('fake-nki-content').digest())
472 payload_gen.SetPartInfo(
Amin Hassani55c75412019-10-07 11:20:39 -0700473 common.ROOTFS, True, new_rootfs_fs_size,
Gilad Arnold5502b562013-03-08 13:22:31 -0800474 None if fail_bad_nri else hashlib.sha256('fake-nri-content').digest())
475
Gilad Arnold0d575cd2015-07-13 17:29:21 -0700476 # Set the minor version.
477 payload_gen.SetMinorVersion(0)
478
Gilad Arnold5502b562013-03-08 13:22:31 -0800479 # Create the test object.
480 payload_checker = _GetPayloadChecker(payload_gen.WriteToFile)
481 report = checker._PayloadReport()
482
483 should_fail = (fail_mismatched_block_size or fail_bad_sigs or
484 fail_mismatched_oki_ori or fail_bad_oki or fail_bad_ori or
Gilad Arnold5bc7fbe2015-02-05 13:01:09 -0800485 fail_bad_nki or fail_bad_nri or fail_old_kernel_fs_size or
486 fail_old_rootfs_fs_size or fail_new_kernel_fs_size or
487 fail_new_rootfs_fs_size)
Tudor Brindus8d05a7e2018-06-14 11:18:18 -0700488 part_sizes = {
489 common.ROOTFS: rootfs_part_size,
490 common.KERNEL: kernel_part_size
491 }
492
Gilad Arnold5502b562013-03-08 13:22:31 -0800493 if should_fail:
Amin Hassanib05a65a2017-12-18 15:15:32 -0800494 self.assertRaises(PayloadError, payload_checker._CheckManifest, report,
Tudor Brindus8d05a7e2018-06-14 11:18:18 -0700495 part_sizes)
Gilad Arnold5502b562013-03-08 13:22:31 -0800496 else:
Tudor Brindus8d05a7e2018-06-14 11:18:18 -0700497 self.assertIsNone(payload_checker._CheckManifest(report, part_sizes))
Gilad Arnold5502b562013-03-08 13:22:31 -0800498
499 def testCheckLength(self):
500 """Tests _CheckLength()."""
501 payload_checker = checker.PayloadChecker(self.MockPayload())
502 block_size = payload_checker.block_size
503
504 # Passes.
505 self.assertIsNone(payload_checker._CheckLength(
506 int(3.5 * block_size), 4, 'foo', 'bar'))
507 # Fails, too few blocks.
Amin Hassanib05a65a2017-12-18 15:15:32 -0800508 self.assertRaises(PayloadError, payload_checker._CheckLength,
Gilad Arnold5502b562013-03-08 13:22:31 -0800509 int(3.5 * block_size), 3, 'foo', 'bar')
510 # Fails, too many blocks.
Amin Hassanib05a65a2017-12-18 15:15:32 -0800511 self.assertRaises(PayloadError, payload_checker._CheckLength,
Gilad Arnold5502b562013-03-08 13:22:31 -0800512 int(3.5 * block_size), 5, 'foo', 'bar')
513
514 def testCheckExtents(self):
515 """Tests _CheckExtents()."""
516 payload_checker = checker.PayloadChecker(self.MockPayload())
517 block_size = payload_checker.block_size
518
519 # Passes w/ all real extents.
520 extents = self.NewExtentList((0, 4), (8, 3), (1024, 16))
521 self.assertEquals(
Gilad Arnoldcb638912013-06-24 04:57:11 -0700522 23,
Gilad Arnold5502b562013-03-08 13:22:31 -0800523 payload_checker._CheckExtents(extents, (1024 + 16) * block_size,
Gilad Arnoldcb638912013-06-24 04:57:11 -0700524 collections.defaultdict(int), 'foo'))
Gilad Arnold5502b562013-03-08 13:22:31 -0800525
Gilad Arnold5502b562013-03-08 13:22:31 -0800526 # Fails, extent missing a start block.
527 extents = self.NewExtentList((-1, 4), (8, 3), (1024, 16))
528 self.assertRaises(
Amin Hassanib05a65a2017-12-18 15:15:32 -0800529 PayloadError, payload_checker._CheckExtents, extents,
530 (1024 + 16) * block_size, collections.defaultdict(int), 'foo')
Gilad Arnold5502b562013-03-08 13:22:31 -0800531
532 # Fails, extent missing block count.
533 extents = self.NewExtentList((0, -1), (8, 3), (1024, 16))
534 self.assertRaises(
Amin Hassanib05a65a2017-12-18 15:15:32 -0800535 PayloadError, payload_checker._CheckExtents, extents,
536 (1024 + 16) * block_size, collections.defaultdict(int), 'foo')
Gilad Arnold5502b562013-03-08 13:22:31 -0800537
538 # Fails, extent has zero blocks.
539 extents = self.NewExtentList((0, 4), (8, 3), (1024, 0))
540 self.assertRaises(
Amin Hassanib05a65a2017-12-18 15:15:32 -0800541 PayloadError, payload_checker._CheckExtents, extents,
542 (1024 + 16) * block_size, collections.defaultdict(int), 'foo')
Gilad Arnold5502b562013-03-08 13:22:31 -0800543
544 # Fails, extent exceeds partition boundaries.
545 extents = self.NewExtentList((0, 4), (8, 3), (1024, 16))
546 self.assertRaises(
Amin Hassanib05a65a2017-12-18 15:15:32 -0800547 PayloadError, payload_checker._CheckExtents, extents,
548 (1024 + 15) * block_size, collections.defaultdict(int), 'foo')
Gilad Arnold5502b562013-03-08 13:22:31 -0800549
550 def testCheckReplaceOperation(self):
551 """Tests _CheckReplaceOperation() where op.type == REPLACE."""
552 payload_checker = checker.PayloadChecker(self.MockPayload())
553 block_size = payload_checker.block_size
554 data_length = 10000
555
556 op = self.mox.CreateMock(
Alex Deymo28466772015-09-11 17:16:44 -0700557 update_metadata_pb2.InstallOperation)
Gilad Arnold5502b562013-03-08 13:22:31 -0800558 op.type = common.OpType.REPLACE
559
560 # Pass.
561 op.src_extents = []
562 self.assertIsNone(
563 payload_checker._CheckReplaceOperation(
564 op, data_length, (data_length + block_size - 1) / block_size,
565 'foo'))
566
567 # Fail, src extents founds.
568 op.src_extents = ['bar']
569 self.assertRaises(
Amin Hassanib05a65a2017-12-18 15:15:32 -0800570 PayloadError, payload_checker._CheckReplaceOperation,
Gilad Arnold5502b562013-03-08 13:22:31 -0800571 op, data_length, (data_length + block_size - 1) / block_size, 'foo')
572
573 # Fail, missing data.
574 op.src_extents = []
575 self.assertRaises(
Amin Hassanib05a65a2017-12-18 15:15:32 -0800576 PayloadError, payload_checker._CheckReplaceOperation,
Gilad Arnold5502b562013-03-08 13:22:31 -0800577 op, None, (data_length + block_size - 1) / block_size, 'foo')
578
579 # Fail, length / block number mismatch.
580 op.src_extents = ['bar']
581 self.assertRaises(
Amin Hassanib05a65a2017-12-18 15:15:32 -0800582 PayloadError, payload_checker._CheckReplaceOperation,
Gilad Arnold5502b562013-03-08 13:22:31 -0800583 op, data_length, (data_length + block_size - 1) / block_size + 1, 'foo')
584
585 def testCheckReplaceBzOperation(self):
586 """Tests _CheckReplaceOperation() where op.type == REPLACE_BZ."""
587 payload_checker = checker.PayloadChecker(self.MockPayload())
588 block_size = payload_checker.block_size
589 data_length = block_size * 3
590
591 op = self.mox.CreateMock(
Alex Deymo28466772015-09-11 17:16:44 -0700592 update_metadata_pb2.InstallOperation)
Gilad Arnold5502b562013-03-08 13:22:31 -0800593 op.type = common.OpType.REPLACE_BZ
594
595 # Pass.
596 op.src_extents = []
597 self.assertIsNone(
598 payload_checker._CheckReplaceOperation(
599 op, data_length, (data_length + block_size - 1) / block_size + 5,
600 'foo'))
601
602 # Fail, src extents founds.
603 op.src_extents = ['bar']
604 self.assertRaises(
Amin Hassanib05a65a2017-12-18 15:15:32 -0800605 PayloadError, payload_checker._CheckReplaceOperation,
Gilad Arnold5502b562013-03-08 13:22:31 -0800606 op, data_length, (data_length + block_size - 1) / block_size + 5, 'foo')
607
608 # Fail, missing data.
609 op.src_extents = []
610 self.assertRaises(
Amin Hassanib05a65a2017-12-18 15:15:32 -0800611 PayloadError, payload_checker._CheckReplaceOperation,
Gilad Arnold5502b562013-03-08 13:22:31 -0800612 op, None, (data_length + block_size - 1) / block_size, 'foo')
613
614 # Fail, too few blocks to justify BZ.
615 op.src_extents = []
616 self.assertRaises(
Amin Hassanib05a65a2017-12-18 15:15:32 -0800617 PayloadError, payload_checker._CheckReplaceOperation,
Gilad Arnold5502b562013-03-08 13:22:31 -0800618 op, data_length, (data_length + block_size - 1) / block_size, 'foo')
619
Amin Hassani0de7f782017-12-07 12:13:03 -0800620 def testCheckReplaceXzOperation(self):
621 """Tests _CheckReplaceOperation() where op.type == REPLACE_XZ."""
622 payload_checker = checker.PayloadChecker(self.MockPayload())
623 block_size = payload_checker.block_size
624 data_length = block_size * 3
625
626 op = self.mox.CreateMock(
627 update_metadata_pb2.InstallOperation)
628 op.type = common.OpType.REPLACE_XZ
629
630 # Pass.
631 op.src_extents = []
632 self.assertIsNone(
633 payload_checker._CheckReplaceOperation(
634 op, data_length, (data_length + block_size - 1) / block_size + 5,
635 'foo'))
636
637 # Fail, src extents founds.
638 op.src_extents = ['bar']
639 self.assertRaises(
640 PayloadError, payload_checker._CheckReplaceOperation,
641 op, data_length, (data_length + block_size - 1) / block_size + 5, 'foo')
642
643 # Fail, missing data.
644 op.src_extents = []
645 self.assertRaises(
646 PayloadError, payload_checker._CheckReplaceOperation,
647 op, None, (data_length + block_size - 1) / block_size, 'foo')
648
649 # Fail, too few blocks to justify XZ.
650 op.src_extents = []
651 self.assertRaises(
652 PayloadError, payload_checker._CheckReplaceOperation,
653 op, data_length, (data_length + block_size - 1) / block_size, 'foo')
654
Sen Jiang92161a72016-06-28 16:09:38 -0700655 def testCheckAnyDiff(self):
656 """Tests _CheckAnyDiffOperation()."""
Gilad Arnold5502b562013-03-08 13:22:31 -0800657 payload_checker = checker.PayloadChecker(self.MockPayload())
Amin Hassaniefa62d92017-11-09 13:46:56 -0800658 op = update_metadata_pb2.InstallOperation()
Gilad Arnold5502b562013-03-08 13:22:31 -0800659
660 # Pass.
661 self.assertIsNone(
Amin Hassaniefa62d92017-11-09 13:46:56 -0800662 payload_checker._CheckAnyDiffOperation(op, 10000, 3, 'foo'))
Gilad Arnold5502b562013-03-08 13:22:31 -0800663
664 # Fail, missing data blob.
665 self.assertRaises(
Amin Hassanib05a65a2017-12-18 15:15:32 -0800666 PayloadError, payload_checker._CheckAnyDiffOperation,
Amin Hassaniefa62d92017-11-09 13:46:56 -0800667 op, None, 3, 'foo')
Gilad Arnold5502b562013-03-08 13:22:31 -0800668
669 # Fail, too big of a diff blob (unjustified).
670 self.assertRaises(
Amin Hassanib05a65a2017-12-18 15:15:32 -0800671 PayloadError, payload_checker._CheckAnyDiffOperation,
Amin Hassaniefa62d92017-11-09 13:46:56 -0800672 op, 10000, 2, 'foo')
Gilad Arnold5502b562013-03-08 13:22:31 -0800673
Allie Woodf5c4f3e2015-02-20 16:57:46 -0800674 def testCheckSourceCopyOperation_Pass(self):
675 """Tests _CheckSourceCopyOperation(); pass case."""
676 payload_checker = checker.PayloadChecker(self.MockPayload())
677 self.assertIsNone(
678 payload_checker._CheckSourceCopyOperation(None, 134, 134, 'foo'))
679
680 def testCheckSourceCopyOperation_FailContainsData(self):
681 """Tests _CheckSourceCopyOperation(); message contains data."""
682 payload_checker = checker.PayloadChecker(self.MockPayload())
Amin Hassanib05a65a2017-12-18 15:15:32 -0800683 self.assertRaises(PayloadError, payload_checker._CheckSourceCopyOperation,
Allie Woodf5c4f3e2015-02-20 16:57:46 -0800684 134, 0, 0, 'foo')
685
686 def testCheckSourceCopyOperation_FailBlockCountsMismatch(self):
687 """Tests _CheckSourceCopyOperation(); src and dst block totals not equal."""
688 payload_checker = checker.PayloadChecker(self.MockPayload())
Amin Hassanib05a65a2017-12-18 15:15:32 -0800689 self.assertRaises(PayloadError, payload_checker._CheckSourceCopyOperation,
Allie Woodf5c4f3e2015-02-20 16:57:46 -0800690 None, 0, 1, 'foo')
691
Amin Hassani55c75412019-10-07 11:20:39 -0700692 def DoCheckOperationTest(self, op_type_name, allow_unhashed,
693 fail_src_extents, fail_dst_extents,
Gilad Arnold5502b562013-03-08 13:22:31 -0800694 fail_mismatched_data_offset_length,
695 fail_missing_dst_extents, fail_src_length,
696 fail_dst_length, fail_data_hash,
Allie Wood7cf9f132015-02-26 14:28:19 -0800697 fail_prev_data_offset, fail_bad_minor_version):
Gilad Arnold5502b562013-03-08 13:22:31 -0800698 """Parametric testing of _CheckOperation().
699
700 Args:
Amin Hassani0f59a9a2019-09-27 10:24:31 -0700701 op_type_name: 'REPLACE', 'REPLACE_BZ', 'REPLACE_XZ',
Amin Hassani0de7f782017-12-07 12:13:03 -0800702 'SOURCE_COPY', 'SOURCE_BSDIFF', BROTLI_BSDIFF or 'PUFFDIFF'.
Gilad Arnoldcb638912013-06-24 04:57:11 -0700703 allow_unhashed: Whether we're allowing to not hash the data.
704 fail_src_extents: Tamper with src extents.
705 fail_dst_extents: Tamper with dst extents.
706 fail_mismatched_data_offset_length: Make data_{offset,length}
707 inconsistent.
708 fail_missing_dst_extents: Do not include dst extents.
709 fail_src_length: Make src length inconsistent.
710 fail_dst_length: Make dst length inconsistent.
711 fail_data_hash: Tamper with the data blob hash.
712 fail_prev_data_offset: Make data space uses incontiguous.
Allie Wood7cf9f132015-02-26 14:28:19 -0800713 fail_bad_minor_version: Make minor version incompatible with op.
Gilad Arnold5502b562013-03-08 13:22:31 -0800714 """
715 op_type = _OpTypeByName(op_type_name)
716
717 # Create the test object.
718 payload = self.MockPayload()
Gilad Arnoldeaed0d12013-04-30 15:38:22 -0700719 payload_checker = checker.PayloadChecker(payload,
720 allow_unhashed=allow_unhashed)
Gilad Arnold5502b562013-03-08 13:22:31 -0800721 block_size = payload_checker.block_size
722
723 # Create auxiliary arguments.
Gilad Arnold18f4f9f2013-04-02 16:24:41 -0700724 old_part_size = test_utils.MiB(4)
725 new_part_size = test_utils.MiB(8)
Gilad Arnold5502b562013-03-08 13:22:31 -0800726 old_block_counters = array.array(
727 'B', [0] * ((old_part_size + block_size - 1) / block_size))
728 new_block_counters = array.array(
729 'B', [0] * ((new_part_size + block_size - 1) / block_size))
730 prev_data_offset = 1876
731 blob_hash_counts = collections.defaultdict(int)
732
733 # Create the operation object for the test.
Alex Deymo28466772015-09-11 17:16:44 -0700734 op = update_metadata_pb2.InstallOperation()
Gilad Arnold5502b562013-03-08 13:22:31 -0800735 op.type = op_type
736
737 total_src_blocks = 0
Amin Hassani0f59a9a2019-09-27 10:24:31 -0700738 if op_type in (common.OpType.SOURCE_COPY, common.OpType.SOURCE_BSDIFF,
Amin Hassaniefa62d92017-11-09 13:46:56 -0800739 common.OpType.PUFFDIFF, common.OpType.BROTLI_BSDIFF):
Gilad Arnold5502b562013-03-08 13:22:31 -0800740 if fail_src_extents:
741 self.AddToMessage(op.src_extents,
Allie Woodb065e132015-04-24 10:20:27 -0700742 self.NewExtentList((1, 0)))
Gilad Arnold5502b562013-03-08 13:22:31 -0800743 else:
744 self.AddToMessage(op.src_extents,
Allie Woodb065e132015-04-24 10:20:27 -0700745 self.NewExtentList((1, 16)))
Gilad Arnold5502b562013-03-08 13:22:31 -0800746 total_src_blocks = 16
747
Amin Hassani55c75412019-10-07 11:20:39 -0700748 payload_checker.major_version = common.BRILLO_MAJOR_PAYLOAD_VERSION
Allie Wood7cf9f132015-02-26 14:28:19 -0800749 if op_type in (common.OpType.REPLACE, common.OpType.REPLACE_BZ):
Gilad Arnold0d575cd2015-07-13 17:29:21 -0700750 payload_checker.minor_version = 0
Allie Wood7cf9f132015-02-26 14:28:19 -0800751 elif op_type in (common.OpType.SOURCE_COPY, common.OpType.SOURCE_BSDIFF):
Gilad Arnold0d575cd2015-07-13 17:29:21 -0700752 payload_checker.minor_version = 1 if fail_bad_minor_version else 2
Amin Hassani0de7f782017-12-07 12:13:03 -0800753 if op_type == common.OpType.REPLACE_XZ:
754 payload_checker.minor_version = 2 if fail_bad_minor_version else 3
Amin Hassanicdeb6e62017-10-11 10:15:11 -0700755 elif op_type in (common.OpType.ZERO, common.OpType.DISCARD,
Amin Hassani77d7cbc2018-02-07 16:21:33 -0800756 common.OpType.BROTLI_BSDIFF):
Amin Hassani8ad22ba2017-10-11 10:15:11 -0700757 payload_checker.minor_version = 3 if fail_bad_minor_version else 4
Amin Hassani77d7cbc2018-02-07 16:21:33 -0800758 elif op_type == common.OpType.PUFFDIFF:
759 payload_checker.minor_version = 4 if fail_bad_minor_version else 5
Allie Wood7cf9f132015-02-26 14:28:19 -0800760
Amin Hassani0f59a9a2019-09-27 10:24:31 -0700761 if op_type != common.OpType.SOURCE_COPY:
Gilad Arnold5502b562013-03-08 13:22:31 -0800762 if not fail_mismatched_data_offset_length:
763 op.data_length = 16 * block_size - 8
764 if fail_prev_data_offset:
765 op.data_offset = prev_data_offset + 16
766 else:
767 op.data_offset = prev_data_offset
768
769 fake_data = 'fake-data'.ljust(op.data_length)
Amin Hassani55c75412019-10-07 11:20:39 -0700770 if not allow_unhashed and not fail_data_hash:
771 # Create a valid data blob hash.
772 op.data_sha256_hash = hashlib.sha256(fake_data).digest()
773 payload.ReadDataBlob(op.data_offset, op.data_length).AndReturn(
774 fake_data)
Amin Hassaniefa62d92017-11-09 13:46:56 -0800775
Gilad Arnold5502b562013-03-08 13:22:31 -0800776 elif fail_data_hash:
777 # Create an invalid data blob hash.
778 op.data_sha256_hash = hashlib.sha256(
779 fake_data.replace(' ', '-')).digest()
780 payload.ReadDataBlob(op.data_offset, op.data_length).AndReturn(
781 fake_data)
782
783 total_dst_blocks = 0
784 if not fail_missing_dst_extents:
785 total_dst_blocks = 16
786 if fail_dst_extents:
787 self.AddToMessage(op.dst_extents,
788 self.NewExtentList((4, 16), (32, 0)))
789 else:
790 self.AddToMessage(op.dst_extents,
791 self.NewExtentList((4, 8), (64, 8)))
792
793 if total_src_blocks:
794 if fail_src_length:
795 op.src_length = total_src_blocks * block_size + 8
Amin Hassani0f59a9a2019-09-27 10:24:31 -0700796 elif (op_type == common.OpType.SOURCE_BSDIFF and
Amin Hassaniefa62d92017-11-09 13:46:56 -0800797 payload_checker.minor_version <= 3):
Gilad Arnold5502b562013-03-08 13:22:31 -0800798 op.src_length = total_src_blocks * block_size
799 elif fail_src_length:
800 # Add an orphaned src_length.
801 op.src_length = 16
802
803 if total_dst_blocks:
804 if fail_dst_length:
805 op.dst_length = total_dst_blocks * block_size + 8
Amin Hassani0f59a9a2019-09-27 10:24:31 -0700806 elif (op_type == common.OpType.SOURCE_BSDIFF and
Amin Hassaniefa62d92017-11-09 13:46:56 -0800807 payload_checker.minor_version <= 3):
Gilad Arnold5502b562013-03-08 13:22:31 -0800808 op.dst_length = total_dst_blocks * block_size
809
810 self.mox.ReplayAll()
811 should_fail = (fail_src_extents or fail_dst_extents or
812 fail_mismatched_data_offset_length or
813 fail_missing_dst_extents or fail_src_length or
Allie Wood7cf9f132015-02-26 14:28:19 -0800814 fail_dst_length or fail_data_hash or fail_prev_data_offset or
815 fail_bad_minor_version)
Amin Hassani55c75412019-10-07 11:20:39 -0700816 args = (op, 'foo', old_block_counters, new_block_counters,
817 old_part_size, new_part_size, prev_data_offset,
Gilad Arnoldcb638912013-06-24 04:57:11 -0700818 blob_hash_counts)
Gilad Arnold5502b562013-03-08 13:22:31 -0800819 if should_fail:
Amin Hassanib05a65a2017-12-18 15:15:32 -0800820 self.assertRaises(PayloadError, payload_checker._CheckOperation, *args)
Gilad Arnold5502b562013-03-08 13:22:31 -0800821 else:
Gilad Arnoldcb638912013-06-24 04:57:11 -0700822 self.assertEqual(op.data_length if op.HasField('data_length') else 0,
823 payload_checker._CheckOperation(*args))
Gilad Arnold5502b562013-03-08 13:22:31 -0800824
825 def testAllocBlockCounters(self):
826 """Tests _CheckMoveOperation()."""
827 payload_checker = checker.PayloadChecker(self.MockPayload())
828 block_size = payload_checker.block_size
829
830 # Check allocation for block-aligned partition size, ensure it's integers.
831 result = payload_checker._AllocBlockCounters(16 * block_size)
Gilad Arnoldcb638912013-06-24 04:57:11 -0700832 self.assertEqual(16, len(result))
833 self.assertEqual(int, type(result[0]))
Gilad Arnold5502b562013-03-08 13:22:31 -0800834
835 # Check allocation of unaligned partition sizes.
836 result = payload_checker._AllocBlockCounters(16 * block_size - 1)
Gilad Arnoldcb638912013-06-24 04:57:11 -0700837 self.assertEqual(16, len(result))
Gilad Arnold5502b562013-03-08 13:22:31 -0800838 result = payload_checker._AllocBlockCounters(16 * block_size + 1)
Gilad Arnoldcb638912013-06-24 04:57:11 -0700839 self.assertEqual(17, len(result))
Gilad Arnold5502b562013-03-08 13:22:31 -0800840
Allie Woodfb04d302015-04-03 14:25:48 -0700841 def DoCheckOperationsTest(self, fail_nonexhaustive_full_update):
Amin Hassanib05a65a2017-12-18 15:15:32 -0800842 """Tests _CheckOperations()."""
Gilad Arnold5502b562013-03-08 13:22:31 -0800843 # Generate a test payload. For this test, we only care about one
844 # (arbitrary) set of operations, so we'll only be generating kernel and
845 # test with them.
846 payload_gen = test_utils.PayloadGenerator()
847
Gilad Arnold18f4f9f2013-04-02 16:24:41 -0700848 block_size = test_utils.KiB(4)
Gilad Arnold5502b562013-03-08 13:22:31 -0800849 payload_gen.SetBlockSize(block_size)
850
Gilad Arnold18f4f9f2013-04-02 16:24:41 -0700851 rootfs_part_size = test_utils.MiB(8)
Gilad Arnold5502b562013-03-08 13:22:31 -0800852
853 # Fake rootfs operations in a full update, tampered with as required.
854 rootfs_op_type = common.OpType.REPLACE
Gilad Arnold5502b562013-03-08 13:22:31 -0800855 rootfs_data_length = rootfs_part_size
856 if fail_nonexhaustive_full_update:
857 rootfs_data_length -= block_size
858
Amin Hassani55c75412019-10-07 11:20:39 -0700859 payload_gen.AddOperation(common.ROOTFS, rootfs_op_type,
Gilad Arnold5502b562013-03-08 13:22:31 -0800860 dst_extents=[(0, rootfs_data_length / block_size)],
861 data_offset=0,
862 data_length=rootfs_data_length)
863
864 # Create the test object.
Gilad Arnoldeaed0d12013-04-30 15:38:22 -0700865 payload_checker = _GetPayloadChecker(payload_gen.WriteToFile,
866 checker_init_dargs={
867 'allow_unhashed': True})
Gilad Arnold5502b562013-03-08 13:22:31 -0800868 payload_checker.payload_type = checker._TYPE_FULL
869 report = checker._PayloadReport()
Amin Hassani55c75412019-10-07 11:20:39 -0700870 partition = next((p for p in payload_checker.payload.manifest.partitions
871 if p.partition_name == common.ROOTFS), None)
872 args = (partition.operations, report, 'foo',
873 0, rootfs_part_size, rootfs_part_size, rootfs_part_size, 0)
Allie Woodfb04d302015-04-03 14:25:48 -0700874 if fail_nonexhaustive_full_update:
Amin Hassanib05a65a2017-12-18 15:15:32 -0800875 self.assertRaises(PayloadError, payload_checker._CheckOperations, *args)
Gilad Arnold5502b562013-03-08 13:22:31 -0800876 else:
Gilad Arnoldcb638912013-06-24 04:57:11 -0700877 self.assertEqual(rootfs_data_length,
878 payload_checker._CheckOperations(*args))
Gilad Arnold5502b562013-03-08 13:22:31 -0800879
Amin Hassani55c75412019-10-07 11:20:39 -0700880 def DoCheckSignaturesTest(self, fail_empty_sigs_blob, fail_sig_missing_fields,
Gilad Arnold5502b562013-03-08 13:22:31 -0800881 fail_unknown_sig_version, fail_incorrect_sig):
Amin Hassanib05a65a2017-12-18 15:15:32 -0800882 """Tests _CheckSignatures()."""
Gilad Arnold5502b562013-03-08 13:22:31 -0800883 # Generate a test payload. For this test, we only care about the signature
884 # block and how it relates to the payload hash. Therefore, we're generating
885 # a random (otherwise useless) payload for this purpose.
886 payload_gen = test_utils.EnhancedPayloadGenerator()
Gilad Arnold18f4f9f2013-04-02 16:24:41 -0700887 block_size = test_utils.KiB(4)
Gilad Arnold5502b562013-03-08 13:22:31 -0800888 payload_gen.SetBlockSize(block_size)
Gilad Arnold18f4f9f2013-04-02 16:24:41 -0700889 rootfs_part_size = test_utils.MiB(2)
890 kernel_part_size = test_utils.KiB(16)
Amin Hassani55c75412019-10-07 11:20:39 -0700891 payload_gen.SetPartInfo(common.ROOTFS, True, rootfs_part_size,
Gilad Arnold5502b562013-03-08 13:22:31 -0800892 hashlib.sha256('fake-new-rootfs-content').digest())
Amin Hassani55c75412019-10-07 11:20:39 -0700893 payload_gen.SetPartInfo(common.KERNEL, True, kernel_part_size,
Gilad Arnold5502b562013-03-08 13:22:31 -0800894 hashlib.sha256('fake-new-kernel-content').digest())
Gilad Arnold0d575cd2015-07-13 17:29:21 -0700895 payload_gen.SetMinorVersion(0)
Gilad Arnold5502b562013-03-08 13:22:31 -0800896 payload_gen.AddOperationWithData(
Amin Hassani55c75412019-10-07 11:20:39 -0700897 common.ROOTFS, common.OpType.REPLACE,
Gilad Arnold5502b562013-03-08 13:22:31 -0800898 dst_extents=[(0, rootfs_part_size / block_size)],
899 data_blob=os.urandom(rootfs_part_size))
900
Amin Hassani55c75412019-10-07 11:20:39 -0700901 do_forge_sigs_data = (fail_empty_sigs_blob or fail_sig_missing_fields or
902 fail_unknown_sig_version or fail_incorrect_sig)
Gilad Arnold5502b562013-03-08 13:22:31 -0800903
904 sigs_data = None
905 if do_forge_sigs_data:
906 sigs_gen = test_utils.SignaturesGenerator()
907 if not fail_empty_sigs_blob:
908 if fail_sig_missing_fields:
909 sig_data = None
910 else:
911 sig_data = test_utils.SignSha256('fake-payload-content',
Gilad Arnold18f4f9f2013-04-02 16:24:41 -0700912 test_utils._PRIVKEY_FILE_NAME)
Gilad Arnold5502b562013-03-08 13:22:31 -0800913 sigs_gen.AddSig(5 if fail_unknown_sig_version else 1, sig_data)
914
915 sigs_data = sigs_gen.ToBinary()
916 payload_gen.SetSignatures(payload_gen.curr_offset, len(sigs_data))
917
Gilad Arnold5502b562013-03-08 13:22:31 -0800918 # Generate payload (complete w/ signature) and create the test object.
919 payload_checker = _GetPayloadChecker(
Gilad Arnoldeaed0d12013-04-30 15:38:22 -0700920 payload_gen.WriteToFileWithData,
921 payload_gen_dargs={
922 'sigs_data': sigs_data,
Amin Hassani55c75412019-10-07 11:20:39 -0700923 'privkey_file_name': test_utils._PRIVKEY_FILE_NAME})
Gilad Arnold5502b562013-03-08 13:22:31 -0800924 payload_checker.payload_type = checker._TYPE_FULL
925 report = checker._PayloadReport()
926
927 # We have to check the manifest first in order to set signature attributes.
Tudor Brindus8d05a7e2018-06-14 11:18:18 -0700928 payload_checker._CheckManifest(report, {
929 common.ROOTFS: rootfs_part_size,
930 common.KERNEL: kernel_part_size
931 })
Gilad Arnold5502b562013-03-08 13:22:31 -0800932
Amin Hassani55c75412019-10-07 11:20:39 -0700933 should_fail = (fail_empty_sigs_blob or fail_sig_missing_fields or
Gilad Arnold5502b562013-03-08 13:22:31 -0800934 fail_unknown_sig_version or fail_incorrect_sig)
Gilad Arnoldcb638912013-06-24 04:57:11 -0700935 args = (report, test_utils._PUBKEY_FILE_NAME)
Gilad Arnold5502b562013-03-08 13:22:31 -0800936 if should_fail:
Amin Hassanib05a65a2017-12-18 15:15:32 -0800937 self.assertRaises(PayloadError, payload_checker._CheckSignatures, *args)
Gilad Arnold5502b562013-03-08 13:22:31 -0800938 else:
Gilad Arnoldcb638912013-06-24 04:57:11 -0700939 self.assertIsNone(payload_checker._CheckSignatures(*args))
Gilad Arnold5502b562013-03-08 13:22:31 -0800940
Gilad Arnold0d575cd2015-07-13 17:29:21 -0700941 def DoCheckManifestMinorVersionTest(self, minor_version, payload_type):
942 """Parametric testing for CheckManifestMinorVersion().
Allie Woodf5c4f3e2015-02-20 16:57:46 -0800943
944 Args:
945 minor_version: The payload minor version to test with.
946 payload_type: The type of the payload we're testing, delta or full.
947 """
948 # Create the test object.
Gilad Arnold0d575cd2015-07-13 17:29:21 -0700949 payload = self.MockPayload()
950 payload.manifest.minor_version = minor_version
951 payload_checker = checker.PayloadChecker(payload)
952 payload_checker.payload_type = payload_type
Allie Woodf5c4f3e2015-02-20 16:57:46 -0800953 report = checker._PayloadReport()
954
955 should_succeed = (
956 (minor_version == 0 and payload_type == checker._TYPE_FULL) or
Sen Jiang912c4df2015-12-10 12:17:13 -0800957 (minor_version == 2 and payload_type == checker._TYPE_DELTA) or
Sen Jiang92161a72016-06-28 16:09:38 -0700958 (minor_version == 3 and payload_type == checker._TYPE_DELTA) or
Amin Hassani77d7cbc2018-02-07 16:21:33 -0800959 (minor_version == 4 and payload_type == checker._TYPE_DELTA) or
960 (minor_version == 5 and payload_type == checker._TYPE_DELTA))
Gilad Arnold0d575cd2015-07-13 17:29:21 -0700961 args = (report,)
Allie Woodf5c4f3e2015-02-20 16:57:46 -0800962
963 if should_succeed:
Gilad Arnold0d575cd2015-07-13 17:29:21 -0700964 self.assertIsNone(payload_checker._CheckManifestMinorVersion(*args))
Allie Woodf5c4f3e2015-02-20 16:57:46 -0800965 else:
Amin Hassanib05a65a2017-12-18 15:15:32 -0800966 self.assertRaises(PayloadError,
Gilad Arnold0d575cd2015-07-13 17:29:21 -0700967 payload_checker._CheckManifestMinorVersion, *args)
Allie Woodf5c4f3e2015-02-20 16:57:46 -0800968
Gilad Arnold06eea332015-07-13 18:06:33 -0700969 def DoRunTest(self, rootfs_part_size_provided, kernel_part_size_provided,
970 fail_wrong_payload_type, fail_invalid_block_size,
Amin Hassania86b1082018-03-08 15:48:59 -0800971 fail_mismatched_metadata_size, fail_mismatched_block_size,
972 fail_excess_data, fail_rootfs_part_size_exceeded,
Gilad Arnold06eea332015-07-13 18:06:33 -0700973 fail_kernel_part_size_exceeded):
Amin Hassanib05a65a2017-12-18 15:15:32 -0800974 """Tests Run()."""
Gilad Arnold5502b562013-03-08 13:22:31 -0800975 # Generate a test payload. For this test, we generate a full update that
Gilad Arnoldeaed0d12013-04-30 15:38:22 -0700976 # has sample kernel and rootfs operations. Since most testing is done with
Gilad Arnold5502b562013-03-08 13:22:31 -0800977 # internal PayloadChecker methods that are tested elsewhere, here we only
978 # tamper with what's actually being manipulated and/or tested in the Run()
979 # method itself. Note that the checker doesn't verify partition hashes, so
980 # they're safe to fake.
981 payload_gen = test_utils.EnhancedPayloadGenerator()
Gilad Arnold18f4f9f2013-04-02 16:24:41 -0700982 block_size = test_utils.KiB(4)
Gilad Arnold5502b562013-03-08 13:22:31 -0800983 payload_gen.SetBlockSize(block_size)
Gilad Arnold06eea332015-07-13 18:06:33 -0700984 kernel_filesystem_size = test_utils.KiB(16)
985 rootfs_filesystem_size = test_utils.MiB(2)
Amin Hassani55c75412019-10-07 11:20:39 -0700986 payload_gen.SetPartInfo(common.ROOTFS, True, rootfs_filesystem_size,
Gilad Arnold5502b562013-03-08 13:22:31 -0800987 hashlib.sha256('fake-new-rootfs-content').digest())
Amin Hassani55c75412019-10-07 11:20:39 -0700988 payload_gen.SetPartInfo(common.KERNEL, True, kernel_filesystem_size,
Gilad Arnold5502b562013-03-08 13:22:31 -0800989 hashlib.sha256('fake-new-kernel-content').digest())
Gilad Arnold0d575cd2015-07-13 17:29:21 -0700990 payload_gen.SetMinorVersion(0)
Gilad Arnold06eea332015-07-13 18:06:33 -0700991
992 rootfs_part_size = 0
993 if rootfs_part_size_provided:
994 rootfs_part_size = rootfs_filesystem_size + block_size
995 rootfs_op_size = rootfs_part_size or rootfs_filesystem_size
996 if fail_rootfs_part_size_exceeded:
997 rootfs_op_size += block_size
Gilad Arnold5502b562013-03-08 13:22:31 -0800998 payload_gen.AddOperationWithData(
Amin Hassani55c75412019-10-07 11:20:39 -0700999 common.ROOTFS, common.OpType.REPLACE,
Gilad Arnold06eea332015-07-13 18:06:33 -07001000 dst_extents=[(0, rootfs_op_size / block_size)],
1001 data_blob=os.urandom(rootfs_op_size))
1002
1003 kernel_part_size = 0
1004 if kernel_part_size_provided:
1005 kernel_part_size = kernel_filesystem_size + block_size
1006 kernel_op_size = kernel_part_size or kernel_filesystem_size
1007 if fail_kernel_part_size_exceeded:
1008 kernel_op_size += block_size
Gilad Arnold5502b562013-03-08 13:22:31 -08001009 payload_gen.AddOperationWithData(
Amin Hassani55c75412019-10-07 11:20:39 -07001010 common.KERNEL, common.OpType.REPLACE,
Gilad Arnold06eea332015-07-13 18:06:33 -07001011 dst_extents=[(0, kernel_op_size / block_size)],
1012 data_blob=os.urandom(kernel_op_size))
Gilad Arnold5502b562013-03-08 13:22:31 -08001013
1014 # Generate payload (complete w/ signature) and create the test object.
Gilad Arnold5502b562013-03-08 13:22:31 -08001015 if fail_invalid_block_size:
Gilad Arnoldcb638912013-06-24 04:57:11 -07001016 use_block_size = block_size + 5 # Not a power of two.
Gilad Arnold5502b562013-03-08 13:22:31 -08001017 elif fail_mismatched_block_size:
Gilad Arnoldcb638912013-06-24 04:57:11 -07001018 use_block_size = block_size * 2 # Different that payload stated.
Gilad Arnold5502b562013-03-08 13:22:31 -08001019 else:
1020 use_block_size = block_size
Gilad Arnold5502b562013-03-08 13:22:31 -08001021
Amin Hassani55c75412019-10-07 11:20:39 -07001022 # For the unittests 237 is the value that generated for the payload.
1023 metadata_size = 237
Amin Hassania86b1082018-03-08 15:48:59 -08001024 if fail_mismatched_metadata_size:
1025 metadata_size += 1
1026
Gilad Arnoldcb638912013-06-24 04:57:11 -07001027 kwargs = {
Gilad Arnoldeaed0d12013-04-30 15:38:22 -07001028 'payload_gen_dargs': {
Gilad Arnold18f4f9f2013-04-02 16:24:41 -07001029 'privkey_file_name': test_utils._PRIVKEY_FILE_NAME,
Gilad Arnoldeaed0d12013-04-30 15:38:22 -07001030 'padding': os.urandom(1024) if fail_excess_data else None},
1031 'checker_init_dargs': {
1032 'assert_type': 'delta' if fail_wrong_payload_type else 'full',
1033 'block_size': use_block_size}}
1034 if fail_invalid_block_size:
Amin Hassanib05a65a2017-12-18 15:15:32 -08001035 self.assertRaises(PayloadError, _GetPayloadChecker,
Gilad Arnoldcb638912013-06-24 04:57:11 -07001036 payload_gen.WriteToFileWithData, **kwargs)
Gilad Arnold5502b562013-03-08 13:22:31 -08001037 else:
Gilad Arnoldeaed0d12013-04-30 15:38:22 -07001038 payload_checker = _GetPayloadChecker(payload_gen.WriteToFileWithData,
Gilad Arnoldcb638912013-06-24 04:57:11 -07001039 **kwargs)
Gilad Arnold06eea332015-07-13 18:06:33 -07001040
Amin Hassani55c75412019-10-07 11:20:39 -07001041 kwargs2 = {
Tudor Brindus2d22c1a2018-06-15 13:07:13 -07001042 'pubkey_file_name': test_utils._PUBKEY_FILE_NAME,
1043 'metadata_size': metadata_size,
1044 'part_sizes': {
1045 common.KERNEL: kernel_part_size,
1046 common.ROOTFS: rootfs_part_size}}
1047
Gilad Arnoldeaed0d12013-04-30 15:38:22 -07001048 should_fail = (fail_wrong_payload_type or fail_mismatched_block_size or
Amin Hassania86b1082018-03-08 15:48:59 -08001049 fail_mismatched_metadata_size or fail_excess_data or
Gilad Arnold06eea332015-07-13 18:06:33 -07001050 fail_rootfs_part_size_exceeded or
1051 fail_kernel_part_size_exceeded)
Gilad Arnoldeaed0d12013-04-30 15:38:22 -07001052 if should_fail:
Amin Hassani55c75412019-10-07 11:20:39 -07001053 self.assertRaises(PayloadError, payload_checker.Run, **kwargs2)
Gilad Arnoldeaed0d12013-04-30 15:38:22 -07001054 else:
Amin Hassani55c75412019-10-07 11:20:39 -07001055 self.assertIsNone(payload_checker.Run(**kwargs2))
Gilad Arnold5502b562013-03-08 13:22:31 -08001056
Gilad Arnold5502b562013-03-08 13:22:31 -08001057# This implements a generic API, hence the occasional unused args.
1058# pylint: disable=W0613
Amin Hassani55c75412019-10-07 11:20:39 -07001059def ValidateCheckOperationTest(op_type_name, allow_unhashed,
1060 fail_src_extents, fail_dst_extents,
Gilad Arnold5502b562013-03-08 13:22:31 -08001061 fail_mismatched_data_offset_length,
1062 fail_missing_dst_extents, fail_src_length,
1063 fail_dst_length, fail_data_hash,
Allie Wood7cf9f132015-02-26 14:28:19 -08001064 fail_prev_data_offset, fail_bad_minor_version):
Gilad Arnold5502b562013-03-08 13:22:31 -08001065 """Returns True iff the combination of arguments represents a valid test."""
1066 op_type = _OpTypeByName(op_type_name)
1067
Amin Hassani0de7f782017-12-07 12:13:03 -08001068 # REPLACE/REPLACE_BZ/REPLACE_XZ operations don't read data from src
1069 # partition. They are compatible with all valid minor versions, so we don't
1070 # need to check that.
1071 if (op_type in (common.OpType.REPLACE, common.OpType.REPLACE_BZ,
1072 common.OpType.REPLACE_XZ) and (fail_src_extents or
1073 fail_src_length or
1074 fail_bad_minor_version)):
Gilad Arnold5502b562013-03-08 13:22:31 -08001075 return False
1076
Amin Hassani0f59a9a2019-09-27 10:24:31 -07001077 # SOURCE_COPY operation does not carry data.
1078 if (op_type == common.OpType.SOURCE_COPY and (
Gilad Arnold5502b562013-03-08 13:22:31 -08001079 fail_mismatched_data_offset_length or fail_data_hash or
1080 fail_prev_data_offset)):
1081 return False
1082
1083 return True
1084
1085
1086def TestMethodBody(run_method_name, run_dargs):
1087 """Returns a function that invokes a named method with named arguments."""
1088 return lambda self: getattr(self, run_method_name)(**run_dargs)
1089
1090
1091def AddParametricTests(tested_method_name, arg_space, validate_func=None):
1092 """Enumerates and adds specific parametric tests to PayloadCheckerTest.
1093
1094 This function enumerates a space of test parameters (defined by arg_space),
1095 then binds a new, unique method name in PayloadCheckerTest to a test function
1096 that gets handed the said parameters. This is a preferable approach to doing
1097 the enumeration and invocation during the tests because this way each test is
1098 treated as a complete run by the unittest framework, and so benefits from the
1099 usual setUp/tearDown mechanics.
1100
1101 Args:
Gilad Arnoldcb638912013-06-24 04:57:11 -07001102 tested_method_name: Name of the tested PayloadChecker method.
1103 arg_space: A dictionary containing variables (keys) and lists of values
1104 (values) associated with them.
1105 validate_func: A function used for validating test argument combinations.
Gilad Arnold5502b562013-03-08 13:22:31 -08001106 """
1107 for value_tuple in itertools.product(*arg_space.itervalues()):
1108 run_dargs = dict(zip(arg_space.iterkeys(), value_tuple))
1109 if validate_func and not validate_func(**run_dargs):
1110 continue
1111 run_method_name = 'Do%sTest' % tested_method_name
1112 test_method_name = 'test%s' % tested_method_name
1113 for arg_key, arg_val in run_dargs.iteritems():
Amin Hassani55c75412019-10-07 11:20:39 -07001114 if arg_val or isinstance(arg_val, int):
Gilad Arnold5502b562013-03-08 13:22:31 -08001115 test_method_name += '__%s=%s' % (arg_key, arg_val)
1116 setattr(PayloadCheckerTest, test_method_name,
1117 TestMethodBody(run_method_name, run_dargs))
1118
1119
1120def AddAllParametricTests():
1121 """Enumerates and adds all parametric tests to PayloadCheckerTest."""
1122 # Add all _CheckElem() test cases.
1123 AddParametricTests('AddElem',
1124 {'linebreak': (True, False),
1125 'indent': (0, 1, 2),
1126 'convert': (str, lambda s: s[::-1]),
1127 'is_present': (True, False),
1128 'is_mandatory': (True, False),
1129 'is_submsg': (True, False)})
1130
1131 # Add all _Add{Mandatory,Optional}Field tests.
1132 AddParametricTests('AddField',
1133 {'is_mandatory': (True, False),
1134 'linebreak': (True, False),
1135 'indent': (0, 1, 2),
1136 'convert': (str, lambda s: s[::-1]),
1137 'is_present': (True, False)})
1138
1139 # Add all _Add{Mandatory,Optional}SubMsg tests.
1140 AddParametricTests('AddSubMsg',
1141 {'is_mandatory': (True, False),
1142 'is_present': (True, False)})
1143
1144 # Add all _CheckManifest() test cases.
1145 AddParametricTests('CheckManifest',
1146 {'fail_mismatched_block_size': (True, False),
1147 'fail_bad_sigs': (True, False),
1148 'fail_mismatched_oki_ori': (True, False),
1149 'fail_bad_oki': (True, False),
1150 'fail_bad_ori': (True, False),
1151 'fail_bad_nki': (True, False),
1152 'fail_bad_nri': (True, False),
Gilad Arnold382df5c2013-05-03 12:49:28 -07001153 'fail_old_kernel_fs_size': (True, False),
1154 'fail_old_rootfs_fs_size': (True, False),
1155 'fail_new_kernel_fs_size': (True, False),
1156 'fail_new_rootfs_fs_size': (True, False)})
Gilad Arnold5502b562013-03-08 13:22:31 -08001157
1158 # Add all _CheckOperation() test cases.
1159 AddParametricTests('CheckOperation',
Amin Hassani0de7f782017-12-07 12:13:03 -08001160 {'op_type_name': ('REPLACE', 'REPLACE_BZ', 'REPLACE_XZ',
Amin Hassani0f59a9a2019-09-27 10:24:31 -07001161 'SOURCE_COPY', 'SOURCE_BSDIFF',
1162 'PUFFDIFF', 'BROTLI_BSDIFF'),
Gilad Arnold5502b562013-03-08 13:22:31 -08001163 'allow_unhashed': (True, False),
1164 'fail_src_extents': (True, False),
1165 'fail_dst_extents': (True, False),
1166 'fail_mismatched_data_offset_length': (True, False),
1167 'fail_missing_dst_extents': (True, False),
1168 'fail_src_length': (True, False),
1169 'fail_dst_length': (True, False),
1170 'fail_data_hash': (True, False),
Allie Wood7cf9f132015-02-26 14:28:19 -08001171 'fail_prev_data_offset': (True, False),
1172 'fail_bad_minor_version': (True, False)},
Gilad Arnold5502b562013-03-08 13:22:31 -08001173 validate_func=ValidateCheckOperationTest)
1174
1175 # Add all _CheckOperations() test cases.
1176 AddParametricTests('CheckOperations',
Allie Woodfb04d302015-04-03 14:25:48 -07001177 {'fail_nonexhaustive_full_update': (True, False)})
Gilad Arnold5502b562013-03-08 13:22:31 -08001178
1179 # Add all _CheckOperations() test cases.
1180 AddParametricTests('CheckSignatures',
1181 {'fail_empty_sigs_blob': (True, False),
Gilad Arnold5502b562013-03-08 13:22:31 -08001182 'fail_sig_missing_fields': (True, False),
1183 'fail_unknown_sig_version': (True, False),
1184 'fail_incorrect_sig': (True, False)})
1185
Gilad Arnold0d575cd2015-07-13 17:29:21 -07001186 # Add all _CheckManifestMinorVersion() test cases.
1187 AddParametricTests('CheckManifestMinorVersion',
Amin Hassani0f59a9a2019-09-27 10:24:31 -07001188 {'minor_version': (None, 0, 2, 3, 4, 5, 555),
Allie Woodf5c4f3e2015-02-20 16:57:46 -08001189 'payload_type': (checker._TYPE_FULL,
1190 checker._TYPE_DELTA)})
1191
Gilad Arnold5502b562013-03-08 13:22:31 -08001192 # Add all Run() test cases.
1193 AddParametricTests('Run',
Gilad Arnold06eea332015-07-13 18:06:33 -07001194 {'rootfs_part_size_provided': (True, False),
1195 'kernel_part_size_provided': (True, False),
1196 'fail_wrong_payload_type': (True, False),
Gilad Arnold5502b562013-03-08 13:22:31 -08001197 'fail_invalid_block_size': (True, False),
Amin Hassania86b1082018-03-08 15:48:59 -08001198 'fail_mismatched_metadata_size': (True, False),
Gilad Arnold5502b562013-03-08 13:22:31 -08001199 'fail_mismatched_block_size': (True, False),
Gilad Arnold06eea332015-07-13 18:06:33 -07001200 'fail_excess_data': (True, False),
1201 'fail_rootfs_part_size_exceeded': (True, False),
1202 'fail_kernel_part_size_exceeded': (True, False)})
Gilad Arnold5502b562013-03-08 13:22:31 -08001203
1204
1205if __name__ == '__main__':
1206 AddAllParametricTests()
1207 unittest.main()