#!/bin/bash # # Copyright 2008 Google Inc. # Author: Lincoln Smith # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http:#www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # This script tests the correctness of the vcdiff command-line executable. # If you add a new test here, please add the same test to the Windows script # vsprojects/vcdiff_test.bat. # # The caller should set the environment variable $srcdir to the root directory # of the open-vcdiff package. ($srcdir is automatically provided by Automake # when this script is run by "make check".) # Find input files VCDIFF=./vcdiff # These options are only needed for the encoder; # the decoder will recognize the interleaved and checksum formats # without needing to specify any options. VCD_OPTIONS="-interleaved -checksum" DICTIONARY_FILE=$srcdir/testdata/configure.ac.v0.1 TARGET_FILE=$srcdir/testdata/configure.ac.v0.2 TEST_TMPDIR=${TMPDIR-/tmp} DELTA_FILE=$TEST_TMPDIR/configure.ac.vcdiff OUTPUT_TARGET_FILE=$TEST_TMPDIR/configure.ac.output MALICIOUS_ENCODING=$srcdir/testdata/allocates_4gb.vcdiff # vcdiff with no arguments shows usage information & error result $VCDIFF \ && { echo "vcdiff with no arguments should fail, but succeeded"; \ exit 1; } echo "Test 1 ok"; # vcdiff with three arguments but without "encode" or "decode" # shows usage information & error result $VCDIFF $VCD_OPTIONS \ -dictionary $DICTIONARY_FILE -target $TARGET_FILE -delta $DELTA_FILE \ && { echo "vcdiff without operation argument should fail, but succeeded"; \ exit 1; } echo "Test 2 ok"; # vcdiff with all three arguments. Verify that output file matches target file $VCDIFF $VCD_OPTIONS \ encode -dictionary $DICTIONARY_FILE \ -target $TARGET_FILE \ -delta $DELTA_FILE \ || { echo "Encode with three arguments failed"; \ exit 1; } $VCDIFF decode -dictionary $DICTIONARY_FILE \ -delta $DELTA_FILE \ -target $OUTPUT_TARGET_FILE \ || { echo "Decode with three arguments failed"; \ exit 1; } cmp $TARGET_FILE $OUTPUT_TARGET_FILE \ || { echo "Decoded target does not match original"; \ exit 1; } echo "Test 3 ok"; rm $DELTA_FILE rm $OUTPUT_TARGET_FILE # vcdiff using stdin/stdout. Verify that output file matches target file { $VCDIFF $VCD_OPTIONS \ encode -dictionary $DICTIONARY_FILE \ < $TARGET_FILE \ > $DELTA_FILE; } \ || { echo "Encode using stdin/stdout failed"; \ exit 1; } { $VCDIFF decode -dictionary $DICTIONARY_FILE \ < $DELTA_FILE \ > $OUTPUT_TARGET_FILE; } \ || { echo "Decode using stdin/stdout failed"; \ exit 1; } cmp $TARGET_FILE $OUTPUT_TARGET_FILE \ || { echo "Decoded target does not match original"; \ exit 1; } echo "Test 4 ok"; rm $DELTA_FILE rm $OUTPUT_TARGET_FILE # vcdiff with mixed stdin/stdout. { $VCDIFF $VCD_OPTIONS \ encode -dictionary $DICTIONARY_FILE \ -target $TARGET_FILE \ > $DELTA_FILE; } \ || { echo "Encode with mixed arguments failed"; \ exit 1; } { $VCDIFF decode -dictionary $DICTIONARY_FILE \ -delta $DELTA_FILE \ > $OUTPUT_TARGET_FILE; } \ || { echo "Decode with mixed arguments failed"; \ exit 1; } cmp $TARGET_FILE $OUTPUT_TARGET_FILE \ || { echo "Decoded target does not match original"; \ exit 1; } echo "Test 5 ok"; rm $DELTA_FILE rm $OUTPUT_TARGET_FILE { $VCDIFF $VCD_OPTIONS \ encode -dictionary $DICTIONARY_FILE \ < $TARGET_FILE \ -delta $DELTA_FILE; } \ || { echo "Encode with mixed arguments failed"; \ exit 1; } { $VCDIFF decode -dictionary $DICTIONARY_FILE \ < $DELTA_FILE \ -target $OUTPUT_TARGET_FILE; } \ || { echo "Decode with mixed arguments failed"; \ exit 1; } cmp $TARGET_FILE $OUTPUT_TARGET_FILE \ || { echo "Decoded target does not match original"; \ exit 1; } echo "Test 6 ok"; rm $OUTPUT_TARGET_FILE # Don't remove $DELTA_FILE; use it for the next test # If using the wrong dictionary, and dictionary is smaller than the original # dictionary, vcdiff will spot the mistake and return an error. (It can't # detect the case where the wrong dictionary is larger than the right one.) $VCDIFF decode -dictionary $TARGET_FILE \ -delta $DELTA_FILE \ -target $OUTPUT_TARGET_FILE \ && { echo "Decode using larger dictionary should fail, but succeeded"; \ exit 1; } echo "Test 7 ok"; rm $DELTA_FILE rm $OUTPUT_TARGET_FILE # "vcdiff test" with all three arguments. $VCDIFF $VCD_OPTIONS \ test -dictionary $DICTIONARY_FILE \ -target $TARGET_FILE \ -delta $DELTA_FILE \ || { echo "vcdiff test with three arguments failed"; \ exit 1; } echo "Test 8 ok"; rm $DELTA_FILE # Dictionary file not found. $VCDIFF $VCD_OPTIONS \ encode -dictionary $TEST_TMPDIR/nonexistent_file \ -target $TARGET_FILE \ -delta $DELTA_FILE \ && { echo "vcdiff with missing dictionary file should fail, but succeeded"; \ exit 1; } echo "Test 9 ok"; # Target file not found. $VCDIFF $VCD_OPTIONS \ encode -dictionary $DICTIONARY_FILE \ -target $TEST_TMPDIR/nonexistent_file \ -delta $DELTA_FILE \ && { echo "vcdiff with missing target file should fail, but succeeded"; \ exit 1; } echo "Test 10 ok"; # Delta file not found. $VCDIFF decode -dictionary $DICTIONARY_FILE \ -delta $TEST_TMPDIR/nonexistent_file \ -target $OUTPUT_TARGET_FILE \ && { echo "vcdiff with missing delta file should fail, but succeeded"; \ exit 1; } echo "Test 11 ok"; # Try traversing an infinite loop of symbolic links. ln -s $TEST_TMPDIR/infinite_loop1 $TEST_TMPDIR/infinite_loop2 ln -s $TEST_TMPDIR/infinite_loop2 $TEST_TMPDIR/infinite_loop1 $VCDIFF $VCD_OPTIONS \ encode -dictionary $TEST_TMPDIR/infinite_loop1 \ -target $TEST_TMPDIR/infinite_loop2 \ -delta $DELTA_FILE \ && { echo "vcdiff with symbolic link loop should fail, but succeeded"; \ exit 1; } echo "Test 12 ok"; rm $TEST_TMPDIR/infinite_loop1 $TEST_TMPDIR/infinite_loop2 # Test using -stats flag $VCDIFF $VCD_OPTIONS \ encode -dictionary $DICTIONARY_FILE \ -target $TARGET_FILE \ -delta $DELTA_FILE \ -stats \ || { echo "Encode with -stats failed"; \ exit 1; } $VCDIFF -stats \ decode -dictionary $DICTIONARY_FILE \ -delta $DELTA_FILE \ -target $OUTPUT_TARGET_FILE \ || { echo "Decode with -stats failed"; \ exit 1; } cmp $TARGET_FILE $OUTPUT_TARGET_FILE \ || { echo "Decoded target does not match original"; \ exit 1; } echo "Test 13 ok"; rm $DELTA_FILE rm $OUTPUT_TARGET_FILE # Using /dev/null as dictionary should work, but (because dictionary is empty) # it will not produce a small delta file. $VCDIFF $VCD_OPTIONS \ test -dictionary /dev/null \ -target $TARGET_FILE \ -delta $DELTA_FILE \ -stats \ || { echo "vcdiff test with /dev/null as dictionary failed"; \ exit 1; } echo "Test 14 ok"; rm $DELTA_FILE # Using /dev/kmem as dictionary or target should produce an error # (permission denied, or too large, or special file type) $VCDIFF $VCD_OPTIONS \ encode -dictionary /dev/kmem \ -target $TARGET_FILE \ -delta $DELTA_FILE \ && { echo "vcdiff with /dev/kmem as dictionary should fail, but succeeded"; \ exit 1; } echo "Test 15 ok"; $VCDIFF $VCD_OPTIONS \ encode -dictionary $DICTIONARY_FILE \ -target /dev/kmem \ -delta $DELTA_FILE \ && { echo "vcdiff with /dev/kmem as target should fail, but succeeded"; \ exit 1; } echo "Test 16 ok"; # Decode using something that isn't a delta file $VCDIFF decode -dictionary $DICTIONARY_FILE \ -delta /etc/fstab \ -target $OUTPUT_TARGET_FILE \ && { echo "vcdiff with invalid delta file should fail, but succeeded"; \ exit 1; } echo "Test 17 ok"; $VCDIFF $VCD_OPTIONS \ encode -target $TARGET_FILE \ -delta $DELTA_FILE \ -dictionary \ && { echo "-dictionary option with no file name should fail, but succeeded"; \ exit 1; } echo "Test 18 ok"; $VCDIFF $VCD_OPTIONS \ encode -dictionary $DICTIONARY_FILE \ -delta $DELTA_FILE \ -target \ && { echo "-target option with no file name should fail, but succeeded"; \ exit 1; } echo "Test 19 ok"; $VCDIFF $VCD_OPTIONS \ encode -dictionary $DICTIONARY_FILE \ -target $TARGET_FILE \ -delta \ && { echo "-delta option with no file name should fail, but succeeded"; \ exit 1; } echo "Test 20 ok"; $VCDIFF $VCD_OPTIONS \ encode -dictionary $DICTIONARY_FILE \ -target $TARGET_FILE \ -delta $DELTA_FILE \ -buffersize \ && { echo "-buffersize option with no argument should fail, but succeeded"; \ exit 1; } echo "Test 21 ok"; # Using -buffersize=1 should still work. $VCDIFF $VCD_OPTIONS \ test -dictionary $DICTIONARY_FILE \ -target $TARGET_FILE \ -delta $DELTA_FILE \ -buffersize 1 \ -stats \ || { echo "vcdiff test with -buffersize=1 failed"; \ exit 1; } echo "Test 22 ok"; rm $DELTA_FILE # Using -buffersize=1 with stdin/stdout means that vcdiff # will create a separate target window for each byte read. { $VCDIFF encode -dictionary $DICTIONARY_FILE \ -buffersize 1 \ -stats \ < $TARGET_FILE \ > $DELTA_FILE; } \ || { echo "Encode using stdin/stdout with -buffersize=1 failed"; \ exit 1; } { $VCDIFF decode -dictionary $DICTIONARY_FILE \ -buffersize 1 \ -stats \ < $DELTA_FILE \ > $OUTPUT_TARGET_FILE; } \ || { echo "Decode using stdin/stdout with -buffersize=1 failed"; \ exit 1; } cmp $TARGET_FILE $OUTPUT_TARGET_FILE \ || { echo "Decoded target does not match original with -buffersize=1"; \ exit 1; } echo "Test 23 ok"; rm $DELTA_FILE rm $OUTPUT_TARGET_FILE # Using -buffersize=0 should fail. $VCDIFF $VCD_OPTIONS \ test -dictionary $DICTIONARY_FILE \ -target $TARGET_FILE \ -delta $DELTA_FILE \ -buffersize 0 \ && { echo "vcdiff test with -buffersize=0 should fail, but succeeded"; \ exit 1; } echo "Test 24 ok"; rm $DELTA_FILE # Using -buffersize=128M (larger than default maximum) should still work. $VCDIFF $VCD_OPTIONS \ test -dictionary $DICTIONARY_FILE \ -target $TARGET_FILE \ -delta $DELTA_FILE \ -buffersize 134217728 \ -stats \ || { echo "vcdiff test with -buffersize=128M failed"; \ exit 1; } echo "Test 25 ok"; rm $DELTA_FILE $VCDIFF $VCD_OPTIONS \ test -dictionary $DICTIONARY_FILE \ -target $TARGET_FILE \ -delta $DELTA_FILE \ -froobish \ && { echo "vdiff test with unrecognized option should fail, but succeeded"; \ exit 1; } echo "Test 26 ok"; $VCDIFF $VCD_OPTIONS \ encode -target $TARGET_FILE \ -delta $DELTA_FILE \ && { echo "encode with no dictionary option should fail, but succeeded"; \ exit 1; } echo "Test 27 ok"; $VCDIFF decode -target $TARGET_FILE \ -delta $DELTA_FILE \ && { echo "decode with no dictionary option should fail, but succeeded"; \ exit 1; } echo "Test 28 ok"; # Remove -interleaved and -checksum options { $VCDIFF encode -dictionary $DICTIONARY_FILE \ < $TARGET_FILE \ > $DELTA_FILE; } \ || { echo "Encode without -interleaved and -checksum options failed"; \ exit 1; } { $VCDIFF decode -dictionary $DICTIONARY_FILE \ < $DELTA_FILE \ > $OUTPUT_TARGET_FILE; } \ || { echo "Decode non-interleaved output failed"; \ exit 1; } cmp $TARGET_FILE $OUTPUT_TARGET_FILE \ || { echo "Decoded target does not match original with -interleaved"; \ exit 1; } echo "Test 29 ok"; # -target_matches option { $VCDIFF encode -dictionary $DICTIONARY_FILE \ -target_matches \ -stats \ < $TARGET_FILE \ > $DELTA_FILE; } \ || { echo "Encode with -target_matches option failed"; \ exit 1; } # The decode operation ignores the -target_matches option. { $VCDIFF decode -dictionary $DICTIONARY_FILE \ < $DELTA_FILE \ > $OUTPUT_TARGET_FILE; } \ || { echo "Decode output failed with -target_matches"; \ exit 1; } cmp $TARGET_FILE $OUTPUT_TARGET_FILE \ || { echo "Decoded target does not match original with -target_matches"; \ exit 1; } echo "Test 30 ok"; rm $DELTA_FILE rm $OUTPUT_TARGET_FILE $VCDIFF $VCD_OPTIONS \ dencode -dictionary $DICTIONARY_FILE \ -target $TARGET_FILE \ -delta $DELTA_FILE \ && { echo "vdiff with unrecognized action should fail, but succeeded"; \ exit 1; } echo "Test 31 ok"; $VCDIFF $VCD_OPTIONS \ test -dictionary $DICTIONARY_FILE \ -target $TARGET_FILE \ && { echo "vdiff test without delta option should fail, but succeeded"; \ exit 1; } echo "Test 32 ok"; $VCDIFF $VCD_OPTIONS \ test -dictionary $DICTIONARY_FILE \ -delta $DELTA_FILE \ && { echo "vdiff test without target option should fail, but succeeded"; \ exit 1; } echo "Test 33 ok"; # open-vcdiff bug 8 (http://code.google.com/p/open-vcdiff/issues/detail?id=8) # A malicious encoding that tries to produce a 4GB target file made up of 64 # windows, each window having a size of 64MB. # Limit memory usage to 256MB per process, so the test doesn't take forever # to run out of memory. OLD_ULIMIT=$(ulimit -v) echo "Old ulimit: $OLD_ULIMIT" ulimit -S -v 262144 echo "New ulimit: $(ulimit -v)" $VCDIFF $VCD_OPTIONS \ decode -dictionary $DICTIONARY_FILE \ -delta $MALICIOUS_ENCODING \ -target /dev/null \ -max_target_file_size=65536 \ && { echo "Decoding malicious file should fail, but succeeded"; \ exit 1; } echo "Test 34 ok"; $VCDIFF $VCD_OPTIONS \ decode -dictionary $DICTIONARY_FILE \ -delta $MALICIOUS_ENCODING \ -target /dev/null \ -max_target_window_size=65536 \ && { echo "Decoding malicious file should fail, but succeeded"; \ exit 1; } echo "Test 35 ok"; ulimit -S -v $OLD_ULIMIT # Decoding a small target with the -max_target_file_size option should succeed. $VCDIFF $VCD_OPTIONS \ test -dictionary $DICTIONARY_FILE \ -target $TARGET_FILE \ -delta $DELTA_FILE \ -max_target_file_size=65536 \ || { echo "vcdiff test with -max_target_file_size failed"; \ exit 1; } echo "Test 36 ok"; # Decoding a small target with -max_target_window_size option should succeed. $VCDIFF $VCD_OPTIONS \ test -dictionary $DICTIONARY_FILE \ -target $TARGET_FILE \ -delta $DELTA_FILE \ -max_target_window_size=65536 \ || { echo "vcdiff test with -max_target_window_size failed"; \ exit 1; } echo "Test 37 ok"; rm $DELTA_FILE # Test using -allow_vcd_target=false $VCDIFF $VCD_OPTIONS \ encode -dictionary $DICTIONARY_FILE \ -target $TARGET_FILE \ -delta $DELTA_FILE \ -allow_vcd_target=false \ || { echo "Encode with -allow_vcd_target=false failed"; \ exit 1; } $VCDIFF $VCD_OPTIONS \ decode -dictionary $DICTIONARY_FILE \ -delta $DELTA_FILE \ -target $OUTPUT_TARGET_FILE \ -allow_vcd_target=false \ || { echo "Decode with -allow_vcd_target=false failed"; \ exit 1; } cmp $TARGET_FILE $OUTPUT_TARGET_FILE \ || { echo "Decoded target does not match original"; \ exit 1; } echo "Test 38 ok"; rm $DELTA_FILE rm $OUTPUT_TARGET_FILE # Test using -allow_vcd_target=true $VCDIFF $VCD_OPTIONS \ encode -dictionary $DICTIONARY_FILE \ -target $TARGET_FILE \ -delta $DELTA_FILE \ -allow_vcd_target=true \ || { echo "Encode with -allow_vcd_target=true failed"; \ exit 1; } $VCDIFF $VCD_OPTIONS \ decode -dictionary $DICTIONARY_FILE \ -delta $DELTA_FILE \ -target $OUTPUT_TARGET_FILE \ -allow_vcd_target=true \ || { echo "Decode with -allow_vcd_target=true failed"; \ exit 1; } cmp $TARGET_FILE $OUTPUT_TARGET_FILE \ || { echo "Decoded target does not match original"; \ exit 1; } echo "Test 39 ok"; echo "PASS"