1 # Hey Emacs, this is a -*- shell-script -*- !!! :-)
4 # Augment PATH with relevant stubs/ directories.
7 stubs_dir="${TEST_SUBDIR}/stubs"
8 [ -d "${stubs_dir}" ] || die "Failed to locate stubs/ subdirectory"
10 # Make the path absolute for tests that change directory
13 *) stubs_dir="${PWD}/${stubs_dir}" ;;
16 # Use stubs as helpers
17 export CTDB_HELPER_BINDIR="$stubs_dir"
19 PATH="${stubs_dir}:${PATH}"
24 [ -n "$TEST_VAR_DIR" ] || die "TEST_VAR_DIR unset"
25 export EVENTSCRIPTS_TESTS_VAR_DIR="${TEST_VAR_DIR}/unit_eventscripts"
26 if [ -d "$EVENTSCRIPTS_TESTS_VAR_DIR" ] ; then
27 rm -r "$EVENTSCRIPTS_TESTS_VAR_DIR"
29 mkdir -p "$EVENTSCRIPTS_TESTS_VAR_DIR"
31 export CTDB_LOGGING="file:${EVENTSCRIPTS_TESTS_VAR_DIR}/log.ctdb"
32 touch "${CTDB_LOGGING#file:}" || \
33 die "Unable to setup logging for \"$CTDB_LOGGING\""
35 if [ -d "${TEST_SUBDIR}/etc" ] ; then
36 cp -a "${TEST_SUBDIR}/etc" "$EVENTSCRIPTS_TESTS_VAR_DIR"
37 export CTDB_SYS_ETCDIR="${EVENTSCRIPTS_TESTS_VAR_DIR}/etc"
39 die "Unable to setup \$CTDB_SYS_ETCDIR"
42 setup_ctdb_base "$EVENTSCRIPTS_TESTS_VAR_DIR" "etc-ctdb" \
46 nfs-linux-kernel-callout \
49 export FAKE_CTDB_STATE="$EVENTSCRIPTS_TESTS_VAR_DIR/fake-ctdb"
50 mkdir -p "$FAKE_CTDB_STATE"
52 export FAKE_NETWORK_STATE="$EVENTSCRIPTS_TESTS_VAR_DIR/fake-network-state"
53 mkdir -p "$FAKE_NETWORK_STATE"
55 ######################################################################
57 if "$TEST_VERBOSE" ; then
70 ######################################################################
72 # General setup fakery
74 # Default is to use script name with ".options" appended. With
75 # arguments, this can specify an alternate script name (and
77 setup_script_options ()
79 if [ $# -eq 2 ] ; then
81 elif [ $# -eq 0 ] ; then
84 die "usage: setup_script_options [ component script ]"
87 if [ -n "$_script" ] ; then
88 _options="${CTDB_BASE}/events.d/${_script}.options"
90 _options="${script_dir}/${script%.script}.options"
95 # Source the options so that tests can use the variables
101 export CTDB_DBDIR_BASE="${EVENTSCRIPTS_TESTS_VAR_DIR}/db"
102 CTDB_DBDIR="${CTDB_DBDIR_BASE}/volatile"
103 CTDB_DBDIR_PERSISTENT="${CTDB_DBDIR_BASE}/persistent"
104 CTDB_DBDIR_STATE="${CTDB_DBDIR_BASE}/state"
105 cat >>"${CTDB_BASE}/ctdb.conf" <<EOF
107 volatile database directory = ${CTDB_DBDIR}
108 persistent database directory = ${CTDB_DBDIR_PERSISTENT}
109 state database directory = ${CTDB_DBDIR_STATE}
111 mkdir -p "$CTDB_DBDIR"
112 mkdir -p "$CTDB_DBDIR_PERSISTENT"
113 mkdir -p "$CTDB_DBDIR_STATE"
118 export FAKE_DATE_OUTPUT="$1"
123 export FAKE_TCP_LISTEN="$*"
126 tcp_port_listening ()
129 FAKE_TCP_LISTEN="${FAKE_TCP_LISTEN} ${_i}"
136 debug "Marking TCP port \"${_port}\" as not listening"
139 for _i in $FAKE_TCP_LISTEN ; do
140 if [ "$_i" = "$_port" ] ; then
146 FAKE_TCP_LISTEN="$_t"
151 export FAKE_NETSTAT_UNIX_LISTEN="$*"
154 unix_socket_listening ()
158 FAKE_NETSTAT_UNIX_LISTEN="${FAKE_NETSTAT_UNIX_LISTEN} ${_s}"
163 debug "Setting up shares (3 existing shares)"
164 # Create 3 fake shares/exports.
165 export FAKE_SHARES=""
166 for i in $(seq 1 3) ; do
167 _s="${EVENTSCRIPTS_TESTS_VAR_DIR}/shares/share${i}"
169 FAKE_SHARES="${FAKE_SHARES}${FAKE_SHARES:+ }${_s}"
175 # Mark some shares as non-existent
183 for _i in $FAKE_SHARES ; do
185 if [ $_n -ne "$_j" ] ; then
189 debug "Mark share $_n as missing share \"$_i\""
191 _t=$(printf "$_fmt" "${_i}")
192 _out="${_out}${_out:+${_nl}}${_t}"
202 FAKE_ETHTOOL_LINK_DOWN="${FAKE_NETWORK_STATE}/ethtool-link-down"
203 export FAKE_ETHTOOL_LINK_DOWN
204 mkdir -p "$FAKE_ETHTOOL_LINK_DOWN"
207 ethtool_interfaces_down ()
212 echo "Marking interface $_i DOWN for ethtool"
213 touch "${FAKE_ETHTOOL_LINK_DOWN}/${_i}"
217 ethtool_interfaces_up ()
222 echo "Marking interface $_i UP for ethtool"
223 rm -f "${FAKE_ETHTOOL_LINK_DOWN}/${_i}"
229 echo "# ip rule show"
233 while read _p _x _i _x _t ; do
234 # Remove trailing colon after priority/preference.
236 # Only remove rules that match our priority/preference.
237 [ "$CTDB_PER_IP_ROUTING_RULE_PREF" = "$_p" ] || continue
239 echo "# ip route show table $_t"
240 ip route show table "$_t"
244 # Copied from 13.per_ip_routing for now... so this is lazy testing :-(
245 ipv4_host_addr_to_net ()
250 # Convert the host address to an unsigned long by splitting out
251 # the octets and doing the math.
253 for _o in $(export IFS="." ; echo $_host) ; do
254 _host_ul=$(( ($_host_ul << 8) + $_o)) # work around Emacs color bug
257 # Calculate the mask and apply it.
258 _mask_ul=$(( 0xffffffff << (32 - $_maskbits) ))
259 _net_ul=$(( $_host_ul & $_mask_ul ))
261 # Now convert to a network address one byte at a time.
263 for _o in $(seq 1 4) ; do
264 _net="$(($_net_ul & 255))${_net:+.}${_net}"
265 _net_ul=$(($_net_ul >> 8))
268 echo "${_net}/${_maskbits}"
271 ######################################################################
277 export FAKE_CTDB_NUMNODES="${1:-3}"
278 echo "Setting up CTDB with ${FAKE_CTDB_NUMNODES} fake nodes"
281 # For now this creates the same public addresses each time. However,
282 # it could be made more flexible.
283 setup_public_addresses ()
285 _f="${CTDB_BASE}/public_addresses"
287 echo "Setting up public addresses in ${_f}"
300 # Needed for IP allocation
304 # Need to cope with ctdb_get_pnn(). If a test changes PNN then it
305 # needs to be using a different state directory, otherwise the wrong
306 # PNN can already be cached in the state directory.
309 export FAKE_CTDB_PNN="$1"
310 echo "Setting up PNN ${FAKE_CTDB_PNN}"
312 CTDB_SCRIPT_VARDIR="${EVENTSCRIPTS_TESTS_VAR_DIR}/scripts/${FAKE_CTDB_PNN}"
313 export CTDB_SCRIPT_VARDIR
314 mkdir -p "$CTDB_SCRIPT_VARDIR"
317 ctdb_get_interfaces ()
319 # The echo/subshell forces all the output onto 1 line.
320 echo $(ctdb ifaces -X | awk -F'|' 'FNR > 1 {print $2}')
323 ctdb_get_1_interface ()
325 _t=$(ctdb_get_interfaces)
329 # Print all public addresses as: interface IP maskbits
330 # Each line is suitable for passing to takeip/releaseip
331 ctdb_get_all_public_addresses ()
333 _f="${CTDB_BASE}/public_addresses"
334 while IFS="/$IFS" read _ip _maskbits _ifaces ; do
335 echo "$_ifaces $_ip $_maskbits"
339 # Print public addresses on this node as: interface IP maskbits
340 # Each line is suitable for passing to takeip/releaseip
341 ctdb_get_my_public_addresses ()
344 read _x # skip header line
346 while IFS="|" read _x _ip _x _iface _x ; do
347 [ -n "$_iface" ] || continue
348 while IFS="/$IFS" read _i _maskbits _x ; do
349 if [ "$_ip" = "$_i" ] ; then
350 echo $_iface $_ip $_maskbits
353 done <"${CTDB_BASE}/public_addresses"
358 # Prints the 1st public address as: interface IP maskbits
359 # This is suitable for passing to takeip/releaseip
360 ctdb_get_1_public_address ()
362 ctdb_get_my_public_addresses | { head -n 1 ; cat >/dev/null ; }
365 # Check the routes against those that are expected. $1 is the number
366 # of assigned IPs to use (<num>, all), defaulting to 1. If $2 is
367 # "default" then expect default routes to have been added.
371 _should_add_default="$2"
376 ctdb_get_my_public_addresses |
377 if [ "$_num_ips" = "all" ] ; then
380 { head -n "$_num_ips" ; cat >/dev/null ; }
382 while read _dev _ip _bits ; do
383 _net=$(ipv4_host_addr_to_net "$_ip" "$_bits")
384 _gw="${_net%.*}.254" # a dumb, calculated default
386 _policy_rules="${_policy_rules}
387 ${CTDB_PER_IP_ROUTING_RULE_PREF}: from $_ip lookup ctdb.$_ip "
388 _policy_routes="${_policy_routes}
389 # ip route show table ctdb.$_ip
390 $_net dev $_dev scope link "
392 if [ "$_should_add_default" = "default" ] ; then
393 _policy_routes="${_policy_routes}
394 default via $_gw dev $_dev "
400 0: from all lookup local ${_policy_rules}
401 32766: from all lookup main
402 32767: from all lookup default ${_policy_routes}
405 simple_test_command dump_routes
409 ######################################################################
414 _etc="$CTDB_SYS_ETCDIR" # shortcut for readability
415 for _c in "$_etc/sysconfig/nfs" "$_etc/default/nfs" "$_etc/ctdb/sysconfig/nfs" ; do
416 if [ -r "$_c" ] ; then
423 program_stack_trace ()
429 Stack trace for ${_prog}[${_pid}]:
430 [<ffffffff87654321>] fake_stack_trace_for_pid_${_pid}/stack+0x0/0xff
434 ######################################################################
436 # Result and test functions
439 ############################################################
443 die "setup() is not defined"
446 # Set some globals and print the summary.
451 _f=$(basename "$0" ".sh")
453 # Remaining format should be NN.service.event.NNN or NN.service.NNN:
461 script_dir="${CTDB_BASE}/events.d"
466 script_dir="${CTDB_BASE}/events.d"
471 script_dir="${CTDB_BASE}"
476 script_dir="${CTDB_BASE}"
479 [ -r "${script_dir}/${script}" ] || \
480 die "Internal error - unable to find script \"${script_dir}/${script}\""
482 printf "%-17s %-10s %-4s - %s\n\n" "$script" "$event" "$_num" "$desc"
484 _f="${TEST_SUBDIR}/scripts/${script}.sh"
485 if [ -r "$_f" ] ; then
492 # Run an eventscript once. The test passes if the return code and
493 # output match those required.
495 # Any args are passed to the eventscript.
499 [ -n "$event" ] || die 'simple_test: $event not set'
505 echo "Running script \"$script $event${args:+ }$args\""
512 ##################################################
513 CTDB_BASE="$CTDB_BASE"
514 CTDB_SYS_ETCDIR="$CTDB_SYS_ETCDIR"
515 ctdb client is "$(which ctdb)"
516 ip command is "$(which ip)"
520 script_test "${script_dir}/${script}" "$event" "$@"
528 # If something has previously failed then don't continue.
533 echo "=================================================="
537 simple_test_command ()