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 export CTDB_DBDIR="${CTDB_DBDIR_BASE}/volatile"
103 export CTDB_DBDIR_PERSISTENT="${CTDB_DBDIR_BASE}/persistent"
104 export CTDB_DBDIR_STATE="${CTDB_DBDIR_BASE}/state"
105 mkdir -p "$CTDB_DBDIR"
106 mkdir -p "$CTDB_DBDIR_PERSISTENT"
107 mkdir -p "$CTDB_DBDIR_STATE"
112 export FAKE_DATE_OUTPUT="$1"
117 export FAKE_TCP_LISTEN="$*"
120 tcp_port_listening ()
123 FAKE_TCP_LISTEN="${FAKE_TCP_LISTEN} ${_i}"
130 debug "Marking TCP port \"${_port}\" as not listening"
133 for _i in $FAKE_TCP_LISTEN ; do
134 if [ "$_i" = "$_port" ] ; then
140 FAKE_TCP_LISTEN="$_t"
145 export FAKE_NETSTAT_UNIX_LISTEN="$*"
148 unix_socket_listening ()
152 FAKE_NETSTAT_UNIX_LISTEN="${FAKE_NETSTAT_UNIX_LISTEN} ${_s}"
157 debug "Setting up shares (3 existing shares)"
158 # Create 3 fake shares/exports.
159 export FAKE_SHARES=""
160 for i in $(seq 1 3) ; do
161 _s="${EVENTSCRIPTS_TESTS_VAR_DIR}/shares/share${i}"
163 FAKE_SHARES="${FAKE_SHARES}${FAKE_SHARES:+ }${_s}"
169 # Mark some shares as non-existent
177 for _i in $FAKE_SHARES ; do
179 if [ $_n -ne "$_j" ] ; then
183 debug "Mark share $_n as missing share \"$_i\""
185 _t=$(printf "$_fmt" "${_i}")
186 _out="${_out}${_out:+${_nl}}${_t}"
196 FAKE_ETHTOOL_LINK_DOWN="${FAKE_NETWORK_STATE}/ethtool-link-down"
197 export FAKE_ETHTOOL_LINK_DOWN
198 mkdir -p "$FAKE_ETHTOOL_LINK_DOWN"
201 ethtool_interfaces_down ()
206 echo "Marking interface $_i DOWN for ethtool"
207 touch "${FAKE_ETHTOOL_LINK_DOWN}/${_i}"
211 ethtool_interfaces_up ()
216 echo "Marking interface $_i UP for ethtool"
217 rm -f "${FAKE_ETHTOOL_LINK_DOWN}/${_i}"
223 echo "# ip rule show"
227 while read _p _x _i _x _t ; do
228 # Remove trailing colon after priority/preference.
230 # Only remove rules that match our priority/preference.
231 [ "$CTDB_PER_IP_ROUTING_RULE_PREF" = "$_p" ] || continue
233 echo "# ip route show table $_t"
234 ip route show table "$_t"
238 # Copied from 13.per_ip_routing for now... so this is lazy testing :-(
239 ipv4_host_addr_to_net ()
244 # Convert the host address to an unsigned long by splitting out
245 # the octets and doing the math.
247 for _o in $(export IFS="." ; echo $_host) ; do
248 _host_ul=$(( ($_host_ul << 8) + $_o)) # work around Emacs color bug
251 # Calculate the mask and apply it.
252 _mask_ul=$(( 0xffffffff << (32 - $_maskbits) ))
253 _net_ul=$(( $_host_ul & $_mask_ul ))
255 # Now convert to a network address one byte at a time.
257 for _o in $(seq 1 4) ; do
258 _net="$(($_net_ul & 255))${_net:+.}${_net}"
259 _net_ul=$(($_net_ul >> 8))
262 echo "${_net}/${_maskbits}"
265 ######################################################################
271 export FAKE_CTDB_NUMNODES="${1:-3}"
272 echo "Setting up CTDB with ${FAKE_CTDB_NUMNODES} fake nodes"
275 # For now this creates the same public addresses each time. However,
276 # it could be made more flexible.
277 setup_public_addresses ()
279 _f="${CTDB_BASE}/public_addresses"
281 echo "Setting up public addresses in ${_f}"
294 # Needed for IP allocation
298 # Need to cope with ctdb_get_pnn(). If a test changes PNN then it
299 # needs to be using a different state directory, otherwise the wrong
300 # PNN can already be cached in the state directory.
303 export FAKE_CTDB_PNN="$1"
304 echo "Setting up PNN ${FAKE_CTDB_PNN}"
306 CTDB_SCRIPT_VARDIR="${EVENTSCRIPTS_TESTS_VAR_DIR}/scripts/${FAKE_CTDB_PNN}"
307 export CTDB_SCRIPT_VARDIR
308 mkdir -p "$CTDB_SCRIPT_VARDIR"
311 ctdb_get_interfaces ()
313 # The echo/subshell forces all the output onto 1 line.
314 echo $(ctdb ifaces -X | awk -F'|' 'FNR > 1 {print $2}')
317 ctdb_get_1_interface ()
319 _t=$(ctdb_get_interfaces)
323 # Print all public addresses as: interface IP maskbits
324 # Each line is suitable for passing to takeip/releaseip
325 ctdb_get_all_public_addresses ()
327 _f="${CTDB_BASE}/public_addresses"
328 while IFS="/$IFS" read _ip _maskbits _ifaces ; do
329 echo "$_ifaces $_ip $_maskbits"
333 # Print public addresses on this node as: interface IP maskbits
334 # Each line is suitable for passing to takeip/releaseip
335 ctdb_get_my_public_addresses ()
338 read _x # skip header line
340 while IFS="|" read _x _ip _x _iface _x ; do
341 [ -n "$_iface" ] || continue
342 while IFS="/$IFS" read _i _maskbits _x ; do
343 if [ "$_ip" = "$_i" ] ; then
344 echo $_iface $_ip $_maskbits
347 done <"${CTDB_BASE}/public_addresses"
352 # Prints the 1st public address as: interface IP maskbits
353 # This is suitable for passing to takeip/releaseip
354 ctdb_get_1_public_address ()
356 ctdb_get_my_public_addresses | { head -n 1 ; cat >/dev/null ; }
359 # Check the routes against those that are expected. $1 is the number
360 # of assigned IPs to use (<num>, all), defaulting to 1. If $2 is
361 # "default" then expect default routes to have been added.
365 _should_add_default="$2"
370 ctdb_get_my_public_addresses |
371 if [ "$_num_ips" = "all" ] ; then
374 { head -n "$_num_ips" ; cat >/dev/null ; }
376 while read _dev _ip _bits ; do
377 _net=$(ipv4_host_addr_to_net "$_ip" "$_bits")
378 _gw="${_net%.*}.254" # a dumb, calculated default
380 _policy_rules="${_policy_rules}
381 ${CTDB_PER_IP_ROUTING_RULE_PREF}: from $_ip lookup ctdb.$_ip "
382 _policy_routes="${_policy_routes}
383 # ip route show table ctdb.$_ip
384 $_net dev $_dev scope link "
386 if [ "$_should_add_default" = "default" ] ; then
387 _policy_routes="${_policy_routes}
388 default via $_gw dev $_dev "
394 0: from all lookup local ${_policy_rules}
395 32766: from all lookup main
396 32767: from all lookup default ${_policy_routes}
399 simple_test_command dump_routes
403 ######################################################################
408 _etc="$CTDB_SYS_ETCDIR" # shortcut for readability
409 for _c in "$_etc/sysconfig/nfs" "$_etc/default/nfs" "$_etc/ctdb/sysconfig/nfs" ; do
410 if [ -r "$_c" ] ; then
417 program_stack_trace ()
423 Stack trace for ${_prog}[${_pid}]:
424 [<ffffffff87654321>] fake_stack_trace_for_pid_${_pid}/stack+0x0/0xff
428 ######################################################################
430 # Result and test functions
433 ############################################################
437 die "setup() is not defined"
440 # Set some globals and print the summary.
445 _f=$(basename "$0" ".sh")
447 # Remaining format should be NN.service.event.NNN or NN.service.NNN:
455 script_dir="${CTDB_BASE}/events.d"
460 script_dir="${CTDB_BASE}/events.d"
465 script_dir="${CTDB_BASE}"
470 script_dir="${CTDB_BASE}"
473 [ -r "${script_dir}/${script}" ] || \
474 die "Internal error - unable to find script \"${script_dir}/${script}\""
476 printf "%-17s %-10s %-4s - %s\n\n" "$script" "$event" "$_num" "$desc"
478 _f="${TEST_SUBDIR}/scripts/${script}.sh"
479 if [ -r "$_f" ] ; then
486 # Run an eventscript once. The test passes if the return code and
487 # output match those required.
489 # Any args are passed to the eventscript.
493 [ -n "$event" ] || die 'simple_test: $event not set'
499 echo "Running script \"$script $event${args:+ }$args\""
506 ##################################################
507 CTDB_BASE="$CTDB_BASE"
508 CTDB_SYS_ETCDIR="$CTDB_SYS_ETCDIR"
509 ctdb client is "$(which ctdb)"
510 ip command is "$(which ip)"
514 script_test "${script_dir}/${script}" "$event" "$@"
522 # If something has previously failed then don't continue.
527 echo "=================================================="
531 simple_test_command ()