Home | History | Annotate | Download | only in scripts
      1 #!/bin/bash
      2 #
      3 # Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
      4 # Use of this source code is governed by a BSD-style license that can be
      5 # found in the LICENSE file.
      6 
      7 # A test script for paycheck.py and the update_payload.py library.
      8 #
      9 # This script requires three payload files, along with a metadata signature for
     10 # each, and a public key for verifying signatures. Payload include:
     11 #
     12 # - A full payload for release X (old_full_payload)
     13 #
     14 # - A full payload for release Y (new_full_payload), where Y > X
     15 #
     16 # - A delta payload from X to Y (delta_payload)
     17 #
     18 # The test performs the following:
     19 #
     20 # - It verifies each payload against its metadata signature, also asserting the
     21 #   payload type. Another artifact is a human-readable payload report, which
     22 #   is output to stdout to be inspected by the user.
     23 #
     24 # - It performs a random block trace on the delta payload (both kernel and
     25 #   rootfs blocks), dumping the traces to stdout for the user to inspect.
     26 #
     27 # - It applies old_full_payload to yield old kernel (old_kern.part) and rootfs
     28 #   (old_root.part) partitions.
     29 #
     30 # - It applies delta_payload to old_{kern,root}.part to yield new kernel
     31 #   (new_delta_kern.part) and rootfs (new_delta_root.part) partitions.
     32 #
     33 # - It applies new_full_payload to yield reference new kernel
     34 #   (new_full_kern.part) and rootfs (new_full_root.part) partitions.
     35 #
     36 # - It compares new_{delta,full}_kern.part and new_{delta,full}_root.part to
     37 #   ensure that they are binary identical.
     38 #
     39 # If all steps have completed successfully we know with high certainty that
     40 # paycheck.py (and hence update_payload.py) correctly parses both full and
     41 # delta payloads, and applies them to yield the expected result. We also know
     42 # that tracing works, to the extent it does not crash. Manual inspection of
     43 # payload reports and block traces will improve this our confidence and are
     44 # strongly encouraged. Finally, each paycheck.py execution is timed.
     45 
     46 
     47 # Stop on errors, unset variables.
     48 set -e
     49 set -u
     50 
     51 # Temporary image files.
     52 OLD_KERN_PART=old_kern.part
     53 OLD_ROOT_PART=old_root.part
     54 NEW_DELTA_KERN_PART=new_delta_kern.part
     55 NEW_DELTA_ROOT_PART=new_delta_root.part
     56 NEW_FULL_KERN_PART=new_full_kern.part
     57 NEW_FULL_ROOT_PART=new_full_root.part
     58 
     59 
     60 log() {
     61   echo "$@" >&2
     62 }
     63 
     64 die() {
     65   log "$@"
     66   exit 1
     67 }
     68 
     69 usage_and_exit() {
     70   cat >&2 <<EOF
     71 Usage: ${0##*/} old_full_payload delta_payload new_full_payload
     72 EOF
     73   exit
     74 }
     75 
     76 check_payload() {
     77   payload_file=$1
     78   payload_type=$2
     79 
     80   time ${paycheck} -t ${payload_type} ${payload_file}
     81 }
     82 
     83 trace_kern_block() {
     84   payload_file=$1
     85   block=$2
     86   time ${paycheck} -B ${block} ${payload_file}
     87 }
     88 
     89 trace_root_block() {
     90   payload_file=$1
     91   block=$2
     92   time ${paycheck} -b ${block} ${payload_file}
     93 }
     94 
     95 apply_full_payload() {
     96   payload_file=$1
     97   dst_kern_part="$2/$3"
     98   dst_root_part="$2/$4"
     99 
    100   time ${paycheck} ${payload_file} ${dst_kern_part} ${dst_root_part}
    101 }
    102 
    103 apply_delta_payload() {
    104   payload_file=$1
    105   dst_kern_part="$2/$3"
    106   dst_root_part="$2/$4"
    107   src_kern_part="$2/$5"
    108   src_root_part="$2/$6"
    109 
    110   time ${paycheck} ${payload_file} ${dst_kern_part} ${dst_root_part} \
    111     ${src_kern_part} ${src_root_part}
    112 }
    113 
    114 main() {
    115   # Read command-line arguments.
    116   if [ $# == 1 ] && [ "$1" == "-h" ]; then
    117     usage_and_exit
    118   elif [ $# != 3 ]; then
    119     die "Error: unexpected number of arguments"
    120   fi
    121   old_full_payload="$1"
    122   delta_payload="$2"
    123   new_full_payload="$3"
    124 
    125   # Find paycheck.py
    126   paycheck=${0%/*}/paycheck.py
    127   if [ -z "${paycheck}" ] || [ ! -x ${paycheck} ]; then
    128     die "cannot find ${paycheck} or file is not executable"
    129   fi
    130 
    131   # Check the payloads statically.
    132   log "Checking payloads..."
    133   check_payload "${old_full_payload}" full
    134   check_payload "${new_full_payload}" full
    135   check_payload "${delta_payload}" delta
    136   log "Done"
    137 
    138   # Trace a random block between 0-1024 on all payloads.
    139   block=$((RANDOM * 1024 / 32767))
    140   log "Tracing a random block (${block}) in full/delta payloads..."
    141   trace_kern_block "${new_full_payload}" ${block}
    142   trace_root_block "${new_full_payload}" ${block}
    143   trace_kern_block "${delta_payload}" ${block}
    144   trace_root_block "${delta_payload}" ${block}
    145   log "Done"
    146 
    147   # Apply full/delta payloads and verify results are identical.
    148   tmpdir="$(mktemp -d --tmpdir test_paycheck.XXXXXXXX)"
    149   log "Initiating application of payloads at $tmpdir"
    150 
    151   log "Applying old full payload..."
    152   apply_full_payload "${old_full_payload}" "${tmpdir}" "${OLD_KERN_PART}" \
    153     "${OLD_ROOT_PART}"
    154   log "Done"
    155 
    156   log "Applying delta payload to old partitions..."
    157   apply_delta_payload "${delta_payload}" "${tmpdir}" "${NEW_DELTA_KERN_PART}" \
    158     "${NEW_DELTA_ROOT_PART}" "${OLD_KERN_PART}" "${OLD_ROOT_PART}"
    159   log "Done"
    160 
    161   log "Applying new full payload..."
    162   apply_full_payload "${new_full_payload}" "${tmpdir}" "${NEW_FULL_KERN_PART}" \
    163     "${NEW_FULL_ROOT_PART}"
    164   log "Done"
    165 
    166   log "Comparing results of delta and new full updates..."
    167   diff "${tmpdir}/${NEW_FULL_KERN_PART}" "${tmpdir}/${NEW_DELTA_KERN_PART}"
    168   diff "${tmpdir}/${NEW_FULL_ROOT_PART}" "${tmpdir}/${NEW_DELTA_ROOT_PART}"
    169   log "Done"
    170 
    171   log "Cleaning up"
    172   rm -fr "${tmpdir}"
    173 }
    174 
    175 main "$@"
    176