Page Menu
Home
ClusterLabs Projects
Search
Configure Global Search
Log In
Files
F1841849
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
16 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/xml/regression.sh b/xml/regression.sh
index a021c78ae1..00e325d913 100755
--- a/xml/regression.sh
+++ b/xml/regression.sh
@@ -1,568 +1,569 @@
#!/bin/sh
# Copyright 2018 Red Hat, Inc.
# Author: Jan Pokorny <jpokorny@redhat.com>
# Part of pacemaker project
# SPDX-License-Identifier: GPL-2.0-or-later
set -eu
# $1=reference (can be '-' for stdin), $2=investigated
# alt.: wdiff, colordiff, ...
DIFF=${DIFF:-diff}
DIFFOPTS=${DIFFOPTS--u}
DIFFPAGER=${DIFFPAGER:-less -LRX}
# $1=schema, $2=validated
# alt.: jing -i
RNGVALIDATOR=${RNGVALIDATOR:-xmllint --noout --relaxng}
# $1=stylesheet, $2=source
# alt.: Xalan, saxon (note: only validates reliably with -B)
_xalan_wrapper() {
{ Xalan "$2" "$1" 2>&1 1>&3 \
| sed -e '/^Source tree node.*$/d' \
-e 's|^XSLT message: \(.*\) (Occurred.*)|\1|'; } 3>&1- 1>&2
}
# filtered out message: https://bugzilla.redhat.com/show_bug.cgi?id=1577367
_saxon_wrapper() {
{ saxon "-xsl:$1" "-s:$2" -versionmsg:off 2>&1 1>&3 \
| sed -e '/^Cannot find CatalogManager.properties$/d'; } 3>&1- 1>&2
}
#_xalan_wrapper() { Xalan $2 $1; }
XSLTPROCESSOR=${XSLTPROCESSOR:-xsltproc}
test "${XSLTPROCESSOR}" != Xalan || XSLTPROCESSOR=_xalan_wrapper
test "${XSLTPROCESSOR}" != saxon || XSLTPROCESSOR=_saxon_wrapper
tests= # test* names (should go first) here will become preselected default
#
# commons
#
emit_result() {
_er_howmany=${1:?} # how many errors (0/anything else incl. strings)
_er_subject=${2:?}
_er_prefix=${3-}
test -z "${_er_prefix}" || _er_prefix="${_er_prefix}: "
if test "${_er_howmany}" = 0; then
printf "%s%s finished OK\n" "${_er_prefix}" "${_er_subject}"
else
printf "%s%s encountered ${_er_howmany} errors\n" \
"${_er_prefix}" "${_er_subject}"
fi
}
emit_error() {
_ee_msg=${1:?}
printf "%s\n" "${_ee_msg}" >&2
}
# returns 1 + floor of base 2 logaritm for _lo0r_i in 1...255,
# or 0 for _lo0r_i = 0
log2_or_0_return() {
_lo0r_i=${1:?}
return $(((!(_lo0r_i >> 1) && _lo0r_i) * 1 \
+ (!(_lo0r_i >> 2) && _lo0r_i & (1 << 1)) * 2 \
+ (!(_lo0r_i >> 3) && _lo0r_i & (1 << 2)) * 3 \
+ (!(_lo0r_i >> 4) && _lo0r_i & (1 << 3)) * 4 \
+ (!(_lo0r_i >> 5) && _lo0r_i & (1 << 4)) * 5 \
+ (!(_lo0r_i >> 6) && _lo0r_i & (1 << 5)) * 6 \
+ (!(_lo0r_i >> 7) && _lo0r_i & (1 << 6)) * 7 \
+ !!(_lo0r_i >> 7) * 7 ))
}
# rough addition of two base 2 logarithms
log2_or_0_add() {
_lo0a_op1=${1:?}
_lo0a_op2=${2:?}
if test ${_lo0a_op1} -gt ${_lo0a_op2}; then
return ${_lo0a_op1}
elif test ${_lo0a_op2} -gt ${_lo0a_op1}; then
return ${_lo0a_op2}
elif test ${_lo0a_op1} -gt 0; then
return $((_lo0a_op1 + 1))
else
return ${_lo0a_op1}
fi
}
#
# test phases
#
# -r ... whether to remove referential files as well
# stdin: input file per line
test_cleaner() {
_tc_cleanref=0
while test $# -gt 0; do
case "$1" in
-r) _tc_cleanref=1;;
esac
shift
done
while read _tc_origin; do
_tc_origin=${_tc_origin%.*}
rm -f "${_tc_origin}.up" "${_tc_origin}.up.err"
rm -f "$(dirname "${_tc_origin}")/.$(basename "${_tc_origin}").up"
test ${_tc_cleanref} -eq 0 \
|| rm -f "${_tc_origin}.ref" "${_tc_origin}.ref.err"
done
}
test_selfcheck() {
_tsc_template=
_tsc_validator=
while test $# -gt 0; do
case "$1" in
-o=*) _tsc_template="${1#-o=}";;
esac
shift
done
_tsc_validator="${_tsc_template:?}"
_tsc_validator="cibtr-${_tsc_validator%%.*}.rng"
_tsc_template="upgrade-${_tsc_template}.xsl"
# check schema (sub-grammar) for custom transformation mapping alone
${RNGVALIDATOR} 'http://relaxng.org/relaxng.rng' "${_tsc_validator}"
# check the overall XSLT per the main grammar + said sub-grammar
${RNGVALIDATOR} "xslt_${_tsc_validator}" "${_tsc_template}"
}
test_explanation() {
_tsc_template=
while test $# -gt 0; do
case "$1" in
-o=*) _tsc_template="upgrade-${1#-o=}.xsl";;
esac
shift
done
${XSLTPROCESSOR} upgrade-detail.xsl "${_tsc_template}"
}
# stdout: filename of the transformed file
test_runner_upgrade() {
_tru_template=${1:?}
_tru_source=${2:?} # filename
_tru_mode=${3:?} # extra modes wrt. "referential" outcome, see below
_tru_ref="${_tru_source%.*}.ref"
{ test "$((_tru_mode & (1 << 0)))" -ne 0 \
|| test -f "${_tru_ref}.err"; } \
&& _tru_ref_err="${_tru_ref}.err" || _tru_ref_err=/dev/null
_tru_target="${_tru_source%.*}.up"
_tru_target_err="${_tru_target}.err"
if test $((_tru_mode & (1 << 2))) -eq 0; then
${XSLTPROCESSOR} "${_tru_template}" "${_tru_source}" \
> "${_tru_target}" 2> "${_tru_target_err}" \
|| { _tru_ref=$?; echo "${_tru_target_err}"
return ${_tru_ref}; }
else
# when -B (deblanked outcomes handling) requested, we:
# - drop blanks from the source XML
# (effectively emulating pacemaker handling)
# - re-drop blanks from the XSLT outcome,
# which is compared with referential outcome
# processed with even greedier custom deblanking
# (extraneous inter-element whitespace like blank
# lines will not get removed otherwise, see lower)
xmllint --noblanks "${_tru_source}" \
| ${XSLTPROCESSOR} "${_tru_template}" - \
> "${_tru_target}" 2> "${_tru_target_err}" \
|| { _tru_ref=$?; echo "${_tru_target_err}"
return ${_tru_ref}; }
# reusing variable no longer needed
_tru_template="$(dirname "${_tru_target}")"
_tru_template="${_tru_template}/.$(basename "${_tru_target}")"
mv "${_tru_target}" "${_tru_template}"
${XSLTPROCESSOR} - "${_tru_template}" > "${_tru_target}" <<-EOF
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" encoding="UTF-8" omit-xml-declaration="yes"/>
<xsl:template match="@*|*|comment()|processing-instruction()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="text()">
<xsl:value-of select="normalize-space(.)"/>
</xsl:template>
</xsl:stylesheet>
EOF
fi
# only respond with the flags except for "-B", i.e., when both:
# - _tru_mode non-zero
# - "-B" in _tru_mode is zero (hence non-zero when flipped with XOR)
if test "$((_tru_mode * ((_tru_mode ^ (1 << 2)) & (1 << 2))))" -ne 0; then
if test $((_tru_mode & (1 << 0))) -ne 0; then
cp -a "${_tru_target}" "${_tru_ref}"
cp -a "${_tru_target_err}" "${_tru_ref_err}"
fi
if test $((_tru_mode & (1 << 1))) -ne 0; then
"${DIFF}" ${DIFFOPTS} "${_tru_source}" "${_tru_ref}" \
| ${DIFFPAGER} >&2
if test $? -ne 0; then
printf "\npager failure\n" >&2
return 1
fi
printf '\nIs comparison OK? ' >&2
if read _tru_answer </dev/tty; then
case "${_tru_answer}" in
y|yes) ;;
*) echo "Answer not 'y' nor 'yes'" >&2; return 1;;
esac
else
return 1
fi
fi
elif test -f "${_tru_ref}" && test -e "${_tru_ref_err}"; then
{ test "$((_tru_mode & (1 << 2)))" -eq 0 && cat "${_tru_ref}" \
|| ${XSLTPROCESSOR} - "${_tru_ref}" <<-EOF
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" encoding="UTF-8" omit-xml-declaration="yes"/>
<xsl:template match="@*|*|comment()|processing-instruction()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="text()">
<xsl:value-of select="normalize-space(.)"/>
</xsl:template>
</xsl:stylesheet>
EOF
} \
| "${DIFF}" ${DIFFOPTS} - "${_tru_target}" >&2 \
&& "${DIFF}" ${DIFFOPTS} "${_tru_ref_err}" \
"${_tru_target_err}" >&2
if test $? -ne 0; then
emit_error "Outputs differ from referential ones"
echo "/dev/null"
return 1
fi
else
emit_error "Referential file(s) missing: ${_tru_ref}"
echo "/dev/null"
return 1
fi
echo "${_tru_target}"
}
test_runner_validate() {
_trv_schema=${1:?}
_trv_target=${2:?} # filename
if ! ${RNGVALIDATOR} "${_trv_schema}" "${_trv_target}" \
2>/dev/null; then
${RNGVALIDATOR} "${_trv_schema}" "${_trv_target}"
fi
}
# -o= ... which conventional version to deem as the transform origin
# -t= ... which conventional version to deem as the transform target
# -B
# -D
# -G ... see usage
# stdin: input file per line
test_runner() {
_tr_mode=0
_tr_ret=0
_tr_schema_o=
_tr_schema_t=
_tr_target=
_tr_template=
while test $# -gt 0; do
case "$1" in
-o=*) _tr_template="upgrade-${1#-o=}.xsl"
_tr_schema_o="pacemaker-${1#-o=}.rng";;
-t=*) _tr_schema_t="pacemaker-${1#-t=}.rng";;
-G) _tr_mode=$((_tr_mode | (1 << 0)));;
-D) _tr_mode=$((_tr_mode | (1 << 1)));;
-B) _tr_mode=$((_tr_mode | (1 << 2)));;
esac
shift
done
if ! test -f "${_tr_schema_o:?}" || ! test -f "${_tr_schema_t:?}"; then
emit_error "Origin and/or target schema missing, rerun make"
return 1
fi
while read _tr_origin; do
printf '%-60s' "${_tr_origin}... "
# pre-validate
if ! test_runner_validate "${_tr_schema_o}" "${_tr_origin}"; then
_tr_ret=$((_tr_ret + 1)); echo "E:pre-validate"; continue
fi
# upgrade
if ! _tr_target=$(test_runner_upgrade "${_tr_template}" \
"${_tr_origin}" "${_tr_mode}"); then
_tr_ret=$((_tr_ret + 1));
test -n "${_tr_target}" || break
echo "E:upgrade"
test -s "${_tr_target}" \
&& { echo ---; cat "${_tr_target}" || :; echo ---; }
continue
fi
# post-validate
if ! test_runner_validate "${_tr_schema_t}" "${_tr_target}"; then
_tr_ret=$((_tr_ret + 1)); echo "E:post-validate"; continue
fi
echo "OK"
done
log2_or_0_return ${_tr_ret}
}
#
# particular test variations
# stdin: granular test specification(s) if any
#
test2to3() {
_t23_pattern=
while read _t23_spec; do
_t23_spec=${_t23_spec%.xml}
_t23_spec=${_t23_spec%\*}
_t23_pattern="${_t23_pattern} -name ${_t23_spec}*.xml -o"
done
test -z "${_t23_pattern}" || _t23_pattern="( ${_t23_pattern%-o} )"
find test-2 -name '*.xml' ${_t23_pattern} -print | env LC_ALL=C sort \
| { case " $* " in
*\ -C\ *) test_cleaner;;
*\ -S\ *) test_selfcheck -o=2.10;;
*\ -X\ *) test_explanation -o=2.10;;
*) test_runner -o=2.10 -t=3.0 "$@" || return $?;;
esac; }
}
tests="${tests} test2to3"
# -B
# -D
# -G ... see usage
cts_scheduler() {
_tcp_mode=0
_tcp_ret=0
_tcp_validatewith=
_tcp_schema_o=
_tcp_schema_t=
_tcp_template=
find ../cts/scheduler -name '*.xml' -print | env LC_ALL=C sort \
| { case " $* " in
*\ -C\ *) test_cleaner -r;;
*\ -S\ *) emit_result "not implemented" "option -S";;
*\ -X\ *) emit_result "not implemented" "option -X";;
*)
while test $# -gt 0; do
case "$1" in
-G) _tcp_mode=$((_tcp_mode | (1 << 0)));;
-D) _tcp_mode=$((_tcp_mode | (1 << 1)));;
-B) _tcp_mode=$((_tcp_mode | (1 << 2)));;
esac
shift
done
while read _tcp_origin; do
_tcp_validatewith=$(${XSLTPROCESSOR} - "${_tcp_origin}" <<-EOF
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" encoding="UTF-8"/>
<xsl:template match="/">
<xsl:choose>
<xsl:when test="starts-with(cib/@validate-with, 'pacemaker-')">
<xsl:variable name="Version" select="substring-after(cib/@validate-with, 'pacemaker-')"/>
<xsl:choose>
<xsl:when test="contains(\$Version, '.')">
<xsl:value-of select="substring-before(\$Version, '.')"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="cib/@validate-with"/>
</xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="cib/@validate-with"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
EOF
)
_tcp_schema_t=${_tcp_validatewith}
case "${_tcp_validatewith}" in
1) _tcp_schema_o=1.3;;
2) _tcp_schema_o=2.10;;
# only for gradual refinement as upgrade-2.10.xsl under
# active development, move to 3.x when schema v4 emerges
3) _tcp_schema_o=2.10
_tcp_schema_t=2;;
*) emit_error \
"need to skip ${_tcp_origin} (schema: ${_tcp_validatewith})"
continue;;
esac
_tcp_template="upgrade-${_tcp_schema_o}.xsl"
_tcp_schema_t="pacemaker-$((_tcp_schema_t + 1)).0.rng"
test "${_tcp_schema_o%%.*}" = "${_tcp_validatewith}" \
&& _tcp_schema_o="pacemaker-${_tcp_schema_o}.rng" \
|| _tcp_schema_o="${_tcp_schema_t}"
# pre-validate
if test "${_tcp_schema_o}" != "${_tcp_schema_t}" \
&& ! test_runner_validate "${_tcp_schema_o}" "${_tcp_origin}"; then
_tcp_ret=$((_tcp_ret + 1)); echo "E:pre-validate"; continue
fi
# upgrade
test "$((_tcp_mode & (1 << 0)))" -ne 0 \
|| ln -fs "$(pwd)/${_tcp_origin}" "${_tcp_origin%.*}.ref"
if ! _tcp_target=$(test_runner_upgrade "${_tcp_template}" \
"${_tcp_origin}" "${_tcp_mode}"); then
_tcp_ret=$((_tcp_ret + 1));
test -n "${_tcp_target}" || break
echo "E:upgrade"
test -s "${_tcp_target}" \
&& { echo ---; cat "${_tcp_target}" || :; echo ---; }
continue
fi
test "$((_tcp_mode & (1 << 0)))" -ne 0 \
|| rm -f "${_tcp_origin%.*}.ref"
# post-validate
if ! test_runner_validate "${_tcp_schema_t}" "${_tcp_target}"; then
_tcp_ret=$((_tcp_ret + 1)); echo "E:post-validate"; continue
fi
test "$((_tcp_mode & (1 << 0)))" -eq 0 \
|| mv "${_tcp_target}" "${_tcp_origin}"
done; log2_or_0_return ${_tcp_ret};;
esac; }
}
tests="${tests} cts_scheduler"
#
# "framework"
#
# option-likes ... options to be passed down
# argument-likes ... drives a test selection
test_suite() {
_ts_pass=
_ts_select=
_ts_select_full=
_ts_test_specs=
_ts_global_ret=0
_ts_ret=0
while test $# -gt 0; do
case "$1" in
-) printf '%s\n' 'waiting for tests specified at stdin...';
while read _ts_spec; do _ts_select="${_ts_spec}@$1"; done;;
-*) _ts_pass="${_ts_pass} $1";;
*) _ts_select_full="${_ts_select_full}@$1"
_ts_select="${_ts_select}@${1%%/*}";;
esac
shift
done
_ts_select="${_ts_select}@"
_ts_select_full="${_ts_select_full}@"
for _ts_test in ${tests}; do
while true; do
case "${_ts_select}" in
*@${_ts_test}@*)
_ts_select="${_ts_select%@${_ts_test}@*}"\
"@${_ts_select#*@${_ts_test}@}"
+ break
;;
- @) case "${_ts_test}" in test*) break;; *) continue 2;; esac
+ @) case "${_ts_test}" in test*) break;; esac
;;
- *) continue 2;;
esac
+ continue 2 # move on to matching with next local test
done
_ts_test_specs=
while true; do
case "${_ts_select_full}" in
*@${_ts_test}/*)
_ts_test_full="${_ts_test}/${_ts_select_full#*@${_ts_test}/}"
_ts_test_full="${_ts_test_full%%@*}"
_ts_select_full="${_ts_select_full%@${_ts_test_full}@*}"\
"@${_ts_select_full#*@${_ts_test_full}@}"
_ts_test_specs="${_ts_test_specs} ${_ts_test_full#*/}"
;;
*)
break
;;
esac
done
for _ts_test_spec in ${_ts_test_specs}; do
printf '%s\n' "${_ts_test_spec}"
done | "${_ts_test}" ${_ts_pass} || _ts_ret=$?
test ${_ts_ret} = 0 \
&& emit_result ${_ts_ret} "${_ts_test}" \
|| emit_result "at least 2^$((_ts_ret - 1))" "${_ts_test}"
log2_or_0_add ${_ts_global_ret} ${_ts_ret}
_ts_global_ret=$?
done
if test "${_ts_select}" != @; then
emit_error "Non-existing test(s):$(echo "${_ts_select}" \
| tr '@' ' ')"
log2_or_0_add ${_ts_global_ret} 1 || _ts_global_ret=$?
fi
return ${_ts_global_ret}
}
# NOTE: big letters are dedicated for per-test-set behaviour,
# small ones for generic/global behaviour
usage() {
printf '%s\n %s\n %s\n %s\n %s\n %s\n %s\n %s\n %s\n %s\n' \
"usage: $0 [-{B,C,D,G,S,X}]* [-|{${tests## }}*]" \
"- when no suites (arguments) provided, \"test*\" ones get used" \
"- with '-' suite specification the actual ones grabbed on stdin" \
"- use '-B' to run validate-only check suppressing blanks first" \
"- use '-C' to only cleanup ephemeral byproducts" \
"- use '-D' to review originals vs. \"referential\" outcomes" \
"- use '-G' to generate \"referential\" outcomes" \
"- use '-S' for template self-check (requires net access)" \
"- use '-X' to show explanatory details about the upgrade" \
"- test specification can be granular, e.g. 'test2to3/022'"
}
main() {
_main_pass=
_main_bailout=0
_main_ret=0
while test $# -gt 0; do
case "$1" in
-h) usage; exit;;
-C|-G|-S|-X) _main_bailout=1;;
esac
_main_pass="${_main_pass} $1"
shift
done
test_suite ${_main_pass} || _main_ret=$?
test ${_main_bailout} -eq 1 && return ${_main_ret} \
|| test_suite -C ${_main_pass} >/dev/null || true
test ${_main_ret} = 0 && emit_result ${_main_ret} "Overall suite" \
|| emit_result "at least 2^$((_main_ret - 1))" "Overall suite"
return ${_main_ret}
}
main "$@"
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Sat, Nov 23, 8:46 AM (23 h, 30 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1018498
Default Alt Text
(16 KB)
Attached To
Mode
rP Pacemaker
Attached
Detach File
Event Timeline
Log In to Comment