bringing in testkit tools
[feisty_meow.git] / testkit / library / helper_methods.sh
1 #!/bin/bash
2
3 # useful functions that are somewhat general.  these are not needed for
4 # the basic setup of the test environment, but they are used by other
5 # test and tool functions and also by specific tests.
6 #
7 # Author: Chris Koeritz
8
9 # prints out a timestamp with the current date and time up to seconds.
10 function date_string()
11 {
12   date +"%Y_%b_%e_%H%M_%S" | sed -e 's/ //g'
13 }
14
15 # prints out the timestamp in a somewhat readable way.
16 function readable_date_string()
17 {
18   date +"%Y-%m-%d %T"
19 }
20
21 ########
22 # (donated by the feisty meow scripts at http://feistymeow.org)
23
24   function is_array() {
25     [[ "$(declare -p $1)" =~ "declare -a" ]]
26   }
27
28   function is_alias() {
29     alias $1 &>/dev/null
30     return $?
31   }
32
33   # displays the value of a variable in bash friendly format.
34   function var() {
35     HOLDIFS="$IFS"
36     IFS=""
37     while true; do
38       local varname="$1"; shift
39       if [ -z "$varname" ]; then
40         break
41       fi
42
43       if is_alias "$varname"; then
44 #echo found $varname is alias
45         local tmpfile="$(mktemp $TMP/aliasout.XXXXXX)"
46         alias $varname | sed -e 's/.*=//' >$tmpfile
47         echo "alias $varname=$(cat $tmpfile)"
48         \rm $tmpfile
49       elif [ -z "${!varname}" ]; then
50         echo "$varname undefined"
51       else
52         if is_array "$varname"; then
53 #echo found $varname is array var 
54           local temparray
55           eval temparray="(\${$varname[@]})"
56           echo "$varname=(${temparray[@]})"
57 #hmmm: would be nice to print above with elements enclosed in quotes, so that we can properly
58 # see ones that have spaces in them.
59         else
60 #echo found $varname is simple
61           echo "$varname=${!varname}"
62         fi
63       fi
64     done
65     IFS="$HOLDIFS"
66   }
67 ########
68
69 # given a file name and a phrase to look for, this replaces all instances of
70 # it with a piece of replacement text.  note that slashes are okay in the two
71 # text pieces, but we are using pound signs as the regular expression
72 # separator; phrases including the octothorpe (#) will cause syntax errors.
73 function replace_phrase_in_file()
74 {
75   local file="$1"; shift
76   local phrase="$1"; shift
77   local replacement="$1"; shift
78   if [ -z "$file" -o -z "$phrase" ]; then
79     echo "replace_phrase_in_file: needs a filename, a phrase to replace, and the"
80     echo "text to replace that phrase with."
81     return 1
82   fi
83   sed -i -e "s%$phrase%$replacement%g" "$file"
84 }
85
86 # prints an error message (from parameters) and exits if the previous command failed.
87 function check_if_failed()
88 {
89   if [ $? -ne 0 ]; then
90     echo Step failed: $*
91     exit 1
92   fi
93 }
94
95 # takes a first parameter that is the name for a combined error and output log,
96 # and then runs all the other parameters as a command.
97 function logged_command()
98 {
99   local my_output="$1"; shift
100 #  echo "logged_command args: $(printf -- "[%s] " "${@}")"
101   eval "${@}" >>"$my_output" 2>&1
102   local retval=$?
103   if [ $retval == 0 ]; then
104     # good so far, but check for more subtle ways of failing; if there is
105     # an occurrence of our fail message in the output, that also indicates
106     # the command did not succeed.
107     grep "\[FAILURE\]" $my_output
108     # we do not want to see that phrase in the log.
109     if [ $? != 0 ]; then
110       return 0  # fine exit, can ignore log.
111     fi
112   fi
113   if [[ ! "$my_output" =~ .*fuse_output.* ]]; then
114     # this was a failure, so we need to see the log.
115     # fuse errors currently don't count since they are multifarious.
116     cat "$my_output"
117   fi
118   return 1
119 }
120
121 # runs an arbitrary command.  if the command fails, then the output from it is
122 # displayed and an error code is returned.  otherwise the output is discarded.
123 function run_any_command()
124 {
125   local my_output="$(mktemp $TEST_TEMP/test_logs/out_run_any_cmd_$(date_string).XXXXXX)"
126   logged_command "$my_output" "${@}"
127   local retval=$?
128   # make the external version of the log file available.  if we're multiplexing users,
129   # this will be clobbered constantly, which is why we used unique names above.
130   \cp -f "$my_output" "$TESTKIT_OUTPUT_FILE"
131   # then add the logging results to our huge mongo log of all actions.
132   echo >> "$CONGLOMERATED_TESTKIT_OUTPUT"
133   echo "$(readable_date_string) log from: $my_output" >> "$CONGLOMERATED_TESTKIT_OUTPUT"
134   echo "=======" >> "$CONGLOMERATED_TESTKIT_OUTPUT"
135   cat "$my_output" >> "$CONGLOMERATED_TESTKIT_OUTPUT"
136   echo "=======" >> "$CONGLOMERATED_TESTKIT_OUTPUT"
137   # and now remove the tiny individual log file so we don't litter.
138   \rm -f "$my_output"
139   return $retval
140 }
141
142
143 # returns 0 if there should be no problems using fuse, or non-zero if this platform
144 # does not currently support fuse.
145 function fuse_supported()
146 {
147   local retval=0
148   local platform="$(uname -a | tr A-Z a-z)"
149   if [[ $platform =~ .*darwin.* ]]; then retval=1; fi
150   if [[ $platform =~ .*cygwin.* ]]; then retval=1; fi
151   if [[ $platform =~ .*ming.* ]]; then retval=1; fi
152   return $retval
153 }
154
155 # returns 0 if there should be no problems creating links in the file system,
156 # or non-zero if this platform does not support symbolic links.
157 function links_supported()
158 {
159   local retval=0
160   local platform="$(uname -a | tr A-Z a-z)"
161   if [[ $platform =~ .*cygwin.* ]]; then retval=1; fi
162   if [[ $platform =~ .*ming.* ]]; then retval=1; fi
163   return $retval
164 }
165
166 # Create a test directory (in the first parameter) with $2 subdirectories,
167 # each with $3 subdirs, each with $4 files.
168 fan_out_directories()
169 {
170   local dir_name="$1"; shift
171   local top_count=$1; shift
172   local mid_count=$1; shift
173   local file_count=$1; shift
174   mkdir "$dir_name"
175   for (( di=0 ; di<$top_count ; di++ )); do
176     mkdir "$dir_name"/sub$di
177     for (( dj=0 ; dj<$mid_count ; dj++ )); do
178       mkdir "$dir_name"/sub$di/sub$dj
179       for (( dk=0 ; dk<$file_count ; dk++ )); do
180         echo "file $di$dj$dk" > "$dir_name"/sub$di/sub$dj/file$di$dj$dk
181       done
182     done
183   done
184 }
185 ##############
186
187 # copied from open source codebase at: http://feistymeow.org with permission of author (chris koeritz),
188 # assigned apache ASL license for this usage.
189   # locates a process given a search pattern to match in the process list.
190   # supports a single command line flag style parameter of "-u USERNAME";
191   # if the -u flag is found, a username is expected afterwards, and only the
192   # processes of that user are considered.
193   function psfind() {
194     local -a patterns=("${@}")
195 #echo ====
196 #echo patterns list is: "${patterns[@]}"
197 #echo ====
198
199     local user_flag
200     if [ "${patterns[0]}" == "-u" ]; then
201       user_flag="-u ${patterns[1]}" 
202 #echo "found a -u parm and user=${patterns[1]}" 
203       # void the two elements with that user flag so we don't use them as patterns.
204       unset patterns[0] patterns[1]
205     else
206       # select all users.
207       user_flag="-e"
208     fi
209
210     local PID_DUMP="$(mktemp "$TMP/zz_pidlist.XXXXXX")"
211     local -a PIDS_SOUGHT
212
213     if [ "$OS" == "Windows_NT" ]; then
214       # gets cygwin's (god awful) ps to show windoze processes also.
215       local EXTRA_DOZER_FLAGS="-W"
216       # pattern to use for peeling off the process numbers.
217       local pid_finder_pattern='s/ *\([0-9][0-9]*\) *.*$/\1/p'
218
219     else
220       # flags which clean up the output on unixes, which apparently cygwin
221       # doesn't count as.  their crappy specialized ps doesn't support this.
222       local EXTRA_UNIX_FLAGS="-o pid,args"
223       # pattern to use for peeling off the process numbers.
224       local pid_finder_pattern='s/^[[:space:]]*\([0-9][0-9]*\).*$/\1/p'
225     fi
226
227     /bin/ps $EXTRA_DOZER_FLAGS $EXTRA_UNIX_FLAGS $user_flag | tail -n +2 >$PID_DUMP
228 #echo ====
229 #echo got all this stuff in the pid dump file:
230 #cat $PID_DUMP
231 #echo ====
232
233     # search for the pattern the user wants to find, and just pluck the process
234     # ids out of the results.
235     local i
236     for i in "${patterns[@]}"; do
237       PIDS_SOUGHT+=($(cat $PID_DUMP \
238         | grep -i "$i" \
239         | sed -n -e "$pid_finder_pattern"))
240     done
241 #echo ====
242 #echo pids sought list became:
243 #echo "${PIDS_SOUGHT[@]}"
244 #echo ====
245
246     if [ ${#PIDS_SOUGHT[*]} -ne 0 ]; then
247       local PIDS_SOUGHT2=$(printf -- '%s\n' ${PIDS_SOUGHT[@]} | sort | uniq)
248       PIDS_SOUGHT=()
249       PIDS_SOUGHT=${PIDS_SOUGHT2[*]}
250       echo ${PIDS_SOUGHT[*]}
251     fi
252     /bin/rm $PID_DUMP
253   }
254   
255
256 #######
257
258 # tests the supposed fuse mount that is passed in as the first parameter.
259 function test_fuse_mount()
260 {
261   local mount_point="$1"; shift
262   local trunc_mount="$(basename "$(dirname $mount_point)").$(basename "$mount_point")"
263
264   checkMount="$(mount)"
265 #echo "checkmount is: '$checkMount'"
266 #echo "mount point seeking is: '$trunc_mount'"
267   local retval=1
268   if [[ "$checkMount" =~ .*$trunc_mount.* ]]; then
269 #echo found the mount in the list
270     retval=0
271   fi
272   if [ $retval -ne 0 ]; then
273     echo "Finding mount point '$trunc_mount' failed."
274     return 1
275   fi
276   ls -l "$mount_point" &>/dev/null
277   return $?
278 }
279
280 #######
281
282 # also borrowed from feisty meow scripts...  by consent of author (chris koeritz).
283
284   # is this the Mac OS X operating system?
285   function isMacOSX()
286   {
287     if [ ! -z "$(echo $OSTYPE | grep -i darwin)" ]; then
288       true
289     else
290       false
291     fi
292   }
293
294   # switches from a /X/path form to an X:/ form.  this also processes cygwin paths.
295   function unix_to_dos_path() {
296     # we usually remove dos slashes in favor of forward slashes.
297     if [ ! -z "$SERIOUS_SLASH_TREATMENT" ]; then
298       # unless this flag is set, in which case we force dos slashes.
299       echo "$1" | sed -e 's/\\/\//g' | sed -e 's/\/cygdrive//' | sed -e 's/\/\([a-zA-Z]\)\/\(.*\)/\1:\/\2/' | sed -e 's/\//\\/g'
300     else
301       echo "$1" | sed -e 's/\\/\//g' | sed -e 's/\/cygdrive//' | sed -e 's/\/\([a-zA-Z]\)\/\(.*\)/\1:\/\2/'
302     fi
303   }
304   
305   # switches from an X:/ form to an /X/path form.
306   function dos_to_unix_path() {
307     # we always remove dos slashes in favor of forward slashes.
308     echo "$1" | sed -e 's/\\/\//g' | sed -e 's/\([a-zA-Z]\):\/\(.*\)/\/\1\/\2/'
309   }
310
311 #######
312