1#!/bin/sh 2# 3# Copyright (c) 2010 Hudson River Trading LLC 4# Written by: John H. Baldwin <jhb@FreeBSD.org> 5# All rights reserved. 6# 7# Redistribution and use in source and binary forms, with or without 8# modification, are permitted provided that the following conditions 9# are met: 10# 1. Redistributions of source code must retain the above copyright 11# notice, this list of conditions and the following disclaimer. 12# 2. Redistributions in binary form must reproduce the above copyright 13# notice, this list of conditions and the following disclaimer in the 14# documentation and/or other materials provided with the distribution. 15# 16# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26# SUCH DAMAGE. 27# 28 29# Various regression tests to test the -F flag to the 'update' command. 30 31FAILED=no 32WORKDIR=work 33 34usage() 35{ 36 echo "Usage: fbsdid.sh [-s script] [-w workdir]" 37 exit 1 38} 39 40# Allow the user to specify an alternate work directory or script. 41COMMAND=etcupdate 42while getopts "s:w:" option; do 43 case $option in 44 s) 45 COMMAND="sh $OPTARG" 46 ;; 47 w) 48 WORKDIR=$OPTARG 49 ;; 50 *) 51 echo 52 usage 53 ;; 54 esac 55done 56shift $((OPTIND - 1)) 57if [ $# -ne 0 ]; then 58 usage 59fi 60 61CONFLICTS=$WORKDIR/conflicts 62OLD=$WORKDIR/old 63NEW=$WORKDIR/current 64TEST=$WORKDIR/test 65 66# Store a FreeBSD ID string in a specified file. The first argument 67# is the file, the remaining arguments are the comment to use. 68store_id() 69{ 70 local file 71 72 file=$1 73 shift 74 75 echo -n '# $FreeBSD' >> $file 76 echo -n "$@" >> $file 77 echo '$' >> $file 78} 79 80# These tests deal with FreeBSD ID string conflicts. We run the test 81# twice, once without -F and once with -F. 82build_trees() 83{ 84 local i 85 86 rm -rf $OLD $NEW $TEST $CONFLICTS 87 mkdir -p $OLD $NEW $TEST 88 89 # remove: Remove a file where the only local difference is a 90 # change in the FreeBSD ID string. 91 store_id $OLD/remove 92 store_id $TEST/remove ": head/remove 12345 jhb " 93 94 # old: Modify a file where the only local difference between 95 # the old and test files is a change in the FreeBSD ID string. 96 store_id $OLD/old ": src/old,v 1.1 jhb Exp " 97 store_id $NEW/old ": head/old 12345 jhb " 98 store_id $TEST/old ": head/old 12000 jhb " 99 for i in $OLD $TEST; do 100 cat >> $i/old <<EOF 101 102an old file 103EOF 104 done 105 cat >> $NEW/old <<EOF 106 107a new file 108EOF 109 110 # already: Modify a file where the local file already matches 111 # the new file except for a change in the FreeBSD ID string. 112 store_id $OLD/already ": src/already,v 1.1 jhb Exp " 113 store_id $NEW/already ": head/already 12345 jhb " 114 store_id $TEST/already ": src/already,v 1.2 jhb Exp " 115 cat >> $OLD/already <<EOF 116 117another old file 118EOF 119 for i in $NEW $TEST; do 120 cat >> $i/already <<EOF 121 122another new file 123EOF 124 done 125 126 # add: Add a file that already exists where the only local 127 # difference is a change in the FreeBSD ID string. 128 store_id $NEW/add ": head/add 12345 jhb " 129 store_id $TEST/add "" 130 131 # conflict: Modify a file where the local file has a different 132 # FreeBSD ID string. This should still generate a conflict 133 # even in the -F case. 134 store_id $OLD/conflict ": head/conflict 12000 jhb " 135 store_id $NEW/conflict ": head/conflict 12345 jhb " 136 store_id $TEST/conflict "" 137 cat >> $OLD/conflict <<EOF 138 139this is the old file 140EOF 141 cat >> $NEW/conflict <<EOF 142 143this is the new file 144EOF 145 cat >> $TEST/conflict <<EOF 146 147this is the local file 148EOF 149 150 # local: A file with local modifications has a different 151 # FreeBSD ID string and the only differences between the old 152 # and new versions are a change in the FreeBSD ID string. 153 # This will just update the FreeBSD ID string in the -F case. 154 for i in $OLD $NEW $TEST; do 155 cat >> $i/local <<EOF 156# Some leading text 157# 158EOF 159 done 160 161 store_id $OLD/local ": head/local 12000 jhb " 162 store_id $NEW/local ": head/local 12345 jhb " 163 store_id $TEST/local ": src/local,v 1.5 jhb Exp " 164 165 for i in $OLD $NEW $TEST; do 166 cat >> $i/local <<EOF 167 168this is a file 169EOF 170 done 171 172 cat >> $TEST/local <<EOF 173 174these are some local mods to the file 175EOF 176 177 # local-already: A file with local modifications has the same 178 # FreeBSD ID string as the new version of the file and the 179 # only differences between the old and new versions are a 180 # change in the FreeBSD ID string. Nothing should happen in 181 # the -F case. 182 store_id $OLD/local-already ": head/local 12000 jhb " 183 for i in $NEW $TEST; do 184 store_id $i/local-already ": head/local 12345 jhb " 185 done 186 187 for i in $OLD $NEW $TEST; do 188 cat >> $i/local-already <<EOF 189 190this is a file 191EOF 192 done 193 194 cat >> $TEST/local-already <<EOF 195 196these are some local mods to the file 197EOF 198 199 # local-remove: A file removed locally changed it's FreeBSD ID 200 # but nothing else 201 store_id $OLD/local-remove ": head/local-remove 12000 jhb " 202 store_id $NEW/local-remove ": head/local-remove 12345 jhb " 203 for i in $OLD $NEW; do 204 cat >> $i/local-remove <<EOF 205 206this is a file 207EOF 208 done 209} 210 211# $1 - relative path to file that should be missing from TEST 212missing() 213{ 214 if [ -e $TEST/$1 -o -L $TEST/$1 ]; then 215 echo "File $1 should be missing" 216 FAILED=yes 217 fi 218} 219 220# $1 - relative path to file that should be present in TEST 221present() 222{ 223 if ! [ -e $TEST/$1 -o -L $TEST/$1 ]; then 224 echo "File $1 should be present" 225 FAILED=yes 226 fi 227} 228 229# $1 - relative path to regular file that should be present in TEST 230# $2 - optional string that should match file contents 231# $3 - optional MD5 of the flie contents, overrides $2 if present 232file() 233{ 234 local contents sum 235 236 if ! [ -f $TEST/$1 ]; then 237 echo "File $1 should be a regular file" 238 FAILED=yes 239 elif [ $# -eq 2 ]; then 240 contents=`cat $TEST/$1` 241 if [ "$contents" != "$2" ]; then 242 echo "File $1 has wrong contents" 243 FAILED=yes 244 fi 245 elif [ $# -eq 3 ]; then 246 sum=`md5 -q $TEST/$1` 247 if [ "$sum" != "$3" ]; then 248 echo "File $1 has wrong contents" 249 FAILED=yes 250 fi 251 fi 252} 253 254# $1 - relative path to a regular file that should have a conflict 255# $2 - optional MD5 of the conflict file contents 256conflict() 257{ 258 local sum 259 260 if ! [ -f $CONFLICTS/$1 ]; then 261 echo "File $1 missing conflict" 262 FAILED=yes 263 elif [ $# -gt 1 ]; then 264 sum=`md5 -q $CONFLICTS/$1` 265 if [ "$sum" != "$2" ]; then 266 echo "Conflict $1 has wrong contents" 267 FAILED=yes 268 fi 269 fi 270} 271 272# $1 - relative path to a regular file that should not have a conflict 273noconflict() 274{ 275 if [ -f $CONFLICTS/$1 ]; then 276 echo "File $1 should not have a conflict" 277 FAILED=yes 278 fi 279} 280 281if [ `id -u` -ne 0 ]; then 282 echo "must be root" 283 exit 0 284fi 285 286if [ -r /etc/etcupdate.conf ]; then 287 echo "WARNING: /etc/etcupdate.conf settings may break some tests." 288fi 289 290# First run the test without -F. 291 292build_trees 293 294$COMMAND -r -d $WORKDIR -D $TEST > $WORKDIR/test.out 295 296cat > $WORKDIR/correct.out <<EOF 297 C /already 298 C /conflict 299 C /local 300 M /local-already 301 C /old 302 C /add 303Warnings: 304 Modified regular file remains: /remove 305 Removed file changed: /local-remove 306EOF 307 308echo "Differences for regular:" 309diff -u -L "correct" $WORKDIR/correct.out -L "test" $WORKDIR/test.out \ 310 || FAILED=yes 311 312file /remove "" 1bb4776213af107077be78fead8a351c 313file /old "" 2f799a7addc4132563ef9b44adc66157 314conflict /old 8441be64a1540f2ff584015279682425 315file /already "" aa53bd506f65d01d766e7ba028585e1d 316conflict /already f44105abb1fa3293e95c5d77e428d418 317file /add "" 1dc8c617e541d1fd1b4c70212f71d8ae 318conflict /add f99081e0da9a07f3cfebb430c0414941 319file /conflict "" dc27978df125b0daeb7d9b93265f03fd 320conflict /conflict 868452f666fea1c60ffb918ad9ad9607 321file /local "" aa33e614b5e749449f230e2a2b0072eb 322conflict /local 3df93e64043c8e348fc625b93ea220f4 323file /local-already "" 0298b958a603049f45ae6a109c4f7fea 324missing /local-remove 325 326# Now test with -F. 327 328build_trees 329 330$COMMAND -rF -d $WORKDIR -D $TEST > $WORKDIR/testF.out 331 332cat > $WORKDIR/correctF.out <<EOF 333 D /remove 334 U /already 335 C /conflict 336 M /local 337 U /old 338 U /add 339EOF 340 341echo "Differences for -F:" 342diff -u -L "correct" $WORKDIR/correctF.out -L "test" $WORKDIR/testF.out \ 343 || FAILED=yes 344 345missing /remove 346file /old "" 6a9f34f109d94406a4de3bc5d72de259 347noconflict /old 348file /already "" 21f4eca3aacc702c49878c8da7afd3d0 349noconflict /already 350file /add "" 0208bd647111fedf6318511712ab9e97 351noconflict /add 352file /conflict "" dc27978df125b0daeb7d9b93265f03fd 353conflict /conflict 868452f666fea1c60ffb918ad9ad9607 354file /local "" 3ed5a35e380c8a93fb5f599d4c052713 355file /local-already "" 0298b958a603049f45ae6a109c4f7fea 356missing /local-remove 357 358# Now test with -F and -A forcing all installs. (-A should have 359# precedence over -F) 360 361build_trees 362 363$COMMAND -A '/*' -rF -d $WORKDIR -D $TEST > $WORKDIR/testAF.out 364 365cat > $WORKDIR/correctAF.out <<EOF 366 D /remove 367 U /already 368 U /conflict 369 U /local 370 U /local-already 371 A /local-remove 372 U /old 373 U /add 374EOF 375 376echo "Differences for -A '/*' -F:" 377diff -u -L "correct" $WORKDIR/correctAF.out -L "test" $WORKDIR/testAF.out \ 378 || FAILED=yes 379 380missing /remove 381file /old "" 6a9f34f109d94406a4de3bc5d72de259 382noconflict /old 383file /already "" 21f4eca3aacc702c49878c8da7afd3d0 384noconflict /already 385file /add "" 0208bd647111fedf6318511712ab9e97 386noconflict /add 387file /conflict "" 75ee141c4136beaf14e39de92efa84e4 388noconflict /conflict 389file /local "" 6a8fc5c2755b7a49015089f5e1dbe092 390file /local-already "" 49045f8b51542dd634655301cd296f66 391file /local-remove "" 5c38322efed4014797d7127f5c652d9d 392 393[ "${FAILED}" = no ] 394