| #!/bin/bash |
| # |
| # A test suite for applypatch. Run in a client where you have done |
| # envsetup, choosecombo, etc. |
| # |
| # DO NOT RUN THIS ON A DEVICE YOU CARE ABOUT. It will mess up your |
| # system partition. |
| # |
| # |
| # TODO: find some way to get this run regularly along with the rest of |
| # the tests. |
| |
| EMULATOR_PORT=5580 |
| DATA_DIR=$ANDROID_BUILD_TOP/bootable/recovery/applypatch/testdata |
| |
| # This must be the filename that applypatch uses for its copies. |
| CACHE_TEMP_SOURCE=/cache/saved.file |
| |
| # Put all binaries and files here. We use /cache because it's a |
| # temporary filesystem in the emulator; it's created fresh each time |
| # the emulator starts. |
| WORK_DIR=/system |
| |
| # partition that WORK_DIR is located on, without the leading slash |
| WORK_FS=system |
| |
| # set to 0 to use a device instead |
| USE_EMULATOR=1 |
| |
| # ------------------------ |
| |
| tmpdir=$(mktemp -d) |
| |
| if [ "$USE_EMULATOR" == 1 ]; then |
| emulator -wipe-data -noaudio -no-window -port $EMULATOR_PORT & |
| pid_emulator=$! |
| ADB="adb -s emulator-$EMULATOR_PORT " |
| else |
| ADB="adb -d " |
| fi |
| |
| echo "waiting to connect to device" |
| $ADB wait-for-device |
| echo "device is available" |
| $ADB remount |
| # free up enough space on the system partition for the test to run. |
| $ADB shell rm -r /system/media |
| |
| # run a command on the device; exit with the exit status of the device |
| # command. |
| run_command() { |
| $ADB shell "$@" \; echo \$? | awk '{if (b) {print a}; a=$0; b=1} END {exit a}' |
| } |
| |
| testname() { |
| echo |
| echo "$1"... |
| testname="$1" |
| } |
| |
| fail() { |
| echo |
| echo FAIL: $testname |
| echo |
| [ "$open_pid" == "" ] || kill $open_pid |
| [ "$pid_emulator" == "" ] || kill $pid_emulator |
| exit 1 |
| } |
| |
| sha1() { |
| sha1sum $1 | awk '{print $1}' |
| } |
| |
| free_space() { |
| run_command df | awk "/$1/ {print gensub(/K/, \"\", \"g\", \$6)}" |
| } |
| |
| cleanup() { |
| # not necessary if we're about to kill the emulator, but nice for |
| # running on real devices or already-running emulators. |
| testname "removing test files" |
| run_command rm $WORK_DIR/bloat.dat |
| run_command rm $WORK_DIR/old.file |
| run_command rm $WORK_DIR/foo |
| run_command rm $WORK_DIR/patch.bsdiff |
| run_command rm $WORK_DIR/applypatch |
| run_command rm $CACHE_TEMP_SOURCE |
| run_command rm /cache/bloat*.dat |
| |
| [ "$pid_emulator" == "" ] || kill $pid_emulator |
| |
| if [ $# == 0 ]; then |
| rm -rf $tmpdir |
| fi |
| } |
| |
| cleanup leave_tmp |
| |
| $ADB push $ANDROID_PRODUCT_OUT/system/bin/applypatch $WORK_DIR/applypatch |
| |
| BAD1_SHA1=$(printf "%040x" $RANDOM) |
| BAD2_SHA1=$(printf "%040x" $RANDOM) |
| OLD_SHA1=$(sha1 $DATA_DIR/old.file) |
| NEW_SHA1=$(sha1 $DATA_DIR/new.file) |
| NEW_SIZE=$(stat -c %s $DATA_DIR/new.file) |
| |
| # --------------- basic execution ---------------------- |
| |
| testname "usage message" |
| run_command $WORK_DIR/applypatch && fail |
| |
| testname "display license" |
| run_command $WORK_DIR/applypatch -l | grep -q -i copyright || fail |
| |
| |
| # --------------- check mode ---------------------- |
| |
| $ADB push $DATA_DIR/old.file $WORK_DIR |
| |
| testname "check mode single" |
| run_command $WORK_DIR/applypatch -c $WORK_DIR/old.file $OLD_SHA1 || fail |
| |
| testname "check mode multiple" |
| run_command $WORK_DIR/applypatch -c $WORK_DIR/old.file $BAD1_SHA1 $OLD_SHA1 $BAD2_SHA1|| fail |
| |
| testname "check mode failure" |
| run_command $WORK_DIR/applypatch -c $WORK_DIR/old.file $BAD2_SHA1 $BAD1_SHA1 && fail |
| |
| $ADB push $DATA_DIR/old.file $CACHE_TEMP_SOURCE |
| # put some junk in the old file |
| run_command dd if=/dev/urandom of=$WORK_DIR/old.file count=100 bs=1024 || fail |
| |
| testname "check mode cache (corrupted) single" |
| run_command $WORK_DIR/applypatch -c $WORK_DIR/old.file $OLD_SHA1 || fail |
| |
| testname "check mode cache (corrupted) multiple" |
| run_command $WORK_DIR/applypatch -c $WORK_DIR/old.file $BAD1_SHA1 $OLD_SHA1 $BAD2_SHA1|| fail |
| |
| testname "check mode cache (corrupted) failure" |
| run_command $WORK_DIR/applypatch -c $WORK_DIR/old.file $BAD2_SHA1 $BAD1_SHA1 && fail |
| |
| # remove the old file entirely |
| run_command rm $WORK_DIR/old.file |
| |
| testname "check mode cache (missing) single" |
| run_command $WORK_DIR/applypatch -c $WORK_DIR/old.file $OLD_SHA1 || fail |
| |
| testname "check mode cache (missing) multiple" |
| run_command $WORK_DIR/applypatch -c $WORK_DIR/old.file $BAD1_SHA1 $OLD_SHA1 $BAD2_SHA1|| fail |
| |
| testname "check mode cache (missing) failure" |
| run_command $WORK_DIR/applypatch -c $WORK_DIR/old.file $BAD2_SHA1 $BAD1_SHA1 && fail |
| |
| |
| # --------------- apply patch ---------------------- |
| |
| $ADB push $DATA_DIR/old.file $WORK_DIR |
| $ADB push $DATA_DIR/patch.bsdiff $WORK_DIR |
| echo hello > $tmpdir/foo |
| $ADB push $tmpdir/foo $WORK_DIR |
| |
| # Check that the partition has enough space to apply the patch without |
| # copying. If it doesn't, we'll be testing the low-space condition |
| # when we intend to test the not-low-space condition. |
| testname "apply patches (with enough space)" |
| free_kb=$(free_space $WORK_FS) |
| echo "${free_kb}kb free on /$WORK_FS." |
| if (( free_kb * 1024 < NEW_SIZE * 3 / 2 )); then |
| echo "Not enough space on /$WORK_FS to patch test file." |
| echo |
| echo "This doesn't mean that applypatch is necessarily broken;" |
| echo "just that /$WORK_FS doesn't have enough free space to" |
| echo "properly run this test." |
| exit 1 |
| fi |
| |
| testname "apply bsdiff patch" |
| run_command $WORK_DIR/applypatch $WORK_DIR/old.file - $NEW_SHA1 $NEW_SIZE $BAD1_SHA1:$WORK_DIR/foo $OLD_SHA1:$WORK_DIR/patch.bsdiff || fail |
| $ADB pull $WORK_DIR/old.file $tmpdir/patched |
| diff -q $DATA_DIR/new.file $tmpdir/patched || fail |
| |
| testname "reapply bsdiff patch" |
| run_command $WORK_DIR/applypatch $WORK_DIR/old.file - $NEW_SHA1 $NEW_SIZE $BAD1_SHA1:$WORK_DIR/foo $OLD_SHA1:$WORK_DIR/patch.bsdiff || fail |
| $ADB pull $WORK_DIR/old.file $tmpdir/patched |
| diff -q $DATA_DIR/new.file $tmpdir/patched || fail |
| |
| |
| # --------------- apply patch in new location ---------------------- |
| |
| $ADB push $DATA_DIR/old.file $WORK_DIR |
| $ADB push $DATA_DIR/patch.bsdiff $WORK_DIR |
| |
| # Check that the partition has enough space to apply the patch without |
| # copying. If it doesn't, we'll be testing the low-space condition |
| # when we intend to test the not-low-space condition. |
| testname "apply patch to new location (with enough space)" |
| free_kb=$(free_space $WORK_FS) |
| echo "${free_kb}kb free on /$WORK_FS." |
| if (( free_kb * 1024 < NEW_SIZE * 3 / 2 )); then |
| echo "Not enough space on /$WORK_FS to patch test file." |
| echo |
| echo "This doesn't mean that applypatch is necessarily broken;" |
| echo "just that /$WORK_FS doesn't have enough free space to" |
| echo "properly run this test." |
| exit 1 |
| fi |
| |
| run_command rm $WORK_DIR/new.file |
| run_command rm $CACHE_TEMP_SOURCE |
| |
| testname "apply bsdiff patch to new location" |
| run_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 |
| $ADB pull $WORK_DIR/new.file $tmpdir/patched |
| diff -q $DATA_DIR/new.file $tmpdir/patched || fail |
| |
| testname "reapply bsdiff patch to new location" |
| run_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 |
| $ADB pull $WORK_DIR/new.file $tmpdir/patched |
| diff -q $DATA_DIR/new.file $tmpdir/patched || fail |
| |
| $ADB push $DATA_DIR/old.file $CACHE_TEMP_SOURCE |
| # put some junk in the old file |
| run_command dd if=/dev/urandom of=$WORK_DIR/old.file count=100 bs=1024 || fail |
| |
| testname "apply bsdiff patch to new location with corrupted source" |
| run_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 |
| $ADB pull $WORK_DIR/new.file $tmpdir/patched |
| diff -q $DATA_DIR/new.file $tmpdir/patched || fail |
| |
| # put some junk in the cache copy, too |
| run_command dd if=/dev/urandom of=$CACHE_TEMP_SOURCE count=100 bs=1024 || fail |
| |
| run_command rm $WORK_DIR/new.file |
| testname "apply bsdiff patch to new location with corrupted source and copy (no new file)" |
| run_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 |
| |
| # put some junk in the new file |
| run_command dd if=/dev/urandom of=$WORK_DIR/new.file count=100 bs=1024 || fail |
| |
| testname "apply bsdiff patch to new location with corrupted source and copy (bad new file)" |
| run_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 |
| |
| # --------------- apply patch with low space on /system ---------------------- |
| |
| $ADB push $DATA_DIR/old.file $WORK_DIR |
| $ADB push $DATA_DIR/patch.bsdiff $WORK_DIR |
| |
| free_kb=$(free_space $WORK_FS) |
| echo "${free_kb}kb free on /$WORK_FS; we'll soon fix that." |
| echo run_command dd if=/dev/zero of=$WORK_DIR/bloat.dat count=$((free_kb-512)) bs=1024 || fail |
| run_command dd if=/dev/zero of=$WORK_DIR/bloat.dat count=$((free_kb-512)) bs=1024 || fail |
| free_kb=$(free_space $WORK_FS) |
| echo "${free_kb}kb free on /$WORK_FS now." |
| |
| testname "apply bsdiff patch with low space" |
| run_command $WORK_DIR/applypatch $WORK_DIR/old.file - $NEW_SHA1 $NEW_SIZE $BAD1_SHA1:$WORK_DIR/foo $OLD_SHA1:$WORK_DIR/patch.bsdiff || fail |
| $ADB pull $WORK_DIR/old.file $tmpdir/patched |
| diff -q $DATA_DIR/new.file $tmpdir/patched || fail |
| |
| testname "reapply bsdiff patch with low space" |
| run_command $WORK_DIR/applypatch $WORK_DIR/old.file - $NEW_SHA1 $NEW_SIZE $BAD1_SHA1:$WORK_DIR/foo $OLD_SHA1:$WORK_DIR/patch.bsdiff || fail |
| $ADB pull $WORK_DIR/old.file $tmpdir/patched |
| diff -q $DATA_DIR/new.file $tmpdir/patched || fail |
| |
| # --------------- apply patch with low space on /system and /cache ---------------------- |
| |
| $ADB push $DATA_DIR/old.file $WORK_DIR |
| $ADB push $DATA_DIR/patch.bsdiff $WORK_DIR |
| |
| free_kb=$(free_space $WORK_FS) |
| echo "${free_kb}kb free on /$WORK_FS" |
| |
| run_command mkdir /cache/subdir |
| run_command 'echo > /cache/subdir/a.file' |
| run_command 'echo > /cache/a.file' |
| run_command mkdir /cache/recovery /cache/recovery/otatest |
| run_command 'echo > /cache/recovery/otatest/b.file' |
| run_command "echo > $CACHE_TEMP_SOURCE" |
| free_kb=$(free_space cache) |
| echo "${free_kb}kb free on /cache; we'll soon fix that." |
| run_command dd if=/dev/zero of=/cache/bloat_small.dat count=128 bs=1024 || fail |
| run_command dd if=/dev/zero of=/cache/bloat_large.dat count=$((free_kb-640)) bs=1024 || fail |
| free_kb=$(free_space cache) |
| echo "${free_kb}kb free on /cache now." |
| |
| testname "apply bsdiff patch with low space, full cache, can't delete enough" |
| $ADB shell 'cat >> /cache/bloat_large.dat' & open_pid=$! |
| echo "open_pid is $open_pid" |
| |
| # size check should fail even though it deletes some stuff |
| run_command $WORK_DIR/applypatch -s $NEW_SIZE && fail |
| run_command ls /cache/bloat_small.dat && fail # was deleted |
| run_command ls /cache/a.file && fail # was deleted |
| run_command ls /cache/recovery/otatest/b.file && fail # was deleted |
| run_command ls /cache/bloat_large.dat || fail # wasn't deleted because it was open |
| run_command ls /cache/subdir/a.file || fail # wasn't deleted because it's in a subdir |
| run_command ls $CACHE_TEMP_SOURCE || fail # wasn't deleted because it's the source file copy |
| |
| # should fail; not enough files can be deleted |
| run_command $WORK_DIR/applypatch $WORK_DIR/old.file - $NEW_SHA1 $NEW_SIZE $BAD1_SHA1:$WORK_DIR/foo $OLD_SHA1:$WORK_DIR/patch.bsdiff && fail |
| run_command ls /cache/bloat_large.dat || fail # wasn't deleted because it was open |
| run_command ls /cache/subdir/a.file || fail # wasn't deleted because it's in a subdir |
| run_command ls $CACHE_TEMP_SOURCE || fail # wasn't deleted because it's the source file copy |
| |
| kill $open_pid # /cache/bloat_large.dat is no longer open |
| |
| testname "apply bsdiff patch with low space, full cache, can delete enough" |
| |
| # should succeed after deleting /cache/bloat_large.dat |
| run_command $WORK_DIR/applypatch -s $NEW_SIZE || fail |
| run_command ls /cache/bloat_large.dat && fail # was deleted |
| run_command ls /cache/subdir/a.file || fail # still wasn't deleted because it's in a subdir |
| run_command ls $CACHE_TEMP_SOURCE || fail # wasn't deleted because it's the source file copy |
| |
| # should succeed |
| run_command $WORK_DIR/applypatch $WORK_DIR/old.file - $NEW_SHA1 $NEW_SIZE $BAD1_SHA1:$WORK_DIR/foo $OLD_SHA1:$WORK_DIR/patch.bsdiff || fail |
| $ADB pull $WORK_DIR/old.file $tmpdir/patched |
| diff -q $DATA_DIR/new.file $tmpdir/patched || fail |
| run_command ls /cache/subdir/a.file || fail # still wasn't deleted because it's in a subdir |
| run_command ls $CACHE_TEMP_SOURCE && fail # was deleted because patching overwrote it, then deleted it |
| |
| # --------------- apply patch from cache ---------------------- |
| |
| $ADB push $DATA_DIR/old.file $CACHE_TEMP_SOURCE |
| # put some junk in the old file |
| run_command dd if=/dev/urandom of=$WORK_DIR/old.file count=100 bs=1024 || fail |
| |
| testname "apply bsdiff patch from cache (corrupted source) with low space" |
| run_command $WORK_DIR/applypatch $WORK_DIR/old.file - $NEW_SHA1 $NEW_SIZE $BAD1_SHA1:$WORK_DIR/foo $OLD_SHA1:$WORK_DIR/patch.bsdiff || fail |
| $ADB pull $WORK_DIR/old.file $tmpdir/patched |
| diff -q $DATA_DIR/new.file $tmpdir/patched || fail |
| |
| $ADB push $DATA_DIR/old.file $CACHE_TEMP_SOURCE |
| # remove the old file entirely |
| run_command rm $WORK_DIR/old.file |
| |
| testname "apply bsdiff patch from cache (missing source) with low space" |
| run_command $WORK_DIR/applypatch $WORK_DIR/old.file - $NEW_SHA1 $NEW_SIZE $BAD1_SHA1:$WORK_DIR/foo $OLD_SHA1:$WORK_DIR/patch.bsdiff || fail |
| $ADB pull $WORK_DIR/old.file $tmpdir/patched |
| diff -q $DATA_DIR/new.file $tmpdir/patched || fail |
| |
| |
| # --------------- cleanup ---------------------- |
| |
| cleanup |
| |
| echo |
| echo PASS |
| echo |
| |