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 # The current implementation just assumes each non-comment line of
75 # input is a variable assignment and evals it with export prepended.
76 setup_script_options ()
78 _options="${script_dir}/${script%.script}.options"
82 # Source the options so that tests can use the variables
88 export CTDB_DBDIR="${EVENTSCRIPTS_TESTS_VAR_DIR}/db"
89 export CTDB_DBDIR_PERSISTENT="${CTDB_DBDIR}/persistent"
90 export CTDB_DBDIR_STATE="${CTDB_DBDIR}/state"
91 mkdir -p "$CTDB_DBDIR_PERSISTENT"
92 mkdir -p "$CTDB_DBDIR_STATE"
97 export FAKE_DATE_OUTPUT="$1"
102 export FAKE_TCP_LISTEN="$*"
105 tcp_port_listening ()
108 FAKE_TCP_LISTEN="${FAKE_TCP_LISTEN} ${_i}"
115 debug "Marking TCP port \"${_port}\" as not listening"
118 for _i in $FAKE_TCP_LISTEN ; do
119 if [ "$_i" = "$_port" ] ; then
125 FAKE_TCP_LISTEN="$_t"
130 export FAKE_NETSTAT_UNIX_LISTEN="$*"
133 unix_socket_listening ()
137 FAKE_NETSTAT_UNIX_LISTEN="${FAKE_NETSTAT_UNIX_LISTEN} ${_s}"
142 debug "Setting up shares (3 existing shares)"
143 # Create 3 fake shares/exports.
144 export FAKE_SHARES=""
145 for i in $(seq 1 3) ; do
146 _s="${EVENTSCRIPTS_TESTS_VAR_DIR}/shares/share${i}"
148 FAKE_SHARES="${FAKE_SHARES}${FAKE_SHARES:+ }${_s}"
154 # Mark some shares as non-existent
162 for _i in $FAKE_SHARES ; do
164 if [ $_n -ne "$_j" ] ; then
168 debug "Mark share $_n as missing share \"$_i\""
170 _t=$(printf "$_fmt" "${_i}")
171 _out="${_out}${_out:+${_nl}}${_t}"
181 FAKE_ETHTOOL_LINK_DOWN="${FAKE_NETWORK_STATE}/ethtool-link-down"
182 export FAKE_ETHTOOL_LINK_DOWN
183 mkdir -p "$FAKE_ETHTOOL_LINK_DOWN"
186 ethtool_interfaces_down ()
191 echo "Marking interface $_i DOWN for ethtool"
192 touch "${FAKE_ETHTOOL_LINK_DOWN}/${_i}"
196 ethtool_interfaces_up ()
201 echo "Marking interface $_i UP for ethtool"
202 rm -f "${FAKE_ETHTOOL_LINK_DOWN}/${_i}"
208 echo "# ip rule show"
212 while read _p _x _i _x _t ; do
213 # Remove trailing colon after priority/preference.
215 # Only remove rules that match our priority/preference.
216 [ "$CTDB_PER_IP_ROUTING_RULE_PREF" = "$_p" ] || continue
218 echo "# ip route show table $_t"
219 ip route show table "$_t"
223 # Copied from 13.per_ip_routing for now... so this is lazy testing :-(
224 ipv4_host_addr_to_net ()
229 # Convert the host address to an unsigned long by splitting out
230 # the octets and doing the math.
232 for _o in $(export IFS="." ; echo $_host) ; do
233 _host_ul=$(( ($_host_ul << 8) + $_o)) # work around Emacs color bug
236 # Calculate the mask and apply it.
237 _mask_ul=$(( 0xffffffff << (32 - $_maskbits) ))
238 _net_ul=$(( $_host_ul & $_mask_ul ))
240 # Now convert to a network address one byte at a time.
242 for _o in $(seq 1 4) ; do
243 _net="$(($_net_ul & 255))${_net:+.}${_net}"
244 _net_ul=$(($_net_ul >> 8))
247 echo "${_net}/${_maskbits}"
250 ######################################################################
256 export FAKE_CTDB_NUMNODES="${1:-3}"
257 echo "Setting up CTDB with ${FAKE_CTDB_NUMNODES} fake nodes"
260 # For now this creates the same public addresses each time. However,
261 # it could be made more flexible.
262 setup_public_addresses ()
264 _f="${CTDB_BASE}/public_addresses"
266 echo "Setting up public addresses in ${_f}"
279 # Needed for IP allocation
283 # Need to cope with ctdb_get_pnn(). If a test changes PNN then it
284 # needs to be using a different state directory, otherwise the wrong
285 # PNN can already be cached in the state directory.
288 export FAKE_CTDB_PNN="$1"
289 echo "Setting up PNN ${FAKE_CTDB_PNN}"
291 CTDB_SCRIPT_VARDIR="${EVENTSCRIPTS_TESTS_VAR_DIR}/scripts/${FAKE_CTDB_PNN}"
292 export CTDB_SCRIPT_VARDIR
293 mkdir -p "$CTDB_SCRIPT_VARDIR"
296 ctdb_get_interfaces ()
298 # The echo/subshell forces all the output onto 1 line.
299 echo $(ctdb ifaces -X | awk -F'|' 'FNR > 1 {print $2}')
302 ctdb_get_1_interface ()
304 _t=$(ctdb_get_interfaces)
308 # Print all public addresses as: interface IP maskbits
309 # Each line is suitable for passing to takeip/releaseip
310 ctdb_get_all_public_addresses ()
312 _f="${CTDB_BASE}/public_addresses"
313 while IFS="/$IFS" read _ip _maskbits _ifaces ; do
314 echo "$_ifaces $_ip $_maskbits"
318 # Print public addresses on this node as: interface IP maskbits
319 # Each line is suitable for passing to takeip/releaseip
320 ctdb_get_my_public_addresses ()
323 read _x # skip header line
325 while IFS="|" read _x _ip _x _iface _x ; do
326 [ -n "$_iface" ] || continue
327 while IFS="/$IFS" read _i _maskbits _x ; do
328 if [ "$_ip" = "$_i" ] ; then
329 echo $_iface $_ip $_maskbits
332 done <"${CTDB_BASE}/public_addresses"
337 # Prints the 1st public address as: interface IP maskbits
338 # This is suitable for passing to takeip/releaseip
339 ctdb_get_1_public_address ()
341 ctdb_get_my_public_addresses | { head -n 1 ; cat >/dev/null ; }
344 # Check the routes against those that are expected. $1 is the number
345 # of assigned IPs to use (<num>, all), defaulting to 1. If $2 is
346 # "default" then expect default routes to have been added.
350 _should_add_default="$2"
355 ctdb_get_my_public_addresses |
356 if [ "$_num_ips" = "all" ] ; then
359 { head -n "$_num_ips" ; cat >/dev/null ; }
361 while read _dev _ip _bits ; do
362 _net=$(ipv4_host_addr_to_net "$_ip" "$_bits")
363 _gw="${_net%.*}.254" # a dumb, calculated default
365 _policy_rules="${_policy_rules}
366 ${CTDB_PER_IP_ROUTING_RULE_PREF}: from $_ip lookup ctdb.$_ip "
367 _policy_routes="${_policy_routes}
368 # ip route show table ctdb.$_ip
369 $_net dev $_dev scope link "
371 if [ "$_should_add_default" = "default" ] ; then
372 _policy_routes="${_policy_routes}
373 default via $_gw dev $_dev "
379 0: from all lookup local ${_policy_rules}
380 32766: from all lookup main
381 32767: from all lookup default ${_policy_routes}
384 simple_test_command dump_routes
388 ######################################################################
393 _etc="$CTDB_SYS_ETCDIR" # shortcut for readability
394 for _c in "$_etc/sysconfig/nfs" "$_etc/default/nfs" "$_etc/ctdb/sysconfig/nfs" ; do
395 if [ -r "$_c" ] ; then
402 program_stack_trace ()
408 Stack trace for ${_prog}[${_pid}]:
409 [<ffffffff87654321>] fake_stack_trace_for_pid_${_pid}/stack+0x0/0xff
413 ######################################################################
415 # Result and test functions
418 ############################################################
422 die "setup() is not defined"
425 # Set some globals and print the summary.
430 _f=$(basename "$0" ".sh")
432 # Remaining format should be NN.service.event.NNN or NN.service.NNN:
440 script_dir="${CTDB_BASE}/events.d"
445 script_dir="${CTDB_BASE}/events.d"
450 script_dir="${CTDB_BASE}"
455 script_dir="${CTDB_BASE}"
458 [ -r "${script_dir}/${script}" ] || \
459 die "Internal error - unable to find script \"${script_dir}/${script}\""
461 printf "%-17s %-10s %-4s - %s\n\n" "$script" "$event" "$_num" "$desc"
463 _f="${TEST_SUBDIR}/scripts/${script}.sh"
464 if [ -r "$_f" ] ; then
471 # Run an eventscript once. The test passes if the return code and
472 # output match those required.
474 # Any args are passed to the eventscript.
478 [ -n "$event" ] || die 'simple_test: $event not set'
484 echo "Running script \"$script $event${args:+ }$args\""
491 ##################################################
492 CTDB_BASE="$CTDB_BASE"
493 CTDB_SYS_ETCDIR="$CTDB_SYS_ETCDIR"
494 ctdb client is "$(which ctdb)"
495 ip command is "$(which ip)"
499 script_test "${script_dir}/${script}" "$event" "$@"
507 # If something has previously failed then don't continue.
512 echo "=================================================="
516 simple_test_command ()