#!/bin/ksh # # Copyright (c) 2000-2001 Silicon Graphics, Inc. All Rights Reserved. # #-----------------------------------------------------------------# # run_test: a ksh script for testing the DMAPI. # # USAGE: run_test [-p] [-x] [-u user] # [-F fs_type -M fs_mtpt -R "real" directory] # [-f datafile] [-s sleeptime] # bindir testdir fsdir # # p: Causes pausing after every test (not just ones with errors). # # x: Prints an execution trace as the script runs. # # user: Most tests don't need root access, so they will be run # under this username. # # (NOTE: the following three must be used together) # # fs_type: For NFS tests; the type of filesystem (ie nfs2, nfs3). # # fs_mtpt: For NFS tests, the path to the mount of your # "real" filesystem. # (ie, "mount -t nfs2 localhost:/dmitest $fs_mtpt") # # "real" directory: For NFS tests, the path to the "real" test directory. # # datafile: The name of the file which contains the tests to run. # # sleeptime: time, in seconds, for the daemon to sleep after # responding to an event. (Useful for testing small # outstanding-events queues.) # # bindir: The path to the directory that holds dm_test_daemon, send_msg, # the datafile, and any other files required by the datafile. # # testdir: The path to the test directory. All DMAPI testing # occurs here -- this is where the tests will actually # be run. (For NFS tests, this will be an NFS mount # of the "real" directory.) # # fsdir: The path name of the test filesystem. The daemon will start # using this path, and the mount and unmount of the DMAPI # filesystem will be done here. (Even for NFS tests, this # should still be the same test filesystem.) # #-----------------------------------------------------------------# # For most reads, we'll want spaces to be the field separators. IFS=" " typeset -i fail_flag typeset -i pause_flag typeset -i sleeptime # To run tests that don't require root access, we'll change to # a user specified by lname. lname=$LOGNAME # Set the default external files to use. datafile=main.dat sleeptime=0 unset fs_type fs_mtpt real_dir=set_me_later # Parse the command-line options while getopts :pxu:F:M:R:f:b:s: option do case $option in p) pause_flag=1;; x) set -x;; u) lname=$OPTARG;; F) fs_type=$OPTARG;; M) fs_mtpt=$OPTARG;; R) real_dir=$OPTARG;; f) datafile=$OPTARG;; b) bindir=$OPTARG;; s) sleeptime=$OPTARG;; :) print -u2 "${0##*/}: $OPTARG requires a value" exit 2;; \?) print -nu2 "USAGE: ${0##*/} [-p] [-x] [-u user] " print -nu2 "[-F fs type -M mountpoint directory -R \"real\" directory] " print -u2 "[-s sleeptime] [-f datafile] bindir testdir fsdir" exit 2;; esac done # Shift out the examined options, then check that we have # exactly three arguments left: (the paths to the "bindir", # the test directory, and the filesystem). shift OPTIND-1 if [[ $# != 3 ]] then print -nu2 "USAGE: ${0##*/} [-p] [-x] [-u user] " print -nu2 "[-F fs type -M mountpoint directory -R \"real\" directory] " print -u2 "[-s sleeptime] [-f datafile] bindir testdir fsdir" exit 2 fi # For NFS tests, $2 will be an NFS mount of the test directory; # real_dir should be the test directory's actual path. # Otherwise, real_dir should just be $2. if [[ $real_dir = set_me_later ]] then real_dir=$2 fi # Check bindir for the existence of our three critical external files. error_count=0 for i in dm_test_daemon send_msg $datafile do if [[ ! ( -r "$1/$i" ) ]] then if ((error_count==0)) then print "Aborting: the directory $1/ is missing critical files:" fi print "$1/$i" (( error_count = error_count + 1 )) fi done if (( error_count > 0 )) then exit 1 fi # Open the datafile on file descriptor 3 exec 3< $1/$datafile # Read datafile and determine what files it needs from bindir; # then, check for the existence of these files. error_count=0 while read -u3 file_list do case $file_list in ---*) break;; //*) continue;; *) for i in $file_list do if [[ ! ( -r "$1/$i" ) ]] then if ((error_count==0)) then print "The directory $1/ is missing these files:" fi print "$1/$i" (( error_count = error_count + 1 )) fi done;; esac done if (( error_count > 0 )) then exit 1 fi # Run initialization stuff without daemon. while read -u3 cmd do case $cmd in //*) continue;; ---*) break;; *) eval "$cmd";; esac done # If we're testing over nfs, remount the filesystem to clear the cache. case $fs_type in nfs2) print "Clearing nfs2 cache by remounting filesystem..." eval "umount $fs_mtpt" eval "mount -t nfs2 localhost:$3 $fs_mtpt";; nfs3) print "Clearing nfs3 cache by remounting filesystem..." eval "umount $fs_mtpt" eval "mount -t nfs3 localhost:$3 $fs_mtpt";; *) if [[ $fs_type != "" ]] then print "ERROR: $fs_type not a known or testable filesystem type" fi;; esac # Check with the user before starting up daemon print "\n** Using testfile ${datafile##*/} **" print "** Using userid $lname for tests not requiring root access **" print "Press enter to begin, or enter q or n to abort..." read go case "$go" in n|N|q|Q) exit 1;; *);; esac # Now, the user will need ownership of the test directory # ($2, not $real_dir, since real_dir is accessed only as root). eval "chown $lname $2" # Now it's time to begin running the daemon as a coprocess. # The daemon will use a : as its internal field separator. IFS=":" if (($sleeptime > 0)) then $1/dm_test_daemon -s $sleeptime $3 |& else $1/dm_test_daemon $3 |& fi #Keep track of the coprocess id... "$!" may change. coproc=$! # Initialize the count of errors error_count=0; # dm_test_daemon starts with a spurious line feed. read -p junk # Finally, we've reached the actual loop to read in the testfile. while true do clear while read -u3 cmd do case $cmd in run_without_test) while read -u3 cmd do case $cmd in ---*) clear; continue 2;; //*) continue;; @@*) cmd=${cmd#@@*} print "!! ${cmd# *}" continue;; *) eval $cmd;; esac done;; run_as_root) read -u3 cmd root_flag=1 break;; //*) continue;; @@*) cmd=${cmd#@@*} print "!! ${cmd# *}" continue;; *) root_flag=0 break;; esac done if (( $root_flag == 1 )) then print "Command to execute (as root):\n\n $cmd\n" eval "$cmd" else print "Command to execute:\n\n $cmd\n" eval "su $lname -c \"$cmd\"" fi # Note failure of the command. Also, send a message # that the command is done. We will know we're done # reading from the daemon when we see this message. fail_flag=$? $1/send_msg over print # Reset variables for reading this command. event_count=0 unset contents event fs_handle handle length offset unset media_designator mode mountpoint_handle unset mountpoint_path msg_str name new_name new_parent unset parent_handle ret_code root_handle sequence token unset tries_left unmount_mode # Read events, report them, and store their data. while true do read -p event[event_count] case "${event[event_count]}" in mount) print "Report: found mount event." read -p junk token[event_count] read -p junk sequence[event_count] read -p junk fs_handle[event_count] read -p junk mountpoint_handle[event_count] read -p junk mountpoint_path[event_count] read -p junk media_designator[event_count] read -p junk root_handle[event_count] read -p junk mode[event_count] read -p junk;; preunmount) print "Report: found preunmount event." read -p junk token[event_count] read -p junk sequence[event_count] read -p junk fs_handle[event_count] read -p junk root_handle[event_count] read -p junk unmount_mode[event_count] read -p junk;; unmount) print "Report: found unmount event." read -p junk token[event_count] read -p junk sequence[event_count] read -p junk fs_handle[event_count] read -p junk unmount_mode[event_count] read -p junk ret_code[event_count] read -p junk;; nospace) print "Report: found nospace event." read -p junk token[event_count] read -p junk sequence[event_count] read -p junk fs_handle[event_count] read -p junk;; create|remove) print "Report: found ${event[event_count]} event." read -p junk token[event_count] read -p junk sequence[event_count] read -p junk parent_handle[event_count] read -p junk name[event_count] read -p junk mode[event_count] read -p junk;; postcreate) print "Report: found postcreate event." read -p junk token[event_count] read -p junk sequence[event_count] read -p junk parent_handle[event_count] read -p junk handle[event_count] read -p junk name[event_count] read -p junk mode[event_count] read -p junk ret_code[event_count] read -p junk;; postremove) print "Report: found postremove event." read -p junk token[event_count] read -p junk sequence[event_count] read -p junk parent_handle[event_count] read -p junk name[event_count] read -p junk mode[event_count] read -p junk ret_code[event_count] read -p junk;; rename) print "Report: found rename event." read -p junk token[event_count] read -p junk sequence[event_count] read -p junk parent_handle[event_count] read -p junk new_parent[event_count] read -p junk name[event_count] read -p junk new_name[event_count] read -p junk;; postrename) print "Report: found postrename event." read -p junk token[event_count] read -p junk sequence[event_count] read -p junk parent_handle[event_count] read -p junk new_parent[event_count] read -p junk name[event_count] read -p junk new_name[event_count] read -p junk ret_code[event_count] read -p junk;; symlink) print "Report: found symlink event." read -p junk token[event_count] read -p junk sequence[event_count] read -p junk parent_handle[event_count] read -p junk name[event_count] read -p junk contents[event_count] read -p junk;; postsymlink) print "Report: found postsymlink event." read -p junk token[event_count] read -p junk sequence[event_count] read -p junk parent_handle[event_count] read -p junk handle[event_count] read -p junk name[event_count] read -p junk contents[event_count] read -p junk ret_code[event_count] read -p junk;; link) print "Report: found link event." read -p junk token[event_count] read -p junk sequence[event_count] read -p junk parent_handle[event_count] read -p junk handle[event_count] read -p junk name[event_count] read -p junk;; postlink) print "Report: found postlink event." read -p junk token[event_count] read -p junk sequence[event_count] read -p junk parent_handle[event_count] read -p junk handle[event_count] read -p junk name[event_count] read -p junk ret_code[event_count] read -p junk;; read|write|truncate) print "Report: found ${event[event_count]} event." read -p junk token[event_count] read -p junk sequence[event_count] read -p junk handle[event_count] read -p junk offset[event_count] read -p junk length[event_count] read -p junk;; attribute) print "Report: found attribute event." read -p junk token[event_count] read -p junk sequence[event_count] read -p junk handle[event_count] read -p junk;; destroy) print "Report: found destroy event." read -p junk token[event_count] read -p junk sequence[event_count] read -p junk handle[event_count] read -p junk name[event_count] read -p junk contents[event_count] read -p junk;; user) read -p junk token[event_count] read -p junk sequence[event_count] read -p junk msg_str[event_count] case "${msg_str[event_count]}" in "over") read -p junk event[event_count]=end_of_tests print "Report: found \"end of test\" user event. " break;; *) print "Report: found user event. " read -p junk;; esac;; pending) read -p junk tries_left[event_count] print -n "Report: process pending. " print "Tries left: ${tries_left[event_count]}" read -p junk;; *) print -n "Report: found ${event[event_count]} event. " print "(unknown to this version)" while read -p msg_str[event_count] do case "${msg_str[event_count]}" in "end_of_message") break;; *);; esac done;; esac ((event_count=event_count+1)) done ((old_error_count=error_count)); IFS=" " while read -u3 val_one val_two val_tre do case $val_one in ---*) if [[ $fail_flag != -1 ]] then if [[ $fail_flag != 0 ]] then print -n "ERROR: command failed; it was " print "expected to succeed." ((error_count=error_count+1)) fi fi if (( error_count>old_error_count || pause_flag==1 )) then print "\nEnter q to quit, or press enter to continue..." read go case "$go" in q|Q) break;; *);; esac fi IFS=":" continue 2;; failure) if [[ $fail_flag = 0 ]] then print "ERROR: command succeeded; it was expected to fail." ((error_count=error_count+1)) else print "Note: command is expected to fail." fi fail_flag=-1;; *) case $val_two in matches) if [[ $(eval "print $"{$val_one}) = $(eval "print $"{$val_tre}) ]] then print "Report: $val_one and $val_tre match; both are " if [[ $(eval "print $"{$val_one}) = "" ]] then print "unset" else print "$(eval "print $"{$val_one})" fi else print -n "ERROR: $val_one was " if [[ $(eval "print $"{$val_one}) = "" ]] then print -n "unset " else print -n "equal to $(eval "print $"{$val_one})" fi print -n ", while $val_tre was " if [[ $(eval "print $"{$val_tre}) = "" ]] then print "unset." else print "equal to $(eval "print $"{$val_tre})." fi ((error_count=error_count+1)) fi;; store_in) eval ${val_tre}=$(eval "print $"{$val_one}) print -n "Report: value of ${val_one} copied into " print "${val_tre}.";; *) if [[ $(eval "print $"{$val_one}) = $val_two ]] then : else if [[ "$val_one" = event_count ]] then print -n "ERROR: expected $val_two event(s), " print "but found $event_count." else print -n "ERROR: $val_one was " if [[ $(eval "print $"{$val_one}) = "" ]] then print -n "unset " else print -n "equal to $(eval "print $"{$val_one}) " fi print "rather than $val_two as expected." fi ((error_count=error_count+1)) fi;; esac;; esac done if [[ $fail_flag != -1 ]] then if [[ $fail_flag != 0 ]] then print -n "ERROR: command failed; it was " print "expected to succeed." ((error_count=error_count+1)) fi fi if (( error_count>old_error_count || pause_flag==1 )) then print "\nTests complete. Press enter to quit..." read go fi break done # Close the datafile exec 3<&- # End the daemon kill $coproc wait $coproc clear if ((error_count==1)) then print "Test result: 1 error found." else print "Test result: $error_count errors found." fi