1#!/bin/bash 2# 3# A test suite for applypatch. Run in a client where you have done 4# envsetup, choosecombo, etc. 5# 6# DO NOT RUN THIS ON A DEVICE YOU CARE ABOUT. It will mess up your 7# system partition. 8# 9# 10# TODO: find some way to get this run regularly along with the rest of 11# the tests. 12 13EMULATOR_PORT=5580 14DATA_DIR=$ANDROID_BUILD_TOP/bootable/recovery/applypatch/testdata 15 16# This must be the filename that applypatch uses for its copies. 17CACHE_TEMP_SOURCE=/cache/saved.file 18 19# Put all binaries and files here. We use /cache because it's a 20# temporary filesystem in the emulator; it's created fresh each time 21# the emulator starts. 22WORK_DIR=/system 23 24# partition that WORK_DIR is located on, without the leading slash 25WORK_FS=system 26 27# set to 0 to use a device instead 28USE_EMULATOR=1 29 30# ------------------------ 31 32tmpdir=$(mktemp -d) 33 34if [ "$USE_EMULATOR" == 1 ]; then 35 emulator -wipe-data -noaudio -no-window -port $EMULATOR_PORT & 36 pid_emulator=$! 37 ADB="adb -s emulator-$EMULATOR_PORT " 38else 39 ADB="adb -d " 40fi 41 42echo "waiting to connect to device" 43$ADB wait-for-device 44echo "device is available" 45$ADB remount 46# free up enough space on the system partition for the test to run. 47$ADB shell rm -r /system/media 48 49# run a command on the device; exit with the exit status of the device 50# command. 51run_command() { 52 $ADB shell "$@" \; echo \$? | awk '{if (b) {print a}; a=$0; b=1} END {exit a}' 53} 54 55testname() { 56 echo 57 echo "$1"... 58 testname="$1" 59} 60 61fail() { 62 echo 63 echo FAIL: $testname 64 echo 65 [ "$open_pid" == "" ] || kill $open_pid 66 [ "$pid_emulator" == "" ] || kill $pid_emulator 67 exit 1 68} 69 70sha1() { 71 sha1sum $1 | awk '{print $1}' 72} 73 74free_space() { 75 run_command df | awk "/$1/ {print gensub(/K/, \"\", \"g\", \$6)}" 76} 77 78cleanup() { 79 # not necessary if we're about to kill the emulator, but nice for 80 # running on real devices or already-running emulators. 81 testname "removing test files" 82 run_command rm $WORK_DIR/bloat.dat 83 run_command rm $WORK_DIR/old.file 84 run_command rm $WORK_DIR/foo 85 run_command rm $WORK_DIR/patch.bsdiff 86 run_command rm $WORK_DIR/applypatch 87 run_command rm $CACHE_TEMP_SOURCE 88 run_command rm /cache/bloat*.dat 89 90 [ "$pid_emulator" == "" ] || kill $pid_emulator 91 92 if [ $# == 0 ]; then 93 rm -rf $tmpdir 94 fi 95} 96 97cleanup leave_tmp 98 99$ADB push $ANDROID_PRODUCT_OUT/system/bin/applypatch $WORK_DIR/applypatch 100 101BAD1_SHA1=$(printf "%040x" $RANDOM) 102BAD2_SHA1=$(printf "%040x" $RANDOM) 103OLD_SHA1=$(sha1 $DATA_DIR/old.file) 104NEW_SHA1=$(sha1 $DATA_DIR/new.file) 105NEW_SIZE=$(stat -c %s $DATA_DIR/new.file) 106 107# --------------- basic execution ---------------------- 108 109testname "usage message" 110run_command $WORK_DIR/applypatch && fail 111 112testname "display license" 113run_command $WORK_DIR/applypatch -l | grep -q -i copyright || fail 114 115 116# --------------- check mode ---------------------- 117 118$ADB push $DATA_DIR/old.file $WORK_DIR 119 120testname "check mode single" 121run_command $WORK_DIR/applypatch -c $WORK_DIR/old.file $OLD_SHA1 || fail 122 123testname "check mode multiple" 124run_command $WORK_DIR/applypatch -c $WORK_DIR/old.file $BAD1_SHA1 $OLD_SHA1 $BAD2_SHA1|| fail 125 126testname "check mode failure" 127run_command $WORK_DIR/applypatch -c $WORK_DIR/old.file $BAD2_SHA1 $BAD1_SHA1 && fail 128 129$ADB push $DATA_DIR/old.file $CACHE_TEMP_SOURCE 130# put some junk in the old file 131run_command dd if=/dev/urandom of=$WORK_DIR/old.file count=100 bs=1024 || fail 132 133testname "check mode cache (corrupted) single" 134run_command $WORK_DIR/applypatch -c $WORK_DIR/old.file $OLD_SHA1 || fail 135 136testname "check mode cache (corrupted) multiple" 137run_command $WORK_DIR/applypatch -c $WORK_DIR/old.file $BAD1_SHA1 $OLD_SHA1 $BAD2_SHA1|| fail 138 139testname "check mode cache (corrupted) failure" 140run_command $WORK_DIR/applypatch -c $WORK_DIR/old.file $BAD2_SHA1 $BAD1_SHA1 && fail 141 142# remove the old file entirely 143run_command rm $WORK_DIR/old.file 144 145testname "check mode cache (missing) single" 146run_command $WORK_DIR/applypatch -c $WORK_DIR/old.file $OLD_SHA1 || fail 147 148testname "check mode cache (missing) multiple" 149run_command $WORK_DIR/applypatch -c $WORK_DIR/old.file $BAD1_SHA1 $OLD_SHA1 $BAD2_SHA1|| fail 150 151testname "check mode cache (missing) failure" 152run_command $WORK_DIR/applypatch -c $WORK_DIR/old.file $BAD2_SHA1 $BAD1_SHA1 && fail 153 154 155# --------------- apply patch ---------------------- 156 157$ADB push $DATA_DIR/old.file $WORK_DIR 158$ADB push $DATA_DIR/patch.bsdiff $WORK_DIR 159echo hello > $tmpdir/foo 160$ADB push $tmpdir/foo $WORK_DIR 161 162# Check that the partition has enough space to apply the patch without 163# copying. If it doesn't, we'll be testing the low-space condition 164# when we intend to test the not-low-space condition. 165testname "apply patches (with enough space)" 166free_kb=$(free_space $WORK_FS) 167echo "${free_kb}kb free on /$WORK_FS." 168if (( free_kb * 1024 < NEW_SIZE * 3 / 2 )); then 169 echo "Not enough space on /$WORK_FS to patch test file." 170 echo 171 echo "This doesn't mean that applypatch is necessarily broken;" 172 echo "just that /$WORK_FS doesn't have enough free space to" 173 echo "properly run this test." 174 exit 1 175fi 176 177testname "apply bsdiff patch" 178run_command $WORK_DIR/applypatch $WORK_DIR/old.file - $NEW_SHA1 $NEW_SIZE $BAD1_SHA1:$WORK_DIR/foo $OLD_SHA1:$WORK_DIR/patch.bsdiff || fail 179$ADB pull $WORK_DIR/old.file $tmpdir/patched 180diff -q $DATA_DIR/new.file $tmpdir/patched || fail 181 182testname "reapply bsdiff patch" 183run_command $WORK_DIR/applypatch $WORK_DIR/old.file - $NEW_SHA1 $NEW_SIZE $BAD1_SHA1:$WORK_DIR/foo $OLD_SHA1:$WORK_DIR/patch.bsdiff || fail 184$ADB pull $WORK_DIR/old.file $tmpdir/patched 185diff -q $DATA_DIR/new.file $tmpdir/patched || fail 186 187 188# --------------- apply patch in new location ---------------------- 189 190$ADB push $DATA_DIR/old.file $WORK_DIR 191$ADB push $DATA_DIR/patch.bsdiff $WORK_DIR 192 193# Check that the partition has enough space to apply the patch without 194# copying. If it doesn't, we'll be testing the low-space condition 195# when we intend to test the not-low-space condition. 196testname "apply patch to new location (with enough space)" 197free_kb=$(free_space $WORK_FS) 198echo "${free_kb}kb free on /$WORK_FS." 199if (( free_kb * 1024 < NEW_SIZE * 3 / 2 )); then 200 echo "Not enough space on /$WORK_FS to patch test file." 201 echo 202 echo "This doesn't mean that applypatch is necessarily broken;" 203 echo "just that /$WORK_FS doesn't have enough free space to" 204 echo "properly run this test." 205 exit 1 206fi 207 208run_command rm $WORK_DIR/new.file 209run_command rm $CACHE_TEMP_SOURCE 210 211testname "apply bsdiff patch to new location" 212run_command $WORK_DIR/applypatch $WORK_DIR/old.file $WORK_DIR/new.file $NEW_SHA1 $NEW_SIZE $BAD1_SHA1:$WORK_DIR/foo $OLD_SHA1:$WORK_DIR/patch.bsdiff || fail 213$ADB pull $WORK_DIR/new.file $tmpdir/patched 214diff -q $DATA_DIR/new.file $tmpdir/patched || fail 215 216testname "reapply bsdiff patch to new location" 217run_command $WORK_DIR/applypatch $WORK_DIR/old.file $WORK_DIR/new.file $NEW_SHA1 $NEW_SIZE $BAD1_SHA1:$WORK_DIR/foo $OLD_SHA1:$WORK_DIR/patch.bsdiff || fail 218$ADB pull $WORK_DIR/new.file $tmpdir/patched 219diff -q $DATA_DIR/new.file $tmpdir/patched || fail 220 221$ADB push $DATA_DIR/old.file $CACHE_TEMP_SOURCE 222# put some junk in the old file 223run_command dd if=/dev/urandom of=$WORK_DIR/old.file count=100 bs=1024 || fail 224 225testname "apply bsdiff patch to new location with corrupted source" 226run_command $WORK_DIR/applypatch $WORK_DIR/old.file $WORK_DIR/new.file $NEW_SHA1 $NEW_SIZE $OLD_SHA1:$WORK_DIR/patch.bsdiff $BAD1_SHA1:$WORK_DIR/foo || fail 227$ADB pull $WORK_DIR/new.file $tmpdir/patched 228diff -q $DATA_DIR/new.file $tmpdir/patched || fail 229 230# put some junk in the cache copy, too 231run_command dd if=/dev/urandom of=$CACHE_TEMP_SOURCE count=100 bs=1024 || fail 232 233run_command rm $WORK_DIR/new.file 234testname "apply bsdiff patch to new location with corrupted source and copy (no new file)" 235run_command $WORK_DIR/applypatch $WORK_DIR/old.file $WORK_DIR/new.file $NEW_SHA1 $NEW_SIZE $OLD_SHA1:$WORK_DIR/patch.bsdiff $BAD1_SHA1:$WORK_DIR/foo && fail 236 237# put some junk in the new file 238run_command dd if=/dev/urandom of=$WORK_DIR/new.file count=100 bs=1024 || fail 239 240testname "apply bsdiff patch to new location with corrupted source and copy (bad new file)" 241run_command $WORK_DIR/applypatch $WORK_DIR/old.file $WORK_DIR/new.file $NEW_SHA1 $NEW_SIZE $OLD_SHA1:$WORK_DIR/patch.bsdiff $BAD1_SHA1:$WORK_DIR/foo && fail 242 243# --------------- apply patch with low space on /system ---------------------- 244 245$ADB push $DATA_DIR/old.file $WORK_DIR 246$ADB push $DATA_DIR/patch.bsdiff $WORK_DIR 247 248free_kb=$(free_space $WORK_FS) 249echo "${free_kb}kb free on /$WORK_FS; we'll soon fix that." 250echo run_command dd if=/dev/zero of=$WORK_DIR/bloat.dat count=$((free_kb-512)) bs=1024 || fail 251run_command dd if=/dev/zero of=$WORK_DIR/bloat.dat count=$((free_kb-512)) bs=1024 || fail 252free_kb=$(free_space $WORK_FS) 253echo "${free_kb}kb free on /$WORK_FS now." 254 255testname "apply bsdiff patch with low space" 256run_command $WORK_DIR/applypatch $WORK_DIR/old.file - $NEW_SHA1 $NEW_SIZE $BAD1_SHA1:$WORK_DIR/foo $OLD_SHA1:$WORK_DIR/patch.bsdiff || fail 257$ADB pull $WORK_DIR/old.file $tmpdir/patched 258diff -q $DATA_DIR/new.file $tmpdir/patched || fail 259 260testname "reapply bsdiff patch with low space" 261run_command $WORK_DIR/applypatch $WORK_DIR/old.file - $NEW_SHA1 $NEW_SIZE $BAD1_SHA1:$WORK_DIR/foo $OLD_SHA1:$WORK_DIR/patch.bsdiff || fail 262$ADB pull $WORK_DIR/old.file $tmpdir/patched 263diff -q $DATA_DIR/new.file $tmpdir/patched || fail 264 265# --------------- apply patch with low space on /system and /cache ---------------------- 266 267$ADB push $DATA_DIR/old.file $WORK_DIR 268$ADB push $DATA_DIR/patch.bsdiff $WORK_DIR 269 270free_kb=$(free_space $WORK_FS) 271echo "${free_kb}kb free on /$WORK_FS" 272 273run_command mkdir /cache/subdir 274run_command 'echo > /cache/subdir/a.file' 275run_command 'echo > /cache/a.file' 276run_command mkdir /cache/recovery /cache/recovery/otatest 277run_command 'echo > /cache/recovery/otatest/b.file' 278run_command "echo > $CACHE_TEMP_SOURCE" 279free_kb=$(free_space cache) 280echo "${free_kb}kb free on /cache; we'll soon fix that." 281run_command dd if=/dev/zero of=/cache/bloat_small.dat count=128 bs=1024 || fail 282run_command dd if=/dev/zero of=/cache/bloat_large.dat count=$((free_kb-640)) bs=1024 || fail 283free_kb=$(free_space cache) 284echo "${free_kb}kb free on /cache now." 285 286testname "apply bsdiff patch with low space, full cache, can't delete enough" 287$ADB shell 'cat >> /cache/bloat_large.dat' & open_pid=$! 288echo "open_pid is $open_pid" 289 290# size check should fail even though it deletes some stuff 291run_command $WORK_DIR/applypatch -s $NEW_SIZE && fail 292run_command ls /cache/bloat_small.dat && fail # was deleted 293run_command ls /cache/a.file && fail # was deleted 294run_command ls /cache/recovery/otatest/b.file && fail # was deleted 295run_command ls /cache/bloat_large.dat || fail # wasn't deleted because it was open 296run_command ls /cache/subdir/a.file || fail # wasn't deleted because it's in a subdir 297run_command ls $CACHE_TEMP_SOURCE || fail # wasn't deleted because it's the source file copy 298 299# should fail; not enough files can be deleted 300run_command $WORK_DIR/applypatch $WORK_DIR/old.file - $NEW_SHA1 $NEW_SIZE $BAD1_SHA1:$WORK_DIR/foo $OLD_SHA1:$WORK_DIR/patch.bsdiff && fail 301run_command ls /cache/bloat_large.dat || fail # wasn't deleted because it was open 302run_command ls /cache/subdir/a.file || fail # wasn't deleted because it's in a subdir 303run_command ls $CACHE_TEMP_SOURCE || fail # wasn't deleted because it's the source file copy 304 305kill $open_pid # /cache/bloat_large.dat is no longer open 306 307testname "apply bsdiff patch with low space, full cache, can delete enough" 308 309# should succeed after deleting /cache/bloat_large.dat 310run_command $WORK_DIR/applypatch -s $NEW_SIZE || fail 311run_command ls /cache/bloat_large.dat && fail # was deleted 312run_command ls /cache/subdir/a.file || fail # still wasn't deleted because it's in a subdir 313run_command ls $CACHE_TEMP_SOURCE || fail # wasn't deleted because it's the source file copy 314 315# should succeed 316run_command $WORK_DIR/applypatch $WORK_DIR/old.file - $NEW_SHA1 $NEW_SIZE $BAD1_SHA1:$WORK_DIR/foo $OLD_SHA1:$WORK_DIR/patch.bsdiff || fail 317$ADB pull $WORK_DIR/old.file $tmpdir/patched 318diff -q $DATA_DIR/new.file $tmpdir/patched || fail 319run_command ls /cache/subdir/a.file || fail # still wasn't deleted because it's in a subdir 320run_command ls $CACHE_TEMP_SOURCE && fail # was deleted because patching overwrote it, then deleted it 321 322# --------------- apply patch from cache ---------------------- 323 324$ADB push $DATA_DIR/old.file $CACHE_TEMP_SOURCE 325# put some junk in the old file 326run_command dd if=/dev/urandom of=$WORK_DIR/old.file count=100 bs=1024 || fail 327 328testname "apply bsdiff patch from cache (corrupted source) with low space" 329run_command $WORK_DIR/applypatch $WORK_DIR/old.file - $NEW_SHA1 $NEW_SIZE $BAD1_SHA1:$WORK_DIR/foo $OLD_SHA1:$WORK_DIR/patch.bsdiff || fail 330$ADB pull $WORK_DIR/old.file $tmpdir/patched 331diff -q $DATA_DIR/new.file $tmpdir/patched || fail 332 333$ADB push $DATA_DIR/old.file $CACHE_TEMP_SOURCE 334# remove the old file entirely 335run_command rm $WORK_DIR/old.file 336 337testname "apply bsdiff patch from cache (missing source) with low space" 338run_command $WORK_DIR/applypatch $WORK_DIR/old.file - $NEW_SHA1 $NEW_SIZE $BAD1_SHA1:$WORK_DIR/foo $OLD_SHA1:$WORK_DIR/patch.bsdiff || fail 339$ADB pull $WORK_DIR/old.file $tmpdir/patched 340diff -q $DATA_DIR/new.file $tmpdir/patched || fail 341 342 343# --------------- cleanup ---------------------- 344 345cleanup 346 347echo 348echo PASS 349echo 350 351