#!/bin/bash # # Copyright (c) 2013 The Chromium OS Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. # A test script for paycheck.py and the update_payload.py library. # # This script requires three payload files, along with a metadata signature for # each, and a public key for verifying signatures. Payload include: # # - A full payload for release X (old_full_payload) # # - A full payload for release Y (new_full_payload), where Y > X # # - A delta payload from X to Y (delta_payload) # # The test performs the following: # # - It verifies each payload against its metadata signature, also asserting the # payload type. Another artifact is a human-readable payload report, which # is output to stdout to be inspected by the user. # # - It performs a random block trace on the delta payload (both kernel and # rootfs blocks), dumping the traces to stdout for the user to inspect. # # - It applies old_full_payload to yield old kernel (old_kern.part) and rootfs # (old_root.part) partitions. # # - It applies delta_payload to old_{kern,root}.part to yield new kernel # (new_delta_kern.part) and rootfs (new_delta_root.part) partitions. # # - It applies new_full_payload to yield reference new kernel # (new_full_kern.part) and rootfs (new_full_root.part) partitions. # # - It compares new_{delta,full}_kern.part and new_{delta,full}_root.part to # ensure that they are binary identical. # # If all steps have completed successfully we know with high certainty that # paycheck.py (and hence update_payload.py) correctly parses both full and # delta payloads, and applies them to yield the expected result. We also know # that tracing works, to the extent it does not crash. Manual inspection of # payload reports and block traces will improve this our confidence and are # strongly encouraged. Finally, each paycheck.py execution is timed. # Stop on errors, unset variables. set -e set -u # Temporary image files. OLD_KERN_PART=old_kern.part OLD_ROOT_PART=old_root.part NEW_DELTA_KERN_PART=new_delta_kern.part NEW_DELTA_ROOT_PART=new_delta_root.part NEW_FULL_KERN_PART=new_full_kern.part NEW_FULL_ROOT_PART=new_full_root.part log() { echo "$@" >&2 } die() { log "$@" exit 1 } usage_and_exit() { cat >&2 <<EOF Usage: ${0##*/} old_full_payload delta_payload new_full_payload EOF exit } check_payload() { payload_file=$1 payload_type=$2 time ${paycheck} -t ${payload_type} ${payload_file} } trace_kern_block() { payload_file=$1 block=$2 time ${paycheck} -B ${block} ${payload_file} } trace_root_block() { payload_file=$1 block=$2 time ${paycheck} -b ${block} ${payload_file} } apply_full_payload() { payload_file=$1 dst_kern_part="$2/$3" dst_root_part="$2/$4" time ${paycheck} ${payload_file} ${dst_kern_part} ${dst_root_part} } apply_delta_payload() { payload_file=$1 dst_kern_part="$2/$3" dst_root_part="$2/$4" src_kern_part="$2/$5" src_root_part="$2/$6" time ${paycheck} ${payload_file} ${dst_kern_part} ${dst_root_part} \ ${src_kern_part} ${src_root_part} } main() { # Read command-line arguments. if [ $# == 1 ] && [ "$1" == "-h" ]; then usage_and_exit elif [ $# != 3 ]; then die "Error: unexpected number of arguments" fi old_full_payload="$1" delta_payload="$2" new_full_payload="$3" # Find paycheck.py paycheck=${0%/*}/paycheck.py if [ -z "${paycheck}" ] || [ ! -x ${paycheck} ]; then die "cannot find ${paycheck} or file is not executable" fi # Check the payloads statically. log "Checking payloads..." check_payload "${old_full_payload}" full check_payload "${new_full_payload}" full check_payload "${delta_payload}" delta log "Done" # Trace a random block between 0-1024 on all payloads. block=$((RANDOM * 1024 / 32767)) log "Tracing a random block (${block}) in full/delta payloads..." trace_kern_block "${new_full_payload}" ${block} trace_root_block "${new_full_payload}" ${block} trace_kern_block "${delta_payload}" ${block} trace_root_block "${delta_payload}" ${block} log "Done" # Apply full/delta payloads and verify results are identical. tmpdir="$(mktemp -d --tmpdir test_paycheck.XXXXXXXX)" log "Initiating application of payloads at $tmpdir" log "Applying old full payload..." apply_full_payload "${old_full_payload}" "${tmpdir}" "${OLD_KERN_PART}" \ "${OLD_ROOT_PART}" log "Done" log "Applying delta payload to old partitions..." apply_delta_payload "${delta_payload}" "${tmpdir}" "${NEW_DELTA_KERN_PART}" \ "${NEW_DELTA_ROOT_PART}" "${OLD_KERN_PART}" "${OLD_ROOT_PART}" log "Done" log "Applying new full payload..." apply_full_payload "${new_full_payload}" "${tmpdir}" "${NEW_FULL_KERN_PART}" \ "${NEW_FULL_ROOT_PART}" log "Done" log "Comparing results of delta and new full updates..." diff "${tmpdir}/${NEW_FULL_KERN_PART}" "${tmpdir}/${NEW_DELTA_KERN_PART}" diff "${tmpdir}/${NEW_FULL_ROOT_PART}" "${tmpdir}/${NEW_DELTA_ROOT_PART}" log "Done" log "Cleaning up" rm -fr "${tmpdir}" } main "$@"