Home | History | Annotate | Download | only in applypatch
      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 
     13 EMULATOR_PORT=5580
     14 DATA_DIR=$ANDROID_BUILD_TOP/bootable/recovery/applypatch/testdata
     15 
     16 # This must be the filename that applypatch uses for its copies.
     17 CACHE_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.
     22 WORK_DIR=/system
     23 
     24 # partition that WORK_DIR is located on, without the leading slash
     25 WORK_FS=system
     26 
     27 # set to 0 to use a device instead
     28 USE_EMULATOR=1
     29 
     30 # ------------------------
     31 
     32 tmpdir=$(mktemp -d)
     33 
     34 if [ "$USE_EMULATOR" == 1 ]; then
     35   emulator -wipe-data -noaudio -no-window -port $EMULATOR_PORT &
     36   pid_emulator=$!
     37   ADB="adb -s emulator-$EMULATOR_PORT "
     38 else
     39   ADB="adb -d "
     40 fi
     41 
     42 echo "waiting to connect to device"
     43 $ADB wait-for-device
     44 echo "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.
     51 run_command() {
     52   $ADB shell "$@" \; echo \$? | awk '{if (b) {print a}; a=$0; b=1} END {exit a}'
     53 }
     54 
     55 testname() {
     56   echo
     57   echo "$1"...
     58   testname="$1"
     59 }
     60 
     61 fail() {
     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 
     70 sha1() {
     71   sha1sum $1 | awk '{print $1}'
     72 }
     73 
     74 free_space() {
     75   run_command df | awk "/$1/ {print gensub(/K/, \"\", \"g\", \$6)}"
     76 }
     77 
     78 cleanup() {
     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 
     97 cleanup leave_tmp
     98 
     99 $ADB push $ANDROID_PRODUCT_OUT/system/bin/applypatch $WORK_DIR/applypatch
    100 
    101 BAD1_SHA1=$(printf "%040x" $RANDOM)
    102 BAD2_SHA1=$(printf "%040x" $RANDOM)
    103 OLD_SHA1=$(sha1 $DATA_DIR/old.file)
    104 NEW_SHA1=$(sha1 $DATA_DIR/new.file)
    105 NEW_SIZE=$(stat -c %s $DATA_DIR/new.file)
    106 
    107 # --------------- basic execution ----------------------
    108 
    109 testname "usage message"
    110 run_command $WORK_DIR/applypatch && fail
    111 
    112 testname "display license"
    113 run_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 
    120 testname "check mode single"
    121 run_command $WORK_DIR/applypatch -c $WORK_DIR/old.file $OLD_SHA1 || fail
    122 
    123 testname "check mode multiple"
    124 run_command $WORK_DIR/applypatch -c $WORK_DIR/old.file $BAD1_SHA1 $OLD_SHA1 $BAD2_SHA1|| fail
    125 
    126 testname "check mode failure"
    127 run_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
    131 run_command dd if=/dev/urandom of=$WORK_DIR/old.file count=100 bs=1024 || fail
    132 
    133 testname "check mode cache (corrupted) single"
    134 run_command $WORK_DIR/applypatch -c $WORK_DIR/old.file $OLD_SHA1 || fail
    135 
    136 testname "check mode cache (corrupted) multiple"
    137 run_command $WORK_DIR/applypatch -c $WORK_DIR/old.file $BAD1_SHA1 $OLD_SHA1 $BAD2_SHA1|| fail
    138 
    139 testname "check mode cache (corrupted) failure"
    140 run_command $WORK_DIR/applypatch -c $WORK_DIR/old.file $BAD2_SHA1 $BAD1_SHA1 && fail
    141 
    142 # remove the old file entirely
    143 run_command rm $WORK_DIR/old.file
    144 
    145 testname "check mode cache (missing) single"
    146 run_command $WORK_DIR/applypatch -c $WORK_DIR/old.file $OLD_SHA1 || fail
    147 
    148 testname "check mode cache (missing) multiple"
    149 run_command $WORK_DIR/applypatch -c $WORK_DIR/old.file $BAD1_SHA1 $OLD_SHA1 $BAD2_SHA1|| fail
    150 
    151 testname "check mode cache (missing) failure"
    152 run_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
    159 echo 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.
    165 testname "apply patches (with enough space)"
    166 free_kb=$(free_space $WORK_FS)
    167 echo "${free_kb}kb free on /$WORK_FS."
    168 if (( 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
    175 fi
    176 
    177 testname "apply bsdiff patch"
    178 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
    179 $ADB pull $WORK_DIR/old.file $tmpdir/patched
    180 diff -q $DATA_DIR/new.file $tmpdir/patched || fail
    181 
    182 testname "reapply bsdiff patch"
    183 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
    184 $ADB pull $WORK_DIR/old.file $tmpdir/patched
    185 diff -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.
    196 testname "apply patch to new location (with enough space)"
    197 free_kb=$(free_space $WORK_FS)
    198 echo "${free_kb}kb free on /$WORK_FS."
    199 if (( 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
    206 fi
    207 
    208 run_command rm $WORK_DIR/new.file
    209 run_command rm $CACHE_TEMP_SOURCE
    210 
    211 testname "apply bsdiff patch to new location"
    212 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
    213 $ADB pull $WORK_DIR/new.file $tmpdir/patched
    214 diff -q $DATA_DIR/new.file $tmpdir/patched || fail
    215 
    216 testname "reapply bsdiff patch to new location"
    217 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
    218 $ADB pull $WORK_DIR/new.file $tmpdir/patched
    219 diff -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
    223 run_command dd if=/dev/urandom of=$WORK_DIR/old.file count=100 bs=1024 || fail
    224 
    225 testname "apply bsdiff patch to new location with corrupted source"
    226 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
    227 $ADB pull $WORK_DIR/new.file $tmpdir/patched
    228 diff -q $DATA_DIR/new.file $tmpdir/patched || fail
    229 
    230 # put some junk in the cache copy, too
    231 run_command dd if=/dev/urandom of=$CACHE_TEMP_SOURCE count=100 bs=1024 || fail
    232 
    233 run_command rm $WORK_DIR/new.file
    234 testname "apply bsdiff patch to new location with corrupted source and copy (no new file)"
    235 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
    236 
    237 # put some junk in the new file
    238 run_command dd if=/dev/urandom of=$WORK_DIR/new.file count=100 bs=1024 || fail
    239 
    240 testname "apply bsdiff patch to new location with corrupted source and copy (bad new file)"
    241 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
    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 
    248 free_kb=$(free_space $WORK_FS)
    249 echo "${free_kb}kb free on /$WORK_FS; we'll soon fix that."
    250 echo run_command dd if=/dev/zero of=$WORK_DIR/bloat.dat count=$((free_kb-512)) bs=1024 || fail
    251 run_command dd if=/dev/zero of=$WORK_DIR/bloat.dat count=$((free_kb-512)) bs=1024 || fail
    252 free_kb=$(free_space $WORK_FS)
    253 echo "${free_kb}kb free on /$WORK_FS now."
    254 
    255 testname "apply bsdiff patch with low space"
    256 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
    257 $ADB pull $WORK_DIR/old.file $tmpdir/patched
    258 diff -q $DATA_DIR/new.file $tmpdir/patched || fail
    259 
    260 testname "reapply bsdiff patch with low space"
    261 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
    262 $ADB pull $WORK_DIR/old.file $tmpdir/patched
    263 diff -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 
    270 free_kb=$(free_space $WORK_FS)
    271 echo "${free_kb}kb free on /$WORK_FS"
    272 
    273 run_command mkdir /cache/subdir
    274 run_command 'echo > /cache/subdir/a.file'
    275 run_command 'echo > /cache/a.file'
    276 run_command mkdir /cache/recovery /cache/recovery/otatest
    277 run_command 'echo > /cache/recovery/otatest/b.file'
    278 run_command "echo > $CACHE_TEMP_SOURCE"
    279 free_kb=$(free_space cache)
    280 echo "${free_kb}kb free on /cache; we'll soon fix that."
    281 run_command dd if=/dev/zero of=/cache/bloat_small.dat count=128 bs=1024 || fail
    282 run_command dd if=/dev/zero of=/cache/bloat_large.dat count=$((free_kb-640)) bs=1024 || fail
    283 free_kb=$(free_space cache)
    284 echo "${free_kb}kb free on /cache now."
    285 
    286 testname "apply bsdiff patch with low space, full cache, can't delete enough"
    287 $ADB shell 'cat >> /cache/bloat_large.dat' & open_pid=$!
    288 echo "open_pid is $open_pid"
    289 
    290 # size check should fail even though it deletes some stuff
    291 run_command $WORK_DIR/applypatch -s $NEW_SIZE && fail
    292 run_command ls /cache/bloat_small.dat && fail          # was deleted
    293 run_command ls /cache/a.file && fail                   # was deleted
    294 run_command ls /cache/recovery/otatest/b.file && fail  # was deleted
    295 run_command ls /cache/bloat_large.dat || fail          # wasn't deleted because it was open
    296 run_command ls /cache/subdir/a.file || fail            # wasn't deleted because it's in a subdir
    297 run_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
    300 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
    301 run_command ls /cache/bloat_large.dat || fail   # wasn't deleted because it was open
    302 run_command ls /cache/subdir/a.file || fail     # wasn't deleted because it's in a subdir
    303 run_command ls $CACHE_TEMP_SOURCE || fail       # wasn't deleted because it's the source file copy
    304 
    305 kill $open_pid   # /cache/bloat_large.dat is no longer open
    306 
    307 testname "apply bsdiff patch with low space, full cache, can delete enough"
    308 
    309 # should succeed after deleting /cache/bloat_large.dat
    310 run_command $WORK_DIR/applypatch -s $NEW_SIZE || fail
    311 run_command ls /cache/bloat_large.dat && fail   # was deleted
    312 run_command ls /cache/subdir/a.file || fail     # still wasn't deleted because it's in a subdir
    313 run_command ls $CACHE_TEMP_SOURCE || fail       # wasn't deleted because it's the source file copy
    314 
    315 # should succeed
    316 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
    317 $ADB pull $WORK_DIR/old.file $tmpdir/patched
    318 diff -q $DATA_DIR/new.file $tmpdir/patched || fail
    319 run_command ls /cache/subdir/a.file || fail     # still wasn't deleted because it's in a subdir
    320 run_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
    326 run_command dd if=/dev/urandom of=$WORK_DIR/old.file count=100 bs=1024 || fail
    327 
    328 testname "apply bsdiff patch from cache (corrupted source) with low space"
    329 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
    330 $ADB pull $WORK_DIR/old.file $tmpdir/patched
    331 diff -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
    335 run_command rm $WORK_DIR/old.file
    336 
    337 testname "apply bsdiff patch from cache (missing source) with low space"
    338 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
    339 $ADB pull $WORK_DIR/old.file $tmpdir/patched
    340 diff -q $DATA_DIR/new.file $tmpdir/patched || fail
    341 
    342 
    343 # --------------- cleanup ----------------------
    344 
    345 cleanup
    346 
    347 echo
    348 echo PASS
    349 echo
    350 
    351