1f583a7d7c5255ec0e2321db60b7690c25e58c290Gilad Arnold#!/usr/bin/python2
25502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold#
35502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold# Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
45502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold# Use of this source code is governed by a BSD-style license that can be
55502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold# found in the LICENSE file.
65502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
75502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold"""Unit testing checker.py."""
85502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
9f583a7d7c5255ec0e2321db60b7690c25e58c290Gilad Arnoldfrom __future__ import print_function
10f583a7d7c5255ec0e2321db60b7690c25e58c290Gilad Arnold
115502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnoldimport array
125502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnoldimport collections
135502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnoldimport cStringIO
145502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnoldimport hashlib
155502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnoldimport itertools
165502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnoldimport os
175502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnoldimport unittest
185502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
19cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold# pylint cannot find mox.
205502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold# pylint: disable=F0401
215502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnoldimport mox
225502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
235502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnoldimport checker
245502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnoldimport common
25cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnoldimport payload as update_payload  # Avoid name conflicts later.
265502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnoldimport test_utils
275502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnoldimport update_metadata_pb2
285502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
295502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
305502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnolddef _OpTypeByName(op_name):
315502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold  op_name_to_type = {
325502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold      'REPLACE': common.OpType.REPLACE,
335502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold      'REPLACE_BZ': common.OpType.REPLACE_BZ,
345502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold      'MOVE': common.OpType.MOVE,
355502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold      'BSDIFF': common.OpType.BSDIFF,
36f5c4f3e2a6e7c93e5b4c09272091f23a935fab86Allie Wood      'SOURCE_COPY': common.OpType.SOURCE_COPY,
37f5c4f3e2a6e7c93e5b4c09272091f23a935fab86Allie Wood      'SOURCE_BSDIFF': common.OpType.SOURCE_BSDIFF,
382846677f9ec7725d9cf9513768477c873c19ba78Alex Deymo      'ZERO': common.OpType.ZERO,
392846677f9ec7725d9cf9513768477c873c19ba78Alex Deymo      'DISCARD': common.OpType.DISCARD,
402846677f9ec7725d9cf9513768477c873c19ba78Alex Deymo      'REPLACE_XZ': common.OpType.REPLACE_XZ,
41c2538fab9a7fc01c0216520874d711c8a9fbd9d3Sen Jiang      'IMGDIFF': common.OpType.IMGDIFF,
425502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold  }
435502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold  return op_name_to_type[op_name]
445502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
455502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
46eaed0d1371d781d3f5effa1475f5202dea9467e7Gilad Arnolddef _GetPayloadChecker(payload_gen_write_to_file_func, payload_gen_dargs=None,
47eaed0d1371d781d3f5effa1475f5202dea9467e7Gilad Arnold                       checker_init_dargs=None):
485502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold  """Returns a payload checker from a given payload generator."""
49eaed0d1371d781d3f5effa1475f5202dea9467e7Gilad Arnold  if payload_gen_dargs is None:
50eaed0d1371d781d3f5effa1475f5202dea9467e7Gilad Arnold    payload_gen_dargs = {}
51eaed0d1371d781d3f5effa1475f5202dea9467e7Gilad Arnold  if checker_init_dargs is None:
52eaed0d1371d781d3f5effa1475f5202dea9467e7Gilad Arnold    checker_init_dargs = {}
53eaed0d1371d781d3f5effa1475f5202dea9467e7Gilad Arnold
545502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold  payload_file = cStringIO.StringIO()
55eaed0d1371d781d3f5effa1475f5202dea9467e7Gilad Arnold  payload_gen_write_to_file_func(payload_file, **payload_gen_dargs)
565502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold  payload_file.seek(0)
575502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold  payload = update_payload.Payload(payload_file)
585502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold  payload.Init()
59eaed0d1371d781d3f5effa1475f5202dea9467e7Gilad Arnold  return checker.PayloadChecker(payload, **checker_init_dargs)
605502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
615502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
625502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnolddef _GetPayloadCheckerWithData(payload_gen):
635502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold  """Returns a payload checker from a given payload generator."""
645502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold  payload_file = cStringIO.StringIO()
655502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold  payload_gen.WriteToFile(payload_file)
665502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold  payload_file.seek(0)
675502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold  payload = update_payload.Payload(payload_file)
685502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold  payload.Init()
695502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold  return checker.PayloadChecker(payload)
705502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
715502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
72cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold# This class doesn't need an __init__().
735502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold# pylint: disable=W0232
74cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold# Unit testing is all about running protected methods.
755502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold# pylint: disable=W0212
76cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold# Don't bark about missing members of classes you cannot import.
775502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold# pylint: disable=E1101
785502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnoldclass PayloadCheckerTest(mox.MoxTestBase):
795502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold  """Tests the PayloadChecker class.
805502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
815502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold  In addition to ordinary testFoo() methods, which are automatically invoked by
825502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold  the unittest framework, in this class we make use of DoBarTest() calls that
835502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold  implement parametric tests of certain features. In order to invoke each test,
845502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold  which embodies a unique combination of parameter values, as a complete unit
855502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold  test, we perform explicit enumeration of the parameter space and create
865502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold  individual invocation contexts for each, which are then bound as
875502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold  testBar__param1=val1__param2=val2(). The enumeration of parameter spaces for
885502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold  all such tests is done in AddAllParametricTests().
895502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold  """
905502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
915502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold  def MockPayload(self):
92f5c4f3e2a6e7c93e5b4c09272091f23a935fab86Allie Wood    """Create a mock payload object, complete with a mock manifest."""
935502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    payload = self.mox.CreateMock(update_payload.Payload)
945502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    payload.is_init = True
955502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    payload.manifest = self.mox.CreateMock(
965502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold        update_metadata_pb2.DeltaArchiveManifest)
975502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    return payload
985502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
995502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold  @staticmethod
1005502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold  def NewExtent(start_block, num_blocks):
1015502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    """Returns an Extent message.
1025502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
1035502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    Each of the provided fields is set iff it is >= 0; otherwise, it's left at
1045502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    its default state.
1055502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
1065502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    Args:
107cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold      start_block: The starting block of the extent.
108cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold      num_blocks: The number of blocks in the extent.
109f583a7d7c5255ec0e2321db60b7690c25e58c290Gilad Arnold
1105502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    Returns:
1115502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold      An Extent message.
1125502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    """
1135502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    ex = update_metadata_pb2.Extent()
1145502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    if start_block >= 0:
1155502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold      ex.start_block = start_block
1165502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    if num_blocks >= 0:
1175502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold      ex.num_blocks = num_blocks
1185502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    return ex
1195502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
1205502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold  @staticmethod
1215502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold  def NewExtentList(*args):
1225502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    """Returns an list of extents.
1235502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
1245502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    Args:
125cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold      *args: (start_block, num_blocks) pairs defining the extents.
126f583a7d7c5255ec0e2321db60b7690c25e58c290Gilad Arnold
1275502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    Returns:
1285502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold      A list of Extent objects.
1295502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    """
1305502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    ex_list = []
1315502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    for start_block, num_blocks in args:
1325502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold      ex_list.append(PayloadCheckerTest.NewExtent(start_block, num_blocks))
1335502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    return ex_list
1345502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
1355502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold  @staticmethod
1365502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold  def AddToMessage(repeated_field, field_vals):
1375502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    for field_val in field_vals:
1385502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold      new_field = repeated_field.add()
1395502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold      new_field.CopyFrom(field_val)
1405502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
1415502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold  def SetupAddElemTest(self, is_present, is_submsg, convert=str,
1425502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                       linebreak=False, indent=0):
1435502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    """Setup for testing of _CheckElem() and its derivatives.
1445502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
1455502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    Args:
146cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold      is_present: Whether or not the element is found in the message.
147cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold      is_submsg: Whether the element is a sub-message itself.
148cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold      convert: A representation conversion function.
149cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold      linebreak: Whether or not a linebreak is to be used in the report.
150cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold      indent: Indentation used for the report.
151f583a7d7c5255ec0e2321db60b7690c25e58c290Gilad Arnold
1525502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    Returns:
153cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold      msg: A mock message object.
154cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold      report: A mock report object.
155cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold      subreport: A mock sub-report object.
156cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold      name: An element name to check.
157cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold      val: Expected element value.
1585502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    """
1595502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    name = 'foo'
1605502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    val = 'fake submsg' if is_submsg else 'fake field'
1615502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    subreport = 'fake subreport'
1625502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
1635502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    # Create a mock message.
1642846677f9ec7725d9cf9513768477c873c19ba78Alex Deymo    msg = self.mox.CreateMock(update_metadata_pb2._message.Message)
1655502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    msg.HasField(name).AndReturn(is_present)
1665502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    setattr(msg, name, val)
1675502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
1685502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    # Create a mock report.
1695502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    report = self.mox.CreateMock(checker._PayloadReport)
1705502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    if is_present:
1715502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold      if is_submsg:
1725502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold        report.AddSubReport(name).AndReturn(subreport)
1735502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold      else:
1745502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold        report.AddField(name, convert(val), linebreak=linebreak, indent=indent)
1755502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
1765502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    self.mox.ReplayAll()
1775502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    return (msg, report, subreport, name, val)
1785502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
1795502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold  def DoAddElemTest(self, is_present, is_mandatory, is_submsg, convert,
1805502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                    linebreak, indent):
1815502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    """Parametric testing of _CheckElem().
1825502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
1835502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    Args:
184cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold      is_present: Whether or not the element is found in the message.
185cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold      is_mandatory: Whether or not it's a mandatory element.
186cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold      is_submsg: Whether the element is a sub-message itself.
187cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold      convert: A representation conversion function.
188cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold      linebreak: Whether or not a linebreak is to be used in the report.
189cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold      indent: Indentation used for the report.
1905502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    """
1915502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    msg, report, subreport, name, val = self.SetupAddElemTest(
1925502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold        is_present, is_submsg, convert, linebreak, indent)
1935502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
194cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold    args = (msg, name, report, is_mandatory, is_submsg)
195cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold    kwargs = {'convert': convert, 'linebreak': linebreak, 'indent': indent}
1965502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    if is_mandatory and not is_present:
1975502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold      self.assertRaises(update_payload.PayloadError,
198cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold                        checker.PayloadChecker._CheckElem, *args, **kwargs)
1995502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    else:
200cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold      ret_val, ret_subreport = checker.PayloadChecker._CheckElem(*args,
201cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold                                                                 **kwargs)
202cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold      self.assertEquals(val if is_present else None, ret_val)
203cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold      self.assertEquals(subreport if is_present and is_submsg else None,
204cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold                        ret_subreport)
2055502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
2065502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold  def DoAddFieldTest(self, is_mandatory, is_present, convert, linebreak,
2075502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                     indent):
2085502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    """Parametric testing of _Check{Mandatory,Optional}Field().
2095502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
2105502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    Args:
211cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold      is_mandatory: Whether we're testing a mandatory call.
212cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold      is_present: Whether or not the element is found in the message.
213cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold      convert: A representation conversion function.
214cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold      linebreak: Whether or not a linebreak is to be used in the report.
215cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold      indent: Indentation used for the report.
2165502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    """
2175502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    msg, report, _, name, val = self.SetupAddElemTest(
2185502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold        is_present, False, convert, linebreak, indent)
2195502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
2205502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    # Prepare for invocation of the tested method.
221cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold    args = [msg, name, report]
222cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold    kwargs = {'convert': convert, 'linebreak': linebreak, 'indent': indent}
2235502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    if is_mandatory:
224cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold      args.append('bar')
2255502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold      tested_func = checker.PayloadChecker._CheckMandatoryField
2265502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    else:
2275502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold      tested_func = checker.PayloadChecker._CheckOptionalField
2285502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
2295502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    # Test the method call.
2305502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    if is_mandatory and not is_present:
231cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold      self.assertRaises(update_payload.PayloadError, tested_func, *args,
232cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold                        **kwargs)
2335502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    else:
234cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold      ret_val = tested_func(*args, **kwargs)
235cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold      self.assertEquals(val if is_present else None, ret_val)
2365502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
2375502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold  def DoAddSubMsgTest(self, is_mandatory, is_present):
2385502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    """Parametrized testing of _Check{Mandatory,Optional}SubMsg().
2395502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
2405502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    Args:
241cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold      is_mandatory: Whether we're testing a mandatory call.
242cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold      is_present: Whether or not the element is found in the message.
2435502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    """
2445502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    msg, report, subreport, name, val = self.SetupAddElemTest(is_present, True)
2455502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
2465502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    # Prepare for invocation of the tested method.
247cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold    args = [msg, name, report]
2485502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    if is_mandatory:
249cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold      args.append('bar')
2505502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold      tested_func = checker.PayloadChecker._CheckMandatorySubMsg
2515502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    else:
2525502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold      tested_func = checker.PayloadChecker._CheckOptionalSubMsg
2535502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
2545502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    # Test the method call.
2555502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    if is_mandatory and not is_present:
256cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold      self.assertRaises(update_payload.PayloadError, tested_func, *args)
2575502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    else:
258cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold      ret_val, ret_subreport = tested_func(*args)
259cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold      self.assertEquals(val if is_present else None, ret_val)
260cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold      self.assertEquals(subreport if is_present else None, ret_subreport)
2615502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
2625502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold  def testCheckPresentIff(self):
2635502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    """Tests _CheckPresentIff()."""
2645502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    self.assertIsNone(checker.PayloadChecker._CheckPresentIff(
2655502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold        None, None, 'foo', 'bar', 'baz'))
2665502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    self.assertIsNone(checker.PayloadChecker._CheckPresentIff(
2675502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold        'a', 'b', 'foo', 'bar', 'baz'))
2685502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    self.assertRaises(update_payload.PayloadError,
2695502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                      checker.PayloadChecker._CheckPresentIff,
2705502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                      'a', None, 'foo', 'bar', 'baz')
2715502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    self.assertRaises(update_payload.PayloadError,
2725502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                      checker.PayloadChecker._CheckPresentIff,
2735502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                      None, 'b', 'foo', 'bar', 'baz')
2745502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
2755502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold  def DoCheckSha256SignatureTest(self, expect_pass, expect_subprocess_call,
2765502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                                 sig_data, sig_asn1_header,
2775502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                                 returned_signed_hash, expected_signed_hash):
2785502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    """Parametric testing of _CheckSha256SignatureTest().
2795502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
2805502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    Args:
281cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold      expect_pass: Whether or not it should pass.
282cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold      expect_subprocess_call: Whether to expect the openssl call to happen.
283cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold      sig_data: The signature raw data.
284cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold      sig_asn1_header: The ASN1 header.
285cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold      returned_signed_hash: The signed hash data retuned by openssl.
286cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold      expected_signed_hash: The signed hash data to compare against.
2875502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    """
288cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold    try:
289cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold      # Stub out the subprocess invocation.
290cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold      self.mox.StubOutWithMock(checker.PayloadChecker, '_Run')
291cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold      if expect_subprocess_call:
292cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold        checker.PayloadChecker._Run(
293cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold            mox.IsA(list), send_data=sig_data).AndReturn(
294cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold                (sig_asn1_header + returned_signed_hash, None))
295cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold
296cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold      self.mox.ReplayAll()
297cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold      if expect_pass:
298cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold        self.assertIsNone(checker.PayloadChecker._CheckSha256Signature(
299cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold            sig_data, 'foo', expected_signed_hash, 'bar'))
300cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold      else:
301cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold        self.assertRaises(update_payload.PayloadError,
302cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold                          checker.PayloadChecker._CheckSha256Signature,
303cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold                          sig_data, 'foo', expected_signed_hash, 'bar')
304cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold    finally:
305cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold      self.mox.UnsetStubs()
3065502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
3075502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold  def testCheckSha256Signature_Pass(self):
3085502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    """Tests _CheckSha256Signature(); pass case."""
3095502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    sig_data = 'fake-signature'.ljust(256)
3105502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    signed_hash = hashlib.sha256('fake-data').digest()
3115502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    self.DoCheckSha256SignatureTest(True, True, sig_data,
3125502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                                    common.SIG_ASN1_HEADER, signed_hash,
3135502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                                    signed_hash)
3145502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
3155502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold  def testCheckSha256Signature_FailBadSignature(self):
3165502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    """Tests _CheckSha256Signature(); fails due to malformed signature."""
317cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold    sig_data = 'fake-signature'  # Malformed (not 256 bytes in length).
3185502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    signed_hash = hashlib.sha256('fake-data').digest()
3195502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    self.DoCheckSha256SignatureTest(False, False, sig_data,
3205502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                                    common.SIG_ASN1_HEADER, signed_hash,
3215502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                                    signed_hash)
3225502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
3235502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold  def testCheckSha256Signature_FailBadOutputLength(self):
3245502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    """Tests _CheckSha256Signature(); fails due to unexpected output length."""
3255502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    sig_data = 'fake-signature'.ljust(256)
326cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold    signed_hash = 'fake-hash'  # Malformed (not 32 bytes in length).
3275502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    self.DoCheckSha256SignatureTest(False, True, sig_data,
3285502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                                    common.SIG_ASN1_HEADER, signed_hash,
3295502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                                    signed_hash)
3305502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
3315502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold  def testCheckSha256Signature_FailBadAsnHeader(self):
3325502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    """Tests _CheckSha256Signature(); fails due to bad ASN1 header."""
3335502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    sig_data = 'fake-signature'.ljust(256)
3345502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    signed_hash = hashlib.sha256('fake-data').digest()
3355502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    bad_asn1_header = 'bad-asn-header'.ljust(len(common.SIG_ASN1_HEADER))
3365502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    self.DoCheckSha256SignatureTest(False, True, sig_data, bad_asn1_header,
3375502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                                    signed_hash, signed_hash)
3385502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
3395502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold  def testCheckSha256Signature_FailBadHash(self):
3405502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    """Tests _CheckSha256Signature(); fails due to bad hash returned."""
3415502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    sig_data = 'fake-signature'.ljust(256)
3425502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    expected_signed_hash = hashlib.sha256('fake-data').digest()
3435502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    returned_signed_hash = hashlib.sha256('bad-fake-data').digest()
3445502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    self.DoCheckSha256SignatureTest(False, True, sig_data,
3455502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                                    common.SIG_ASN1_HEADER,
3465502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                                    expected_signed_hash, returned_signed_hash)
3475502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
3485502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold  def testCheckBlocksFitLength_Pass(self):
3495502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    """Tests _CheckBlocksFitLength(); pass case."""
3505502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    self.assertIsNone(checker.PayloadChecker._CheckBlocksFitLength(
3515502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold        64, 4, 16, 'foo'))
3525502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    self.assertIsNone(checker.PayloadChecker._CheckBlocksFitLength(
3535502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold        60, 4, 16, 'foo'))
3545502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    self.assertIsNone(checker.PayloadChecker._CheckBlocksFitLength(
3555502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold        49, 4, 16, 'foo'))
3565502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    self.assertIsNone(checker.PayloadChecker._CheckBlocksFitLength(
3575502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold        48, 3, 16, 'foo'))
3585502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
3595502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold  def testCheckBlocksFitLength_TooManyBlocks(self):
3605502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    """Tests _CheckBlocksFitLength(); fails due to excess blocks."""
3615502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    self.assertRaises(update_payload.PayloadError,
3625502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                      checker.PayloadChecker._CheckBlocksFitLength,
3635502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                      64, 5, 16, 'foo')
3645502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    self.assertRaises(update_payload.PayloadError,
3655502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                      checker.PayloadChecker._CheckBlocksFitLength,
3665502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                      60, 5, 16, 'foo')
3675502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    self.assertRaises(update_payload.PayloadError,
3685502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                      checker.PayloadChecker._CheckBlocksFitLength,
3695502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                      49, 5, 16, 'foo')
3705502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    self.assertRaises(update_payload.PayloadError,
3715502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                      checker.PayloadChecker._CheckBlocksFitLength,
3725502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                      48, 4, 16, 'foo')
3735502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
3745502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold  def testCheckBlocksFitLength_TooFewBlocks(self):
3755502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    """Tests _CheckBlocksFitLength(); fails due to insufficient blocks."""
3765502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    self.assertRaises(update_payload.PayloadError,
3775502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                      checker.PayloadChecker._CheckBlocksFitLength,
3785502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                      64, 3, 16, 'foo')
3795502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    self.assertRaises(update_payload.PayloadError,
3805502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                      checker.PayloadChecker._CheckBlocksFitLength,
3815502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                      60, 3, 16, 'foo')
3825502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    self.assertRaises(update_payload.PayloadError,
3835502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                      checker.PayloadChecker._CheckBlocksFitLength,
3845502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                      49, 3, 16, 'foo')
3855502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    self.assertRaises(update_payload.PayloadError,
3865502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                      checker.PayloadChecker._CheckBlocksFitLength,
3875502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                      48, 2, 16, 'foo')
3885502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
3895502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold  def DoCheckManifestTest(self, fail_mismatched_block_size, fail_bad_sigs,
3905502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                          fail_mismatched_oki_ori, fail_bad_oki, fail_bad_ori,
3915bc7fbea01f944192f146b97cd83050858cddcc5Gilad Arnold                          fail_bad_nki, fail_bad_nri, fail_old_kernel_fs_size,
3925bc7fbea01f944192f146b97cd83050858cddcc5Gilad Arnold                          fail_old_rootfs_fs_size, fail_new_kernel_fs_size,
3935bc7fbea01f944192f146b97cd83050858cddcc5Gilad Arnold                          fail_new_rootfs_fs_size):
3945502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    """Parametric testing of _CheckManifest().
3955502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
3965502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    Args:
397cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold      fail_mismatched_block_size: Simulate a missing block_size field.
398cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold      fail_bad_sigs: Make signatures descriptor inconsistent.
399cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold      fail_mismatched_oki_ori: Make old rootfs/kernel info partially present.
400cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold      fail_bad_oki: Tamper with old kernel info.
401cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold      fail_bad_ori: Tamper with old rootfs info.
402cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold      fail_bad_nki: Tamper with new kernel info.
403cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold      fail_bad_nri: Tamper with new rootfs info.
404cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold      fail_old_kernel_fs_size: Make old kernel fs size too big.
405cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold      fail_old_rootfs_fs_size: Make old rootfs fs size too big.
406cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold      fail_new_kernel_fs_size: Make new kernel fs size too big.
407cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold      fail_new_rootfs_fs_size: Make new rootfs fs size too big.
4085502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    """
4095502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    # Generate a test payload. For this test, we only care about the manifest
4105502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    # and don't need any data blobs, hence we can use a plain paylaod generator
4115502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    # (which also gives us more control on things that can be screwed up).
4125502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    payload_gen = test_utils.PayloadGenerator()
4135502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
4145502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    # Tamper with block size, if required.
4155502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    if fail_mismatched_block_size:
41618f4f9fab192e75a3477979c03a89381c35fd974Gilad Arnold      payload_gen.SetBlockSize(test_utils.KiB(1))
4175502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    else:
41818f4f9fab192e75a3477979c03a89381c35fd974Gilad Arnold      payload_gen.SetBlockSize(test_utils.KiB(4))
4195502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
4205502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    # Add some operations.
4215bc7fbea01f944192f146b97cd83050858cddcc5Gilad Arnold    payload_gen.AddOperation(False, common.OpType.MOVE,
4225bc7fbea01f944192f146b97cd83050858cddcc5Gilad Arnold                             src_extents=[(0, 16), (16, 497)],
4235bc7fbea01f944192f146b97cd83050858cddcc5Gilad Arnold                             dst_extents=[(16, 496), (0, 16)])
4245bc7fbea01f944192f146b97cd83050858cddcc5Gilad Arnold    payload_gen.AddOperation(True, common.OpType.MOVE,
4255bc7fbea01f944192f146b97cd83050858cddcc5Gilad Arnold                             src_extents=[(0, 8), (8, 8)],
4265bc7fbea01f944192f146b97cd83050858cddcc5Gilad Arnold                             dst_extents=[(8, 8), (0, 8)])
4275502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
4285502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    # Set an invalid signatures block (offset but no size), if required.
4295502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    if fail_bad_sigs:
4305502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold      payload_gen.SetSignatures(32, None)
4315502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
432382df5ce2f4b67bf0998b01c6fedcdb5c35ebef9Gilad Arnold    # Set partition / filesystem sizes.
43318f4f9fab192e75a3477979c03a89381c35fd974Gilad Arnold    rootfs_part_size = test_utils.MiB(8)
43418f4f9fab192e75a3477979c03a89381c35fd974Gilad Arnold    kernel_part_size = test_utils.KiB(512)
435382df5ce2f4b67bf0998b01c6fedcdb5c35ebef9Gilad Arnold    old_rootfs_fs_size = new_rootfs_fs_size = rootfs_part_size
436382df5ce2f4b67bf0998b01c6fedcdb5c35ebef9Gilad Arnold    old_kernel_fs_size = new_kernel_fs_size = kernel_part_size
437382df5ce2f4b67bf0998b01c6fedcdb5c35ebef9Gilad Arnold    if fail_old_kernel_fs_size:
438382df5ce2f4b67bf0998b01c6fedcdb5c35ebef9Gilad Arnold      old_kernel_fs_size += 100
439382df5ce2f4b67bf0998b01c6fedcdb5c35ebef9Gilad Arnold    if fail_old_rootfs_fs_size:
440382df5ce2f4b67bf0998b01c6fedcdb5c35ebef9Gilad Arnold      old_rootfs_fs_size += 100
441382df5ce2f4b67bf0998b01c6fedcdb5c35ebef9Gilad Arnold    if fail_new_kernel_fs_size:
442382df5ce2f4b67bf0998b01c6fedcdb5c35ebef9Gilad Arnold      new_kernel_fs_size += 100
443382df5ce2f4b67bf0998b01c6fedcdb5c35ebef9Gilad Arnold    if fail_new_rootfs_fs_size:
444382df5ce2f4b67bf0998b01c6fedcdb5c35ebef9Gilad Arnold      new_rootfs_fs_size += 100
445382df5ce2f4b67bf0998b01c6fedcdb5c35ebef9Gilad Arnold
4465502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    # Add old kernel/rootfs partition info, as required.
447382df5ce2f4b67bf0998b01c6fedcdb5c35ebef9Gilad Arnold    if fail_mismatched_oki_ori or fail_old_kernel_fs_size or fail_bad_oki:
4485502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold      oki_hash = (None if fail_bad_oki
4495502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                  else hashlib.sha256('fake-oki-content').digest())
450382df5ce2f4b67bf0998b01c6fedcdb5c35ebef9Gilad Arnold      payload_gen.SetPartInfo(True, False, old_kernel_fs_size, oki_hash)
451382df5ce2f4b67bf0998b01c6fedcdb5c35ebef9Gilad Arnold    if not fail_mismatched_oki_ori and (fail_old_rootfs_fs_size or
452382df5ce2f4b67bf0998b01c6fedcdb5c35ebef9Gilad Arnold                                        fail_bad_ori):
453382df5ce2f4b67bf0998b01c6fedcdb5c35ebef9Gilad Arnold      ori_hash = (None if fail_bad_ori
454382df5ce2f4b67bf0998b01c6fedcdb5c35ebef9Gilad Arnold                  else hashlib.sha256('fake-ori-content').digest())
455382df5ce2f4b67bf0998b01c6fedcdb5c35ebef9Gilad Arnold      payload_gen.SetPartInfo(False, False, old_rootfs_fs_size, ori_hash)
4565502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
4575502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    # Add new kernel/rootfs partition info.
4585502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    payload_gen.SetPartInfo(
459382df5ce2f4b67bf0998b01c6fedcdb5c35ebef9Gilad Arnold        True, True, new_kernel_fs_size,
4605502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold        None if fail_bad_nki else hashlib.sha256('fake-nki-content').digest())
4615502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    payload_gen.SetPartInfo(
462382df5ce2f4b67bf0998b01c6fedcdb5c35ebef9Gilad Arnold        False, True, new_rootfs_fs_size,
4635502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold        None if fail_bad_nri else hashlib.sha256('fake-nri-content').digest())
4645502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
4650d575cde18a1b44e386181dc1abbc611b9ae7a59Gilad Arnold    # Set the minor version.
4660d575cde18a1b44e386181dc1abbc611b9ae7a59Gilad Arnold    payload_gen.SetMinorVersion(0)
4670d575cde18a1b44e386181dc1abbc611b9ae7a59Gilad Arnold
4685502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    # Create the test object.
4695502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    payload_checker = _GetPayloadChecker(payload_gen.WriteToFile)
4705502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    report = checker._PayloadReport()
4715502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
4725502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    should_fail = (fail_mismatched_block_size or fail_bad_sigs or
4735502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                   fail_mismatched_oki_ori or fail_bad_oki or fail_bad_ori or
4745bc7fbea01f944192f146b97cd83050858cddcc5Gilad Arnold                   fail_bad_nki or fail_bad_nri or fail_old_kernel_fs_size or
4755bc7fbea01f944192f146b97cd83050858cddcc5Gilad Arnold                   fail_old_rootfs_fs_size or fail_new_kernel_fs_size or
4765bc7fbea01f944192f146b97cd83050858cddcc5Gilad Arnold                   fail_new_rootfs_fs_size)
4775502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    if should_fail:
4785502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold      self.assertRaises(update_payload.PayloadError,
479382df5ce2f4b67bf0998b01c6fedcdb5c35ebef9Gilad Arnold                        payload_checker._CheckManifest, report,
480382df5ce2f4b67bf0998b01c6fedcdb5c35ebef9Gilad Arnold                        rootfs_part_size, kernel_part_size)
4815502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    else:
482382df5ce2f4b67bf0998b01c6fedcdb5c35ebef9Gilad Arnold      self.assertIsNone(payload_checker._CheckManifest(report,
483382df5ce2f4b67bf0998b01c6fedcdb5c35ebef9Gilad Arnold                                                       rootfs_part_size,
484382df5ce2f4b67bf0998b01c6fedcdb5c35ebef9Gilad Arnold                                                       kernel_part_size))
4855502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
4865502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold  def testCheckLength(self):
4875502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    """Tests _CheckLength()."""
4885502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    payload_checker = checker.PayloadChecker(self.MockPayload())
4895502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    block_size = payload_checker.block_size
4905502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
4915502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    # Passes.
4925502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    self.assertIsNone(payload_checker._CheckLength(
4935502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold        int(3.5 * block_size), 4, 'foo', 'bar'))
4945502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    # Fails, too few blocks.
4955502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    self.assertRaises(update_payload.PayloadError,
4965502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                      payload_checker._CheckLength,
4975502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                      int(3.5 * block_size), 3, 'foo', 'bar')
4985502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    # Fails, too many blocks.
4995502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    self.assertRaises(update_payload.PayloadError,
5005502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                      payload_checker._CheckLength,
5015502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                      int(3.5 * block_size), 5, 'foo', 'bar')
5025502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
5035502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold  def testCheckExtents(self):
5045502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    """Tests _CheckExtents()."""
5055502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    payload_checker = checker.PayloadChecker(self.MockPayload())
5065502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    block_size = payload_checker.block_size
5075502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
5085502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    # Passes w/ all real extents.
5095502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    extents = self.NewExtentList((0, 4), (8, 3), (1024, 16))
5105502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    self.assertEquals(
511cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold        23,
5125502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold        payload_checker._CheckExtents(extents, (1024 + 16) * block_size,
513cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold                                      collections.defaultdict(int), 'foo'))
5145502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
5155502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    # Passes w/ pseudo-extents (aka sparse holes).
5165502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    extents = self.NewExtentList((0, 4), (common.PSEUDO_EXTENT_MARKER, 5),
5175502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                                 (8, 3))
5185502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    self.assertEquals(
519cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold        12,
5205502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold        payload_checker._CheckExtents(extents, (1024 + 16) * block_size,
5215502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                                      collections.defaultdict(int), 'foo',
522cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold                                      allow_pseudo=True))
5235502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
5245502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    # Passes w/ pseudo-extent due to a signature.
5255502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    extents = self.NewExtentList((common.PSEUDO_EXTENT_MARKER, 2))
5265502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    self.assertEquals(
527cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold        2,
5285502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold        payload_checker._CheckExtents(extents, (1024 + 16) * block_size,
5295502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                                      collections.defaultdict(int), 'foo',
530cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold                                      allow_signature=True))
5315502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
5325502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    # Fails, extent missing a start block.
5335502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    extents = self.NewExtentList((-1, 4), (8, 3), (1024, 16))
5345502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    self.assertRaises(
5355502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold        update_payload.PayloadError, payload_checker._CheckExtents,
5365502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold        extents, (1024 + 16) * block_size, collections.defaultdict(int),
5375502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold        'foo')
5385502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
5395502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    # Fails, extent missing block count.
5405502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    extents = self.NewExtentList((0, -1), (8, 3), (1024, 16))
5415502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    self.assertRaises(
5425502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold        update_payload.PayloadError, payload_checker._CheckExtents,
5435502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold        extents, (1024 + 16) * block_size, collections.defaultdict(int),
5445502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold        'foo')
5455502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
5465502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    # Fails, extent has zero blocks.
5475502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    extents = self.NewExtentList((0, 4), (8, 3), (1024, 0))
5485502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    self.assertRaises(
5495502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold        update_payload.PayloadError, payload_checker._CheckExtents,
5505502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold        extents, (1024 + 16) * block_size, collections.defaultdict(int),
5515502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold        'foo')
5525502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
5535502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    # Fails, extent exceeds partition boundaries.
5545502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    extents = self.NewExtentList((0, 4), (8, 3), (1024, 16))
5555502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    self.assertRaises(
5565502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold        update_payload.PayloadError, payload_checker._CheckExtents,
5575502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold        extents, (1024 + 15) * block_size, collections.defaultdict(int),
5585502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold        'foo')
5595502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
5605502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold  def testCheckReplaceOperation(self):
5615502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    """Tests _CheckReplaceOperation() where op.type == REPLACE."""
5625502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    payload_checker = checker.PayloadChecker(self.MockPayload())
5635502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    block_size = payload_checker.block_size
5645502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    data_length = 10000
5655502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
5665502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    op = self.mox.CreateMock(
5672846677f9ec7725d9cf9513768477c873c19ba78Alex Deymo        update_metadata_pb2.InstallOperation)
5685502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    op.type = common.OpType.REPLACE
5695502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
5705502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    # Pass.
5715502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    op.src_extents = []
5725502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    self.assertIsNone(
5735502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold        payload_checker._CheckReplaceOperation(
5745502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold            op, data_length, (data_length + block_size - 1) / block_size,
5755502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold            'foo'))
5765502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
5775502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    # Fail, src extents founds.
5785502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    op.src_extents = ['bar']
5795502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    self.assertRaises(
5805502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold        update_payload.PayloadError,
5815502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold        payload_checker._CheckReplaceOperation,
5825502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold        op, data_length, (data_length + block_size - 1) / block_size, 'foo')
5835502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
5845502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    # Fail, missing data.
5855502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    op.src_extents = []
5865502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    self.assertRaises(
5875502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold        update_payload.PayloadError,
5885502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold        payload_checker._CheckReplaceOperation,
5895502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold        op, None, (data_length + block_size - 1) / block_size, 'foo')
5905502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
5915502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    # Fail, length / block number mismatch.
5925502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    op.src_extents = ['bar']
5935502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    self.assertRaises(
5945502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold        update_payload.PayloadError,
5955502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold        payload_checker._CheckReplaceOperation,
5965502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold        op, data_length, (data_length + block_size - 1) / block_size + 1, 'foo')
5975502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
5985502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold  def testCheckReplaceBzOperation(self):
5995502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    """Tests _CheckReplaceOperation() where op.type == REPLACE_BZ."""
6005502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    payload_checker = checker.PayloadChecker(self.MockPayload())
6015502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    block_size = payload_checker.block_size
6025502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    data_length = block_size * 3
6035502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
6045502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    op = self.mox.CreateMock(
6052846677f9ec7725d9cf9513768477c873c19ba78Alex Deymo        update_metadata_pb2.InstallOperation)
6065502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    op.type = common.OpType.REPLACE_BZ
6075502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
6085502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    # Pass.
6095502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    op.src_extents = []
6105502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    self.assertIsNone(
6115502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold        payload_checker._CheckReplaceOperation(
6125502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold            op, data_length, (data_length + block_size - 1) / block_size + 5,
6135502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold            'foo'))
6145502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
6155502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    # Fail, src extents founds.
6165502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    op.src_extents = ['bar']
6175502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    self.assertRaises(
6185502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold        update_payload.PayloadError,
6195502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold        payload_checker._CheckReplaceOperation,
6205502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold        op, data_length, (data_length + block_size - 1) / block_size + 5, 'foo')
6215502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
6225502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    # Fail, missing data.
6235502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    op.src_extents = []
6245502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    self.assertRaises(
6255502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold        update_payload.PayloadError,
6265502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold        payload_checker._CheckReplaceOperation,
6275502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold        op, None, (data_length + block_size - 1) / block_size, 'foo')
6285502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
6295502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    # Fail, too few blocks to justify BZ.
6305502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    op.src_extents = []
6315502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    self.assertRaises(
6325502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold        update_payload.PayloadError,
6335502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold        payload_checker._CheckReplaceOperation,
6345502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold        op, data_length, (data_length + block_size - 1) / block_size, 'foo')
6355502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
6365502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold  def testCheckMoveOperation_Pass(self):
6375502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    """Tests _CheckMoveOperation(); pass case."""
6385502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    payload_checker = checker.PayloadChecker(self.MockPayload())
6392846677f9ec7725d9cf9513768477c873c19ba78Alex Deymo    op = update_metadata_pb2.InstallOperation()
6405502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    op.type = common.OpType.MOVE
6415502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
6425502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    self.AddToMessage(op.src_extents,
643b065e13f600d0efc7f089a382611ffd93a8afce9Allie Wood                      self.NewExtentList((1, 4), (12, 2), (1024, 128)))
6445502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    self.AddToMessage(op.dst_extents,
6455502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                      self.NewExtentList((16, 128), (512, 6)))
6465502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    self.assertIsNone(
6475502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold        payload_checker._CheckMoveOperation(op, None, 134, 134, 'foo'))
6485502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
6495502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold  def testCheckMoveOperation_FailContainsData(self):
6505502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    """Tests _CheckMoveOperation(); fails, message contains data."""
6515502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    payload_checker = checker.PayloadChecker(self.MockPayload())
6522846677f9ec7725d9cf9513768477c873c19ba78Alex Deymo    op = update_metadata_pb2.InstallOperation()
6535502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    op.type = common.OpType.MOVE
6545502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
6555502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    self.AddToMessage(op.src_extents,
656b065e13f600d0efc7f089a382611ffd93a8afce9Allie Wood                      self.NewExtentList((1, 4), (12, 2), (1024, 128)))
6575502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    self.AddToMessage(op.dst_extents,
6585502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                      self.NewExtentList((16, 128), (512, 6)))
6595502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    self.assertRaises(
6605502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold        update_payload.PayloadError,
6615502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold        payload_checker._CheckMoveOperation,
6625502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold        op, 1024, 134, 134, 'foo')
6635502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
6645502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold  def testCheckMoveOperation_FailInsufficientSrcBlocks(self):
6655502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    """Tests _CheckMoveOperation(); fails, not enough actual src blocks."""
6665502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    payload_checker = checker.PayloadChecker(self.MockPayload())
6672846677f9ec7725d9cf9513768477c873c19ba78Alex Deymo    op = update_metadata_pb2.InstallOperation()
6685502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    op.type = common.OpType.MOVE
6695502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
6705502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    self.AddToMessage(op.src_extents,
671b065e13f600d0efc7f089a382611ffd93a8afce9Allie Wood                      self.NewExtentList((1, 4), (12, 2), (1024, 127)))
6725502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    self.AddToMessage(op.dst_extents,
6735502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                      self.NewExtentList((16, 128), (512, 6)))
6745502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    self.assertRaises(
6755502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold        update_payload.PayloadError,
6765502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold        payload_checker._CheckMoveOperation,
6775502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold        op, None, 134, 134, 'foo')
6785502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
6795502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold  def testCheckMoveOperation_FailInsufficientDstBlocks(self):
6805502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    """Tests _CheckMoveOperation(); fails, not enough actual dst blocks."""
6815502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    payload_checker = checker.PayloadChecker(self.MockPayload())
6822846677f9ec7725d9cf9513768477c873c19ba78Alex Deymo    op = update_metadata_pb2.InstallOperation()
6835502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    op.type = common.OpType.MOVE
6845502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
6855502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    self.AddToMessage(op.src_extents,
686b065e13f600d0efc7f089a382611ffd93a8afce9Allie Wood                      self.NewExtentList((1, 4), (12, 2), (1024, 128)))
6875502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    self.AddToMessage(op.dst_extents,
6885502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                      self.NewExtentList((16, 128), (512, 5)))
6895502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    self.assertRaises(
6905502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold        update_payload.PayloadError,
6915502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold        payload_checker._CheckMoveOperation,
6925502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold        op, None, 134, 134, 'foo')
6935502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
6945502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold  def testCheckMoveOperation_FailExcessSrcBlocks(self):
6955502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    """Tests _CheckMoveOperation(); fails, too many actual src blocks."""
6965502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    payload_checker = checker.PayloadChecker(self.MockPayload())
6972846677f9ec7725d9cf9513768477c873c19ba78Alex Deymo    op = update_metadata_pb2.InstallOperation()
6985502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    op.type = common.OpType.MOVE
6995502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
7005502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    self.AddToMessage(op.src_extents,
701b065e13f600d0efc7f089a382611ffd93a8afce9Allie Wood                      self.NewExtentList((1, 4), (12, 2), (1024, 128)))
7025502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    self.AddToMessage(op.dst_extents,
7035502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                      self.NewExtentList((16, 128), (512, 5)))
7045502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    self.assertRaises(
7055502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold        update_payload.PayloadError,
7065502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold        payload_checker._CheckMoveOperation,
7075502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold        op, None, 134, 134, 'foo')
7085502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    self.AddToMessage(op.src_extents,
709b065e13f600d0efc7f089a382611ffd93a8afce9Allie Wood                      self.NewExtentList((1, 4), (12, 2), (1024, 129)))
7105502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    self.AddToMessage(op.dst_extents,
7115502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                      self.NewExtentList((16, 128), (512, 6)))
7125502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    self.assertRaises(
7135502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold        update_payload.PayloadError,
7145502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold        payload_checker._CheckMoveOperation,
7155502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold        op, None, 134, 134, 'foo')
7165502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
7175502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold  def testCheckMoveOperation_FailExcessDstBlocks(self):
7185502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    """Tests _CheckMoveOperation(); fails, too many actual dst blocks."""
7195502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    payload_checker = checker.PayloadChecker(self.MockPayload())
7202846677f9ec7725d9cf9513768477c873c19ba78Alex Deymo    op = update_metadata_pb2.InstallOperation()
7215502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    op.type = common.OpType.MOVE
7225502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
7235502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    self.AddToMessage(op.src_extents,
724b065e13f600d0efc7f089a382611ffd93a8afce9Allie Wood                      self.NewExtentList((1, 4), (12, 2), (1024, 128)))
7255502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    self.AddToMessage(op.dst_extents,
7265502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                      self.NewExtentList((16, 128), (512, 7)))
7275502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    self.assertRaises(
7285502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold        update_payload.PayloadError,
7295502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold        payload_checker._CheckMoveOperation,
7305502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold        op, None, 134, 134, 'foo')
7315502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
7325502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold  def testCheckMoveOperation_FailStagnantBlocks(self):
7335502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    """Tests _CheckMoveOperation(); fails, there are blocks that do not move."""
7345502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    payload_checker = checker.PayloadChecker(self.MockPayload())
7352846677f9ec7725d9cf9513768477c873c19ba78Alex Deymo    op = update_metadata_pb2.InstallOperation()
7365502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    op.type = common.OpType.MOVE
7375502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
7385502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    self.AddToMessage(op.src_extents,
739b065e13f600d0efc7f089a382611ffd93a8afce9Allie Wood                      self.NewExtentList((1, 4), (12, 2), (1024, 128)))
740b065e13f600d0efc7f089a382611ffd93a8afce9Allie Wood    self.AddToMessage(op.dst_extents,
741b065e13f600d0efc7f089a382611ffd93a8afce9Allie Wood                      self.NewExtentList((8, 128), (512, 6)))
742b065e13f600d0efc7f089a382611ffd93a8afce9Allie Wood    self.assertRaises(
743b065e13f600d0efc7f089a382611ffd93a8afce9Allie Wood        update_payload.PayloadError,
744b065e13f600d0efc7f089a382611ffd93a8afce9Allie Wood        payload_checker._CheckMoveOperation,
745b065e13f600d0efc7f089a382611ffd93a8afce9Allie Wood        op, None, 134, 134, 'foo')
746b065e13f600d0efc7f089a382611ffd93a8afce9Allie Wood
747b065e13f600d0efc7f089a382611ffd93a8afce9Allie Wood  def testCheckMoveOperation_FailZeroStartBlock(self):
748b065e13f600d0efc7f089a382611ffd93a8afce9Allie Wood    """Tests _CheckMoveOperation(); fails, has extent with start block 0."""
749b065e13f600d0efc7f089a382611ffd93a8afce9Allie Wood    payload_checker = checker.PayloadChecker(self.MockPayload())
7502846677f9ec7725d9cf9513768477c873c19ba78Alex Deymo    op = update_metadata_pb2.InstallOperation()
751b065e13f600d0efc7f089a382611ffd93a8afce9Allie Wood    op.type = common.OpType.MOVE
752b065e13f600d0efc7f089a382611ffd93a8afce9Allie Wood
753b065e13f600d0efc7f089a382611ffd93a8afce9Allie Wood    self.AddToMessage(op.src_extents,
7545502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                      self.NewExtentList((0, 4), (12, 2), (1024, 128)))
7555502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    self.AddToMessage(op.dst_extents,
7565502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                      self.NewExtentList((8, 128), (512, 6)))
7575502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    self.assertRaises(
7585502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold        update_payload.PayloadError,
7595502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold        payload_checker._CheckMoveOperation,
7605502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold        op, None, 134, 134, 'foo')
7615502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
762b065e13f600d0efc7f089a382611ffd93a8afce9Allie Wood    self.AddToMessage(op.src_extents,
763b065e13f600d0efc7f089a382611ffd93a8afce9Allie Wood                      self.NewExtentList((1, 4), (12, 2), (1024, 128)))
764b065e13f600d0efc7f089a382611ffd93a8afce9Allie Wood    self.AddToMessage(op.dst_extents,
765b065e13f600d0efc7f089a382611ffd93a8afce9Allie Wood                      self.NewExtentList((0, 128), (512, 6)))
766b065e13f600d0efc7f089a382611ffd93a8afce9Allie Wood    self.assertRaises(
767b065e13f600d0efc7f089a382611ffd93a8afce9Allie Wood        update_payload.PayloadError,
768b065e13f600d0efc7f089a382611ffd93a8afce9Allie Wood        payload_checker._CheckMoveOperation,
769b065e13f600d0efc7f089a382611ffd93a8afce9Allie Wood        op, None, 134, 134, 'foo')
770b065e13f600d0efc7f089a382611ffd93a8afce9Allie Wood
77192161a7b83c3a491871a167a4d46e4e6b6101e81Sen Jiang  def testCheckAnyDiff(self):
77292161a7b83c3a491871a167a4d46e4e6b6101e81Sen Jiang    """Tests _CheckAnyDiffOperation()."""
7735502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    payload_checker = checker.PayloadChecker(self.MockPayload())
7745502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
7755502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    # Pass.
7765502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    self.assertIsNone(
77792161a7b83c3a491871a167a4d46e4e6b6101e81Sen Jiang        payload_checker._CheckAnyDiffOperation(10000, 3, 'foo'))
7785502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
7795502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    # Fail, missing data blob.
7805502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    self.assertRaises(
7815502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold        update_payload.PayloadError,
78292161a7b83c3a491871a167a4d46e4e6b6101e81Sen Jiang        payload_checker._CheckAnyDiffOperation,
7835502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold        None, 3, 'foo')
7845502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
7855502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    # Fail, too big of a diff blob (unjustified).
7865502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    self.assertRaises(
7875502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold        update_payload.PayloadError,
78892161a7b83c3a491871a167a4d46e4e6b6101e81Sen Jiang        payload_checker._CheckAnyDiffOperation,
7895502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold        10000, 2, 'foo')
7905502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
791f5c4f3e2a6e7c93e5b4c09272091f23a935fab86Allie Wood  def testCheckSourceCopyOperation_Pass(self):
792f5c4f3e2a6e7c93e5b4c09272091f23a935fab86Allie Wood    """Tests _CheckSourceCopyOperation(); pass case."""
793f5c4f3e2a6e7c93e5b4c09272091f23a935fab86Allie Wood    payload_checker = checker.PayloadChecker(self.MockPayload())
794f5c4f3e2a6e7c93e5b4c09272091f23a935fab86Allie Wood    self.assertIsNone(
795f5c4f3e2a6e7c93e5b4c09272091f23a935fab86Allie Wood        payload_checker._CheckSourceCopyOperation(None, 134, 134, 'foo'))
796f5c4f3e2a6e7c93e5b4c09272091f23a935fab86Allie Wood
797f5c4f3e2a6e7c93e5b4c09272091f23a935fab86Allie Wood  def testCheckSourceCopyOperation_FailContainsData(self):
798f5c4f3e2a6e7c93e5b4c09272091f23a935fab86Allie Wood    """Tests _CheckSourceCopyOperation(); message contains data."""
799f5c4f3e2a6e7c93e5b4c09272091f23a935fab86Allie Wood    payload_checker = checker.PayloadChecker(self.MockPayload())
800f5c4f3e2a6e7c93e5b4c09272091f23a935fab86Allie Wood    self.assertRaises(update_payload.PayloadError,
801f5c4f3e2a6e7c93e5b4c09272091f23a935fab86Allie Wood                      payload_checker._CheckSourceCopyOperation,
802f5c4f3e2a6e7c93e5b4c09272091f23a935fab86Allie Wood                      134, 0, 0, 'foo')
803f5c4f3e2a6e7c93e5b4c09272091f23a935fab86Allie Wood
804f5c4f3e2a6e7c93e5b4c09272091f23a935fab86Allie Wood  def testCheckSourceCopyOperation_FailBlockCountsMismatch(self):
805f5c4f3e2a6e7c93e5b4c09272091f23a935fab86Allie Wood    """Tests _CheckSourceCopyOperation(); src and dst block totals not equal."""
806f5c4f3e2a6e7c93e5b4c09272091f23a935fab86Allie Wood    payload_checker = checker.PayloadChecker(self.MockPayload())
807f5c4f3e2a6e7c93e5b4c09272091f23a935fab86Allie Wood    self.assertRaises(update_payload.PayloadError,
808f5c4f3e2a6e7c93e5b4c09272091f23a935fab86Allie Wood                      payload_checker._CheckSourceCopyOperation,
809f5c4f3e2a6e7c93e5b4c09272091f23a935fab86Allie Wood                      None, 0, 1, 'foo')
810f5c4f3e2a6e7c93e5b4c09272091f23a935fab86Allie Wood
8115502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold  def DoCheckOperationTest(self, op_type_name, is_last, allow_signature,
8125502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                           allow_unhashed, fail_src_extents, fail_dst_extents,
8135502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                           fail_mismatched_data_offset_length,
8145502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                           fail_missing_dst_extents, fail_src_length,
8155502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                           fail_dst_length, fail_data_hash,
8167cf9f13f2715d0a033c6300a244b40302d8eb7b7Allie Wood                           fail_prev_data_offset, fail_bad_minor_version):
8175502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    """Parametric testing of _CheckOperation().
8185502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
8195502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    Args:
820f5c4f3e2a6e7c93e5b4c09272091f23a935fab86Allie Wood      op_type_name: 'REPLACE', 'REPLACE_BZ', 'MOVE', 'BSDIFF', 'SOURCE_COPY',
821f5c4f3e2a6e7c93e5b4c09272091f23a935fab86Allie Wood        or 'SOURCE_BSDIFF'.
822cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold      is_last: Whether we're testing the last operation in a sequence.
823cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold      allow_signature: Whether we're testing a signature-capable operation.
824cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold      allow_unhashed: Whether we're allowing to not hash the data.
825cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold      fail_src_extents: Tamper with src extents.
826cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold      fail_dst_extents: Tamper with dst extents.
827cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold      fail_mismatched_data_offset_length: Make data_{offset,length}
828cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold        inconsistent.
829cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold      fail_missing_dst_extents: Do not include dst extents.
830cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold      fail_src_length: Make src length inconsistent.
831cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold      fail_dst_length: Make dst length inconsistent.
832cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold      fail_data_hash: Tamper with the data blob hash.
833cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold      fail_prev_data_offset: Make data space uses incontiguous.
8347cf9f13f2715d0a033c6300a244b40302d8eb7b7Allie Wood      fail_bad_minor_version: Make minor version incompatible with op.
8355502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    """
8365502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    op_type = _OpTypeByName(op_type_name)
8375502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
8385502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    # Create the test object.
8395502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    payload = self.MockPayload()
840eaed0d1371d781d3f5effa1475f5202dea9467e7Gilad Arnold    payload_checker = checker.PayloadChecker(payload,
841eaed0d1371d781d3f5effa1475f5202dea9467e7Gilad Arnold                                             allow_unhashed=allow_unhashed)
8425502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    block_size = payload_checker.block_size
8435502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
8445502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    # Create auxiliary arguments.
84518f4f9fab192e75a3477979c03a89381c35fd974Gilad Arnold    old_part_size = test_utils.MiB(4)
84618f4f9fab192e75a3477979c03a89381c35fd974Gilad Arnold    new_part_size = test_utils.MiB(8)
8475502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    old_block_counters = array.array(
8485502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold        'B', [0] * ((old_part_size + block_size - 1) / block_size))
8495502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    new_block_counters = array.array(
8505502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold        'B', [0] * ((new_part_size + block_size - 1) / block_size))
8515502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    prev_data_offset = 1876
8525502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    blob_hash_counts = collections.defaultdict(int)
8535502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
8545502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    # Create the operation object for the test.
8552846677f9ec7725d9cf9513768477c873c19ba78Alex Deymo    op = update_metadata_pb2.InstallOperation()
8565502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    op.type = op_type
8575502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
8585502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    total_src_blocks = 0
859f5c4f3e2a6e7c93e5b4c09272091f23a935fab86Allie Wood    if op_type in (common.OpType.MOVE, common.OpType.BSDIFF,
860f5c4f3e2a6e7c93e5b4c09272091f23a935fab86Allie Wood                   common.OpType.SOURCE_COPY, common.OpType.SOURCE_BSDIFF):
8615502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold      if fail_src_extents:
8625502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold        self.AddToMessage(op.src_extents,
863b065e13f600d0efc7f089a382611ffd93a8afce9Allie Wood                          self.NewExtentList((1, 0)))
8645502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold      else:
8655502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold        self.AddToMessage(op.src_extents,
866b065e13f600d0efc7f089a382611ffd93a8afce9Allie Wood                          self.NewExtentList((1, 16)))
8675502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold        total_src_blocks = 16
8685502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
8697cf9f13f2715d0a033c6300a244b40302d8eb7b7Allie Wood    if op_type in (common.OpType.REPLACE, common.OpType.REPLACE_BZ):
8700d575cde18a1b44e386181dc1abbc611b9ae7a59Gilad Arnold      payload_checker.minor_version = 0
8717cf9f13f2715d0a033c6300a244b40302d8eb7b7Allie Wood    elif op_type in (common.OpType.MOVE, common.OpType.BSDIFF):
8720d575cde18a1b44e386181dc1abbc611b9ae7a59Gilad Arnold      payload_checker.minor_version = 2 if fail_bad_minor_version else 1
8737cf9f13f2715d0a033c6300a244b40302d8eb7b7Allie Wood    elif op_type in (common.OpType.SOURCE_COPY, common.OpType.SOURCE_BSDIFF):
8740d575cde18a1b44e386181dc1abbc611b9ae7a59Gilad Arnold      payload_checker.minor_version = 1 if fail_bad_minor_version else 2
8757cf9f13f2715d0a033c6300a244b40302d8eb7b7Allie Wood
876f5c4f3e2a6e7c93e5b4c09272091f23a935fab86Allie Wood    if op_type not in (common.OpType.MOVE, common.OpType.SOURCE_COPY):
8775502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold      if not fail_mismatched_data_offset_length:
8785502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold        op.data_length = 16 * block_size - 8
8795502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold      if fail_prev_data_offset:
8805502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold        op.data_offset = prev_data_offset + 16
8815502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold      else:
8825502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold        op.data_offset = prev_data_offset
8835502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
8845502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold      fake_data = 'fake-data'.ljust(op.data_length)
8855502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold      if not (allow_unhashed or (is_last and allow_signature and
8865502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                                 op_type == common.OpType.REPLACE)):
8875502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold        if not fail_data_hash:
8885502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold          # Create a valid data blob hash.
8895502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold          op.data_sha256_hash = hashlib.sha256(fake_data).digest()
8905502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold          payload.ReadDataBlob(op.data_offset, op.data_length).AndReturn(
8915502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold              fake_data)
8925502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold      elif fail_data_hash:
8935502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold        # Create an invalid data blob hash.
8945502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold        op.data_sha256_hash = hashlib.sha256(
8955502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold            fake_data.replace(' ', '-')).digest()
8965502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold        payload.ReadDataBlob(op.data_offset, op.data_length).AndReturn(
8975502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold            fake_data)
8985502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
8995502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    total_dst_blocks = 0
9005502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    if not fail_missing_dst_extents:
9015502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold      total_dst_blocks = 16
9025502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold      if fail_dst_extents:
9035502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold        self.AddToMessage(op.dst_extents,
9045502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                          self.NewExtentList((4, 16), (32, 0)))
9055502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold      else:
9065502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold        self.AddToMessage(op.dst_extents,
9075502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                          self.NewExtentList((4, 8), (64, 8)))
9085502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
9095502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    if total_src_blocks:
9105502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold      if fail_src_length:
9115502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold        op.src_length = total_src_blocks * block_size + 8
9125502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold      else:
9135502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold        op.src_length = total_src_blocks * block_size
9145502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    elif fail_src_length:
9155502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold      # Add an orphaned src_length.
9165502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold      op.src_length = 16
9175502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
9185502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    if total_dst_blocks:
9195502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold      if fail_dst_length:
9205502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold        op.dst_length = total_dst_blocks * block_size + 8
9215502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold      else:
9225502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold        op.dst_length = total_dst_blocks * block_size
9235502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
9245502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    self.mox.ReplayAll()
9255502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    should_fail = (fail_src_extents or fail_dst_extents or
9265502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                   fail_mismatched_data_offset_length or
9275502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                   fail_missing_dst_extents or fail_src_length or
9287cf9f13f2715d0a033c6300a244b40302d8eb7b7Allie Wood                   fail_dst_length or fail_data_hash or fail_prev_data_offset or
9297cf9f13f2715d0a033c6300a244b40302d8eb7b7Allie Wood                   fail_bad_minor_version)
930cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold    args = (op, 'foo', is_last, old_block_counters, new_block_counters,
931cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold            old_part_size, new_part_size, prev_data_offset, allow_signature,
932cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold            blob_hash_counts)
9335502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    if should_fail:
9345502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold      self.assertRaises(update_payload.PayloadError,
935cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold                        payload_checker._CheckOperation, *args)
9365502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    else:
937cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold      self.assertEqual(op.data_length if op.HasField('data_length') else 0,
938cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold                       payload_checker._CheckOperation(*args))
9395502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
9405502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold  def testAllocBlockCounters(self):
9415502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    """Tests _CheckMoveOperation()."""
9425502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    payload_checker = checker.PayloadChecker(self.MockPayload())
9435502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    block_size = payload_checker.block_size
9445502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
9455502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    # Check allocation for block-aligned partition size, ensure it's integers.
9465502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    result = payload_checker._AllocBlockCounters(16 * block_size)
947cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold    self.assertEqual(16, len(result))
948cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold    self.assertEqual(int, type(result[0]))
9495502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
9505502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    # Check allocation of unaligned partition sizes.
9515502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    result = payload_checker._AllocBlockCounters(16 * block_size - 1)
952cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold    self.assertEqual(16, len(result))
9535502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    result = payload_checker._AllocBlockCounters(16 * block_size + 1)
954cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold    self.assertEqual(17, len(result))
9555502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
956fb04d30e433eed1d7e7b78114c1a747c89091362Allie Wood  def DoCheckOperationsTest(self, fail_nonexhaustive_full_update):
9575502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    # Generate a test payload. For this test, we only care about one
9585502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    # (arbitrary) set of operations, so we'll only be generating kernel and
9595502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    # test with them.
9605502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    payload_gen = test_utils.PayloadGenerator()
9615502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
96218f4f9fab192e75a3477979c03a89381c35fd974Gilad Arnold    block_size = test_utils.KiB(4)
9635502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    payload_gen.SetBlockSize(block_size)
9645502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
96518f4f9fab192e75a3477979c03a89381c35fd974Gilad Arnold    rootfs_part_size = test_utils.MiB(8)
9665502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
9675502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    # Fake rootfs operations in a full update, tampered with as required.
9685502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    rootfs_op_type = common.OpType.REPLACE
9695502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    rootfs_data_length = rootfs_part_size
9705502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    if fail_nonexhaustive_full_update:
9715502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold      rootfs_data_length -= block_size
9725502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
9735502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    payload_gen.AddOperation(False, rootfs_op_type,
9745502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                             dst_extents=[(0, rootfs_data_length / block_size)],
9755502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                             data_offset=0,
9765502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                             data_length=rootfs_data_length)
9775502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
9785502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    # Create the test object.
979eaed0d1371d781d3f5effa1475f5202dea9467e7Gilad Arnold    payload_checker = _GetPayloadChecker(payload_gen.WriteToFile,
980eaed0d1371d781d3f5effa1475f5202dea9467e7Gilad Arnold                                         checker_init_dargs={
981eaed0d1371d781d3f5effa1475f5202dea9467e7Gilad Arnold                                             'allow_unhashed': True})
9825502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    payload_checker.payload_type = checker._TYPE_FULL
9835502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    report = checker._PayloadReport()
9845502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
985cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold    args = (payload_checker.payload.manifest.install_operations, report,
986cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold            'foo', 0, rootfs_part_size, rootfs_part_size, 0, False)
987fb04d30e433eed1d7e7b78114c1a747c89091362Allie Wood    if fail_nonexhaustive_full_update:
9885502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold      self.assertRaises(update_payload.PayloadError,
989cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold                        payload_checker._CheckOperations, *args)
9905502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    else:
991cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold      self.assertEqual(rootfs_data_length,
992cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold                       payload_checker._CheckOperations(*args))
9935502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
9945502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold  def DoCheckSignaturesTest(self, fail_empty_sigs_blob, fail_missing_pseudo_op,
9955502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                            fail_mismatched_pseudo_op, fail_sig_missing_fields,
9965502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                            fail_unknown_sig_version, fail_incorrect_sig):
9975502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    # Generate a test payload. For this test, we only care about the signature
9985502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    # block and how it relates to the payload hash. Therefore, we're generating
9995502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    # a random (otherwise useless) payload for this purpose.
10005502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    payload_gen = test_utils.EnhancedPayloadGenerator()
100118f4f9fab192e75a3477979c03a89381c35fd974Gilad Arnold    block_size = test_utils.KiB(4)
10025502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    payload_gen.SetBlockSize(block_size)
100318f4f9fab192e75a3477979c03a89381c35fd974Gilad Arnold    rootfs_part_size = test_utils.MiB(2)
100418f4f9fab192e75a3477979c03a89381c35fd974Gilad Arnold    kernel_part_size = test_utils.KiB(16)
10055502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    payload_gen.SetPartInfo(False, True, rootfs_part_size,
10065502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                            hashlib.sha256('fake-new-rootfs-content').digest())
1007382df5ce2f4b67bf0998b01c6fedcdb5c35ebef9Gilad Arnold    payload_gen.SetPartInfo(True, True, kernel_part_size,
10085502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                            hashlib.sha256('fake-new-kernel-content').digest())
10090d575cde18a1b44e386181dc1abbc611b9ae7a59Gilad Arnold    payload_gen.SetMinorVersion(0)
10105502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    payload_gen.AddOperationWithData(
10115502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold        False, common.OpType.REPLACE,
10125502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold        dst_extents=[(0, rootfs_part_size / block_size)],
10135502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold        data_blob=os.urandom(rootfs_part_size))
10145502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
10155502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    do_forge_pseudo_op = (fail_missing_pseudo_op or fail_mismatched_pseudo_op)
10165502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    do_forge_sigs_data = (do_forge_pseudo_op or fail_empty_sigs_blob or
10175502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                          fail_sig_missing_fields or fail_unknown_sig_version
10185502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                          or fail_incorrect_sig)
10195502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
10205502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    sigs_data = None
10215502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    if do_forge_sigs_data:
10225502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold      sigs_gen = test_utils.SignaturesGenerator()
10235502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold      if not fail_empty_sigs_blob:
10245502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold        if fail_sig_missing_fields:
10255502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold          sig_data = None
10265502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold        else:
10275502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold          sig_data = test_utils.SignSha256('fake-payload-content',
102818f4f9fab192e75a3477979c03a89381c35fd974Gilad Arnold                                           test_utils._PRIVKEY_FILE_NAME)
10295502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold        sigs_gen.AddSig(5 if fail_unknown_sig_version else 1, sig_data)
10305502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
10315502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold      sigs_data = sigs_gen.ToBinary()
10325502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold      payload_gen.SetSignatures(payload_gen.curr_offset, len(sigs_data))
10335502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
10345502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    if do_forge_pseudo_op:
10355502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold      assert sigs_data is not None, 'should have forged signatures blob by now'
10365502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold      sigs_len = len(sigs_data)
10375502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold      payload_gen.AddOperation(
10385502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold          False, common.OpType.REPLACE,
10395502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold          data_offset=payload_gen.curr_offset / 2,
10405502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold          data_length=sigs_len / 2,
10415502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold          dst_extents=[(0, (sigs_len / 2 + block_size - 1) / block_size)])
10425502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
10435502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    # Generate payload (complete w/ signature) and create the test object.
10445502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    payload_checker = _GetPayloadChecker(
1045eaed0d1371d781d3f5effa1475f5202dea9467e7Gilad Arnold        payload_gen.WriteToFileWithData,
1046eaed0d1371d781d3f5effa1475f5202dea9467e7Gilad Arnold        payload_gen_dargs={
1047eaed0d1371d781d3f5effa1475f5202dea9467e7Gilad Arnold            'sigs_data': sigs_data,
104818f4f9fab192e75a3477979c03a89381c35fd974Gilad Arnold            'privkey_file_name': test_utils._PRIVKEY_FILE_NAME,
1049eaed0d1371d781d3f5effa1475f5202dea9467e7Gilad Arnold            'do_add_pseudo_operation': not do_forge_pseudo_op})
10505502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    payload_checker.payload_type = checker._TYPE_FULL
10515502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    report = checker._PayloadReport()
10525502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
10535502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    # We have to check the manifest first in order to set signature attributes.
1054382df5ce2f4b67bf0998b01c6fedcdb5c35ebef9Gilad Arnold    payload_checker._CheckManifest(report, rootfs_part_size, kernel_part_size)
10555502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
10565502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    should_fail = (fail_empty_sigs_blob or fail_missing_pseudo_op or
10575502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                   fail_mismatched_pseudo_op or fail_sig_missing_fields or
10585502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                   fail_unknown_sig_version or fail_incorrect_sig)
1059cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold    args = (report, test_utils._PUBKEY_FILE_NAME)
10605502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    if should_fail:
10615502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold      self.assertRaises(update_payload.PayloadError,
1062cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold                        payload_checker._CheckSignatures, *args)
10635502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    else:
1064cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold      self.assertIsNone(payload_checker._CheckSignatures(*args))
10655502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
10660d575cde18a1b44e386181dc1abbc611b9ae7a59Gilad Arnold  def DoCheckManifestMinorVersionTest(self, minor_version, payload_type):
10670d575cde18a1b44e386181dc1abbc611b9ae7a59Gilad Arnold    """Parametric testing for CheckManifestMinorVersion().
1068f5c4f3e2a6e7c93e5b4c09272091f23a935fab86Allie Wood
1069f5c4f3e2a6e7c93e5b4c09272091f23a935fab86Allie Wood    Args:
1070f5c4f3e2a6e7c93e5b4c09272091f23a935fab86Allie Wood      minor_version: The payload minor version to test with.
1071f5c4f3e2a6e7c93e5b4c09272091f23a935fab86Allie Wood      payload_type: The type of the payload we're testing, delta or full.
1072f5c4f3e2a6e7c93e5b4c09272091f23a935fab86Allie Wood    """
1073f5c4f3e2a6e7c93e5b4c09272091f23a935fab86Allie Wood    # Create the test object.
10740d575cde18a1b44e386181dc1abbc611b9ae7a59Gilad Arnold    payload = self.MockPayload()
10750d575cde18a1b44e386181dc1abbc611b9ae7a59Gilad Arnold    payload.manifest.minor_version = minor_version
10760d575cde18a1b44e386181dc1abbc611b9ae7a59Gilad Arnold    payload_checker = checker.PayloadChecker(payload)
10770d575cde18a1b44e386181dc1abbc611b9ae7a59Gilad Arnold    payload_checker.payload_type = payload_type
1078f5c4f3e2a6e7c93e5b4c09272091f23a935fab86Allie Wood    report = checker._PayloadReport()
1079f5c4f3e2a6e7c93e5b4c09272091f23a935fab86Allie Wood
1080f5c4f3e2a6e7c93e5b4c09272091f23a935fab86Allie Wood    should_succeed = (
1081f5c4f3e2a6e7c93e5b4c09272091f23a935fab86Allie Wood        (minor_version == 0 and payload_type == checker._TYPE_FULL) or
1082f5c4f3e2a6e7c93e5b4c09272091f23a935fab86Allie Wood        (minor_version == 1 and payload_type == checker._TYPE_DELTA) or
1083912c4df6c4f470ddb6937b40cbe281229548783dSen Jiang        (minor_version == 2 and payload_type == checker._TYPE_DELTA) or
108492161a7b83c3a491871a167a4d46e4e6b6101e81Sen Jiang        (minor_version == 3 and payload_type == checker._TYPE_DELTA) or
108592161a7b83c3a491871a167a4d46e4e6b6101e81Sen Jiang        (minor_version == 4 and payload_type == checker._TYPE_DELTA))
10860d575cde18a1b44e386181dc1abbc611b9ae7a59Gilad Arnold    args = (report,)
1087f5c4f3e2a6e7c93e5b4c09272091f23a935fab86Allie Wood
1088f5c4f3e2a6e7c93e5b4c09272091f23a935fab86Allie Wood    if should_succeed:
10890d575cde18a1b44e386181dc1abbc611b9ae7a59Gilad Arnold      self.assertIsNone(payload_checker._CheckManifestMinorVersion(*args))
1090f5c4f3e2a6e7c93e5b4c09272091f23a935fab86Allie Wood    else:
1091f5c4f3e2a6e7c93e5b4c09272091f23a935fab86Allie Wood      self.assertRaises(update_payload.PayloadError,
10920d575cde18a1b44e386181dc1abbc611b9ae7a59Gilad Arnold                        payload_checker._CheckManifestMinorVersion, *args)
1093f5c4f3e2a6e7c93e5b4c09272091f23a935fab86Allie Wood
109406eea33088be4418264d12820f94c700977e3fa6Gilad Arnold  def DoRunTest(self, rootfs_part_size_provided, kernel_part_size_provided,
109506eea33088be4418264d12820f94c700977e3fa6Gilad Arnold                fail_wrong_payload_type, fail_invalid_block_size,
109606eea33088be4418264d12820f94c700977e3fa6Gilad Arnold                fail_mismatched_block_size, fail_excess_data,
109706eea33088be4418264d12820f94c700977e3fa6Gilad Arnold                fail_rootfs_part_size_exceeded,
109806eea33088be4418264d12820f94c700977e3fa6Gilad Arnold                fail_kernel_part_size_exceeded):
10995502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    # Generate a test payload. For this test, we generate a full update that
1100eaed0d1371d781d3f5effa1475f5202dea9467e7Gilad Arnold    # has sample kernel and rootfs operations. Since most testing is done with
11015502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    # internal PayloadChecker methods that are tested elsewhere, here we only
11025502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    # tamper with what's actually being manipulated and/or tested in the Run()
11035502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    # method itself. Note that the checker doesn't verify partition hashes, so
11045502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    # they're safe to fake.
11055502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    payload_gen = test_utils.EnhancedPayloadGenerator()
110618f4f9fab192e75a3477979c03a89381c35fd974Gilad Arnold    block_size = test_utils.KiB(4)
11075502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    payload_gen.SetBlockSize(block_size)
110806eea33088be4418264d12820f94c700977e3fa6Gilad Arnold    kernel_filesystem_size = test_utils.KiB(16)
110906eea33088be4418264d12820f94c700977e3fa6Gilad Arnold    rootfs_filesystem_size = test_utils.MiB(2)
111006eea33088be4418264d12820f94c700977e3fa6Gilad Arnold    payload_gen.SetPartInfo(False, True, rootfs_filesystem_size,
11115502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                            hashlib.sha256('fake-new-rootfs-content').digest())
111206eea33088be4418264d12820f94c700977e3fa6Gilad Arnold    payload_gen.SetPartInfo(True, True, kernel_filesystem_size,
11135502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                            hashlib.sha256('fake-new-kernel-content').digest())
11140d575cde18a1b44e386181dc1abbc611b9ae7a59Gilad Arnold    payload_gen.SetMinorVersion(0)
111506eea33088be4418264d12820f94c700977e3fa6Gilad Arnold
111606eea33088be4418264d12820f94c700977e3fa6Gilad Arnold    rootfs_part_size = 0
111706eea33088be4418264d12820f94c700977e3fa6Gilad Arnold    if rootfs_part_size_provided:
111806eea33088be4418264d12820f94c700977e3fa6Gilad Arnold      rootfs_part_size = rootfs_filesystem_size + block_size
111906eea33088be4418264d12820f94c700977e3fa6Gilad Arnold    rootfs_op_size = rootfs_part_size or rootfs_filesystem_size
112006eea33088be4418264d12820f94c700977e3fa6Gilad Arnold    if fail_rootfs_part_size_exceeded:
112106eea33088be4418264d12820f94c700977e3fa6Gilad Arnold      rootfs_op_size += block_size
11225502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    payload_gen.AddOperationWithData(
11235502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold        False, common.OpType.REPLACE,
112406eea33088be4418264d12820f94c700977e3fa6Gilad Arnold        dst_extents=[(0, rootfs_op_size / block_size)],
112506eea33088be4418264d12820f94c700977e3fa6Gilad Arnold        data_blob=os.urandom(rootfs_op_size))
112606eea33088be4418264d12820f94c700977e3fa6Gilad Arnold
112706eea33088be4418264d12820f94c700977e3fa6Gilad Arnold    kernel_part_size = 0
112806eea33088be4418264d12820f94c700977e3fa6Gilad Arnold    if kernel_part_size_provided:
112906eea33088be4418264d12820f94c700977e3fa6Gilad Arnold      kernel_part_size = kernel_filesystem_size + block_size
113006eea33088be4418264d12820f94c700977e3fa6Gilad Arnold    kernel_op_size = kernel_part_size or kernel_filesystem_size
113106eea33088be4418264d12820f94c700977e3fa6Gilad Arnold    if fail_kernel_part_size_exceeded:
113206eea33088be4418264d12820f94c700977e3fa6Gilad Arnold      kernel_op_size += block_size
11335502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    payload_gen.AddOperationWithData(
11345502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold        True, common.OpType.REPLACE,
113506eea33088be4418264d12820f94c700977e3fa6Gilad Arnold        dst_extents=[(0, kernel_op_size / block_size)],
113606eea33088be4418264d12820f94c700977e3fa6Gilad Arnold        data_blob=os.urandom(kernel_op_size))
11375502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
11385502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    # Generate payload (complete w/ signature) and create the test object.
11395502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    if fail_invalid_block_size:
1140cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold      use_block_size = block_size + 5  # Not a power of two.
11415502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    elif fail_mismatched_block_size:
1142cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold      use_block_size = block_size * 2  # Different that payload stated.
11435502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    else:
11445502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold      use_block_size = block_size
11455502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
1146cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold    kwargs = {
1147eaed0d1371d781d3f5effa1475f5202dea9467e7Gilad Arnold        'payload_gen_dargs': {
114818f4f9fab192e75a3477979c03a89381c35fd974Gilad Arnold            'privkey_file_name': test_utils._PRIVKEY_FILE_NAME,
1149eaed0d1371d781d3f5effa1475f5202dea9467e7Gilad Arnold            'do_add_pseudo_operation': True,
1150eaed0d1371d781d3f5effa1475f5202dea9467e7Gilad Arnold            'is_pseudo_in_kernel': True,
1151eaed0d1371d781d3f5effa1475f5202dea9467e7Gilad Arnold            'padding': os.urandom(1024) if fail_excess_data else None},
1152eaed0d1371d781d3f5effa1475f5202dea9467e7Gilad Arnold        'checker_init_dargs': {
1153eaed0d1371d781d3f5effa1475f5202dea9467e7Gilad Arnold            'assert_type': 'delta' if fail_wrong_payload_type else 'full',
1154eaed0d1371d781d3f5effa1475f5202dea9467e7Gilad Arnold            'block_size': use_block_size}}
1155eaed0d1371d781d3f5effa1475f5202dea9467e7Gilad Arnold    if fail_invalid_block_size:
1156eaed0d1371d781d3f5effa1475f5202dea9467e7Gilad Arnold      self.assertRaises(update_payload.PayloadError, _GetPayloadChecker,
1157cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold                        payload_gen.WriteToFileWithData, **kwargs)
11585502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    else:
1159eaed0d1371d781d3f5effa1475f5202dea9467e7Gilad Arnold      payload_checker = _GetPayloadChecker(payload_gen.WriteToFileWithData,
1160cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold                                           **kwargs)
116106eea33088be4418264d12820f94c700977e3fa6Gilad Arnold
116206eea33088be4418264d12820f94c700977e3fa6Gilad Arnold      kwargs = {'pubkey_file_name': test_utils._PUBKEY_FILE_NAME,
116306eea33088be4418264d12820f94c700977e3fa6Gilad Arnold                'rootfs_part_size': rootfs_part_size,
116406eea33088be4418264d12820f94c700977e3fa6Gilad Arnold                'kernel_part_size': kernel_part_size}
1165eaed0d1371d781d3f5effa1475f5202dea9467e7Gilad Arnold      should_fail = (fail_wrong_payload_type or fail_mismatched_block_size or
116606eea33088be4418264d12820f94c700977e3fa6Gilad Arnold                     fail_excess_data or
116706eea33088be4418264d12820f94c700977e3fa6Gilad Arnold                     fail_rootfs_part_size_exceeded or
116806eea33088be4418264d12820f94c700977e3fa6Gilad Arnold                     fail_kernel_part_size_exceeded)
1169eaed0d1371d781d3f5effa1475f5202dea9467e7Gilad Arnold      if should_fail:
1170cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold        self.assertRaises(update_payload.PayloadError, payload_checker.Run,
1171cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold                          **kwargs)
1172eaed0d1371d781d3f5effa1475f5202dea9467e7Gilad Arnold      else:
1173cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold        self.assertIsNone(payload_checker.Run(**kwargs))
11745502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
11755502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold# This implements a generic API, hence the occasional unused args.
11765502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold# pylint: disable=W0613
11775502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnolddef ValidateCheckOperationTest(op_type_name, is_last, allow_signature,
11785502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                               allow_unhashed, fail_src_extents,
11795502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                               fail_dst_extents,
11805502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                               fail_mismatched_data_offset_length,
11815502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                               fail_missing_dst_extents, fail_src_length,
11825502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                               fail_dst_length, fail_data_hash,
11837cf9f13f2715d0a033c6300a244b40302d8eb7b7Allie Wood                               fail_prev_data_offset, fail_bad_minor_version):
11845502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold  """Returns True iff the combination of arguments represents a valid test."""
11855502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold  op_type = _OpTypeByName(op_type_name)
11865502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
11877cf9f13f2715d0a033c6300a244b40302d8eb7b7Allie Wood  # REPLACE/REPLACE_BZ operations don't read data from src partition. They are
11887cf9f13f2715d0a033c6300a244b40302d8eb7b7Allie Wood  # compatible with all valid minor versions, so we don't need to check that.
11895502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold  if (op_type in (common.OpType.REPLACE, common.OpType.REPLACE_BZ) and (
11907cf9f13f2715d0a033c6300a244b40302d8eb7b7Allie Wood      fail_src_extents or fail_src_length or fail_bad_minor_version)):
11915502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    return False
11925502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
1193f5c4f3e2a6e7c93e5b4c09272091f23a935fab86Allie Wood  # MOVE and SOURCE_COPY operations don't carry data.
1194f5c4f3e2a6e7c93e5b4c09272091f23a935fab86Allie Wood  if (op_type in (common.OpType.MOVE, common.OpType.SOURCE_COPY) and (
11955502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold      fail_mismatched_data_offset_length or fail_data_hash or
11965502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold      fail_prev_data_offset)):
11975502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    return False
11985502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
11995502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold  return True
12005502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
12015502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
12025502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnolddef TestMethodBody(run_method_name, run_dargs):
12035502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold  """Returns a function that invokes a named method with named arguments."""
12045502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold  return lambda self: getattr(self, run_method_name)(**run_dargs)
12055502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
12065502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
12075502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnolddef AddParametricTests(tested_method_name, arg_space, validate_func=None):
12085502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold  """Enumerates and adds specific parametric tests to PayloadCheckerTest.
12095502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
12105502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold  This function enumerates a space of test parameters (defined by arg_space),
12115502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold  then binds a new, unique method name in PayloadCheckerTest to a test function
12125502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold  that gets handed the said parameters. This is a preferable approach to doing
12135502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold  the enumeration and invocation during the tests because this way each test is
12145502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold  treated as a complete run by the unittest framework, and so benefits from the
12155502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold  usual setUp/tearDown mechanics.
12165502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
12175502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold  Args:
1218cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold    tested_method_name: Name of the tested PayloadChecker method.
1219cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold    arg_space: A dictionary containing variables (keys) and lists of values
1220cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold               (values) associated with them.
1221cb638915dbc2e0898b0562c98019c077d7fc1e8aGilad Arnold    validate_func: A function used for validating test argument combinations.
12225502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold  """
12235502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold  for value_tuple in itertools.product(*arg_space.itervalues()):
12245502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    run_dargs = dict(zip(arg_space.iterkeys(), value_tuple))
12255502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    if validate_func and not validate_func(**run_dargs):
12265502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold      continue
12275502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    run_method_name = 'Do%sTest' % tested_method_name
12285502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    test_method_name = 'test%s' % tested_method_name
12295502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    for arg_key, arg_val in run_dargs.iteritems():
12305502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold      if arg_val or type(arg_val) is int:
12315502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold        test_method_name += '__%s=%s' % (arg_key, arg_val)
12325502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold    setattr(PayloadCheckerTest, test_method_name,
12335502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold            TestMethodBody(run_method_name, run_dargs))
12345502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
12355502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
12365502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnolddef AddAllParametricTests():
12375502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold  """Enumerates and adds all parametric tests to PayloadCheckerTest."""
12385502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold  # Add all _CheckElem() test cases.
12395502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold  AddParametricTests('AddElem',
12405502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                     {'linebreak': (True, False),
12415502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                      'indent': (0, 1, 2),
12425502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                      'convert': (str, lambda s: s[::-1]),
12435502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                      'is_present': (True, False),
12445502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                      'is_mandatory': (True, False),
12455502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                      'is_submsg': (True, False)})
12465502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
12475502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold  # Add all _Add{Mandatory,Optional}Field tests.
12485502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold  AddParametricTests('AddField',
12495502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                     {'is_mandatory': (True, False),
12505502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                      'linebreak': (True, False),
12515502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                      'indent': (0, 1, 2),
12525502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                      'convert': (str, lambda s: s[::-1]),
12535502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                      'is_present': (True, False)})
12545502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
12555502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold  # Add all _Add{Mandatory,Optional}SubMsg tests.
12565502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold  AddParametricTests('AddSubMsg',
12575502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                     {'is_mandatory': (True, False),
12585502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                      'is_present': (True, False)})
12595502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
12605502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold  # Add all _CheckManifest() test cases.
12615502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold  AddParametricTests('CheckManifest',
12625502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                     {'fail_mismatched_block_size': (True, False),
12635502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                      'fail_bad_sigs': (True, False),
12645502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                      'fail_mismatched_oki_ori': (True, False),
12655502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                      'fail_bad_oki': (True, False),
12665502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                      'fail_bad_ori': (True, False),
12675502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                      'fail_bad_nki': (True, False),
12685502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                      'fail_bad_nri': (True, False),
1269382df5ce2f4b67bf0998b01c6fedcdb5c35ebef9Gilad Arnold                      'fail_old_kernel_fs_size': (True, False),
1270382df5ce2f4b67bf0998b01c6fedcdb5c35ebef9Gilad Arnold                      'fail_old_rootfs_fs_size': (True, False),
1271382df5ce2f4b67bf0998b01c6fedcdb5c35ebef9Gilad Arnold                      'fail_new_kernel_fs_size': (True, False),
1272382df5ce2f4b67bf0998b01c6fedcdb5c35ebef9Gilad Arnold                      'fail_new_rootfs_fs_size': (True, False)})
12735502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
12745502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold  # Add all _CheckOperation() test cases.
12755502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold  AddParametricTests('CheckOperation',
12765502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                     {'op_type_name': ('REPLACE', 'REPLACE_BZ', 'MOVE',
1277f5c4f3e2a6e7c93e5b4c09272091f23a935fab86Allie Wood                                       'BSDIFF', 'SOURCE_COPY',
1278f5c4f3e2a6e7c93e5b4c09272091f23a935fab86Allie Wood                                       'SOURCE_BSDIFF'),
12795502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                      'is_last': (True, False),
12805502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                      'allow_signature': (True, False),
12815502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                      'allow_unhashed': (True, False),
12825502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                      'fail_src_extents': (True, False),
12835502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                      'fail_dst_extents': (True, False),
12845502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                      'fail_mismatched_data_offset_length': (True, False),
12855502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                      'fail_missing_dst_extents': (True, False),
12865502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                      'fail_src_length': (True, False),
12875502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                      'fail_dst_length': (True, False),
12885502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                      'fail_data_hash': (True, False),
12897cf9f13f2715d0a033c6300a244b40302d8eb7b7Allie Wood                      'fail_prev_data_offset': (True, False),
12907cf9f13f2715d0a033c6300a244b40302d8eb7b7Allie Wood                      'fail_bad_minor_version': (True, False)},
12915502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                     validate_func=ValidateCheckOperationTest)
12925502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
12935502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold  # Add all _CheckOperations() test cases.
12945502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold  AddParametricTests('CheckOperations',
1295fb04d30e433eed1d7e7b78114c1a747c89091362Allie Wood                     {'fail_nonexhaustive_full_update': (True, False)})
12965502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
12975502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold  # Add all _CheckOperations() test cases.
12985502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold  AddParametricTests('CheckSignatures',
12995502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                     {'fail_empty_sigs_blob': (True, False),
13005502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                      'fail_missing_pseudo_op': (True, False),
13015502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                      'fail_mismatched_pseudo_op': (True, False),
13025502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                      'fail_sig_missing_fields': (True, False),
13035502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                      'fail_unknown_sig_version': (True, False),
13045502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                      'fail_incorrect_sig': (True, False)})
13055502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
13060d575cde18a1b44e386181dc1abbc611b9ae7a59Gilad Arnold  # Add all _CheckManifestMinorVersion() test cases.
13070d575cde18a1b44e386181dc1abbc611b9ae7a59Gilad Arnold  AddParametricTests('CheckManifestMinorVersion',
130892161a7b83c3a491871a167a4d46e4e6b6101e81Sen Jiang                     {'minor_version': (None, 0, 1, 2, 3, 4, 555),
1309f5c4f3e2a6e7c93e5b4c09272091f23a935fab86Allie Wood                      'payload_type': (checker._TYPE_FULL,
1310f5c4f3e2a6e7c93e5b4c09272091f23a935fab86Allie Wood                                       checker._TYPE_DELTA)})
1311f5c4f3e2a6e7c93e5b4c09272091f23a935fab86Allie Wood
13125502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold  # Add all Run() test cases.
13135502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold  AddParametricTests('Run',
131406eea33088be4418264d12820f94c700977e3fa6Gilad Arnold                     {'rootfs_part_size_provided': (True, False),
131506eea33088be4418264d12820f94c700977e3fa6Gilad Arnold                      'kernel_part_size_provided': (True, False),
131606eea33088be4418264d12820f94c700977e3fa6Gilad Arnold                      'fail_wrong_payload_type': (True, False),
13175502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                      'fail_invalid_block_size': (True, False),
13185502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold                      'fail_mismatched_block_size': (True, False),
131906eea33088be4418264d12820f94c700977e3fa6Gilad Arnold                      'fail_excess_data': (True, False),
132006eea33088be4418264d12820f94c700977e3fa6Gilad Arnold                      'fail_rootfs_part_size_exceeded': (True, False),
132106eea33088be4418264d12820f94c700977e3fa6Gilad Arnold                      'fail_kernel_part_size_exceeded': (True, False)})
13225502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
13235502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold
13245502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnoldif __name__ == '__main__':
13255502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold  AddAllParametricTests()
13265502b56f34f9703cf053be46e4ea5685c0c9ac26Gilad Arnold  unittest.main()
1327