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