tests: add AFP smoke-suite report helper
All checks were successful
Source release / source-package (push) Successful in 50s

Add an optional Linux-side AFP smoke-suite shell helper that runs the
currently verified AFP NCP 0x2222/35 probes as a single collectable report.
The helper is intended for the same ncpfs/libncp smoke workflow as the
individual C helpers, but it groups the read-only probes, the narrow Set File
Information metadata writes, Linux xattr verification, and a filtered AFP
server-log excerpt so runtime results can be pasted back into follow-up
test-status patches.

Keep the command lines safe to share by masking the password in the printed
report while still passing the real value to the helpers. Parameterize the
server, user, password, NetWare path, Unix path, mars_nwe log file,
FinderInfo type/creator, and output file so the script can be used against
SYS:PUBLIC as well as other exported volumes.

Copy the script into the CMake binary tests/linux directory when
MARS_NWE_BUILD_LINUX_TESTS is enabled, preserving executable permissions. The
script does not add new AFP semantics; it only automates the existing helpers
and documents the Linux xattr names used by the mars_nwe AFP metadata wrapper.

Tests:
- bash -n tests/linux/afp_smoke_suite.sh
- ./tests/linux/afp_smoke_suite.sh --help
- git diff --check
This commit is contained in:
Mario Fetka
2026-05-30 10:35:22 +00:00
parent c51fde95fe
commit 3fa06b4c15
3 changed files with 321 additions and 0 deletions

View File

@@ -18,6 +18,14 @@ if(NOT NCPFS_INCLUDE_DIR OR NOT NCPFS_LIBRARY)
)
endif()
file(COPY afp_smoke_suite.sh
DESTINATION ${CMAKE_CURRENT_BINARY_DIR}
FILE_PERMISSIONS
OWNER_READ OWNER_WRITE OWNER_EXECUTE
GROUP_READ GROUP_EXECUTE
WORLD_READ WORLD_EXECUTE
)
add_executable(afp_entry_id_smoke afp_entry_id_smoke.c)
target_include_directories(afp_entry_id_smoke PRIVATE ${NCPFS_INCLUDE_DIR})
target_link_libraries(afp_entry_id_smoke ${NCPFS_LIBRARY})

View File

@@ -33,6 +33,43 @@ cmake --build . --target afp_temp_dir_handle_smoke
cmake --build . --target afp_set_file_info_smoke
```
## AFP smoke-suite report helper
`afp_smoke_suite.sh` runs the currently verified AFP Linux smoke helpers as one
collectable report. It is meant for interactive runtime validation after a
server rebuild: the script prints each helper with the password masked, captures
new AFP lines appended to the mars_nwe server log while the suite runs, and
adds `getfattr -e hex` checks for the mars_nwe AFP xattrs on the tested Unix
file.
Example from the build `tests/linux` directory:
```sh
./afp_smoke_suite.sh \
-S MARS -U SUPERVISOR -P secret \
--path SYS:PUBLIC/pmdflts.ini \
--unix-path /var/mars_nwe/SYS/public/pmdflts.ini \
--log /var/log/mars_nwe/nw.log \
--out /tmp/mars-afp-smoke.txt
```
The report includes AFP Entry ID, Entry ID From NetWare Handle, Get File
Information, Scan File Information, Alloc Temporary Directory Handle, Open File
Fork, FinderInfo Set File Information, Invisible Set/Clear File Information,
and the Linux xattr checks for:
```text
user.org.mars-nwe.afp.finder-info
user.org.mars-nwe.afp.attributes
user.org.mars-nwe.afp.entry-id
```
Use `--no-log` when the log file is unavailable or when the server log is being
collected separately. Use `--stop-on-failure` for strict bisect-style runs; by
default the script keeps going so one failing endpoint does not hide later AFP
output from the report.
## AFP Entry ID smoke test
`afp_entry_id_smoke` sends the WebSDK-documented NetWare AFP request:

276
tests/linux/afp_smoke_suite.sh Executable file
View File

@@ -0,0 +1,276 @@
#!/usr/bin/env bash
# Run the mars_nwe AFP Linux smoke helpers as one collectable report.
#
# The helper intentionally keeps the password out of the printed command lines,
# captures AFP server diagnostics from the mars_nwe log while the probes run, and
# appends Linux xattr checks for the tested Unix file.
set -u
SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
SERVER="MARS"
USER_NAME="SUPERVISOR"
PASSWORD=""
NETWARE_PATH="SYS:PUBLIC/pmdflts.ini"
UNIX_PATH="/var/mars_nwe/SYS/public/pmdflts.ini"
LOG_FILE="/var/log/mars_nwe/nw.log"
OUT_FILE=""
FINDER_TYPE="TEXT"
FINDER_CREATOR="MARS"
KEEP_GOING=1
CAPTURE_LOG=1
usage() {
cat <<USAGE
Usage: $0 -S SERVER -U USER -P PASSWORD [options]
Options:
--path NETWARE_PATH NetWare path to test (default: $NETWARE_PATH)
--unix-path UNIX_PATH Unix path for getfattr checks (default: $UNIX_PATH)
--log LOGFILE mars_nwe log to tail for AFP lines (default: $LOG_FILE)
--out FILE Write the complete report to FILE as well as stdout
--type FOURCC FinderInfo type written by Set File Info (default: $FINDER_TYPE)
--creator FOURCC FinderInfo creator written by Set File Info (default: $FINDER_CREATOR)
--no-log Do not tail/grep the server log
--stop-on-failure Stop after the first failing smoke command
-h, --help Show this help
The script expects the compiled smoke helpers in the same directory as this
script. It prints commands with the password masked, writes an AFP-only log
snippet, and runs getfattr checks for mars_nwe AFP xattrs.
USAGE
}
while [ $# -gt 0 ]; do
case "$1" in
-S|--server)
SERVER=$2; shift 2 ;;
-U|--user)
USER_NAME=$2; shift 2 ;;
-P|--password)
PASSWORD=$2; shift 2 ;;
--path)
NETWARE_PATH=$2; shift 2 ;;
--unix-path)
UNIX_PATH=$2; shift 2 ;;
--log)
LOG_FILE=$2; shift 2 ;;
--out)
OUT_FILE=$2; shift 2 ;;
--type)
FINDER_TYPE=$2; shift 2 ;;
--creator)
FINDER_CREATOR=$2; shift 2 ;;
--no-log)
CAPTURE_LOG=0; shift ;;
--stop-on-failure)
KEEP_GOING=0; shift ;;
-h|--help)
usage; exit 0 ;;
*)
echo "Unknown argument: $1" >&2
usage >&2
exit 2 ;;
esac
done
if [ -z "$PASSWORD" ]; then
echo "Missing password. Use -P PASSWORD." >&2
usage >&2
exit 2
fi
case "$FINDER_TYPE" in
???? ) ;;
*) echo "--type must be exactly four characters" >&2; exit 2 ;;
esac
case "$FINDER_CREATOR" in
???? ) ;;
*) echo "--creator must be exactly four characters" >&2; exit 2 ;;
esac
DIR_PATH=$NETWARE_PATH
case "$NETWARE_PATH" in
*/*) DIR_PATH=${NETWARE_PATH%/*} ;;
esac
REPORT_TMP=$(mktemp "${TMPDIR:-/tmp}/mars-afp-smoke.XXXXXX")
LOG_TMP=$(mktemp "${TMPDIR:-/tmp}/mars-afp-log.XXXXXX")
LOG_PID=""
FAILURES=0
cleanup() {
if [ -n "$LOG_PID" ] && kill -0 "$LOG_PID" 2>/dev/null; then
kill "$LOG_PID" 2>/dev/null || true
wait "$LOG_PID" 2>/dev/null || true
fi
rm -f "$LOG_TMP"
}
trap cleanup EXIT INT TERM
emit() {
printf '%s\n' "$*" | tee -a "$REPORT_TMP"
}
section() {
emit ""
emit "## $*"
}
run_cmd() {
local label=$1
local printable=$2
shift 2
section "$label"
emit "\$ $printable"
"$@" 2>&1 | tee -a "$REPORT_TMP"
local status=${PIPESTATUS[0]}
emit "[exit=$status]"
if [ "$status" -ne 0 ]; then
FAILURES=$((FAILURES + 1))
if [ "$KEEP_GOING" -eq 0 ]; then
finish_report
exit "$status"
fi
fi
}
finish_report() {
if [ "$CAPTURE_LOG" -eq 1 ]; then
sleep 1
if [ -n "$LOG_PID" ] && kill -0 "$LOG_PID" 2>/dev/null; then
kill "$LOG_PID" 2>/dev/null || true
wait "$LOG_PID" 2>/dev/null || true
LOG_PID=""
fi
section "AFP server log excerpt"
if [ -s "$LOG_TMP" ]; then
cat "$LOG_TMP" | tee -a "$REPORT_TMP"
else
emit "No AFP lines captured from $LOG_FILE."
fi
fi
section "Summary"
emit "failures=$FAILURES"
if [ -n "$OUT_FILE" ]; then
cp "$REPORT_TMP" "$OUT_FILE"
emit "report=$OUT_FILE"
fi
}
section "mars_nwe AFP smoke suite"
emit "date=$(date -Is)"
emit "server=$SERVER"
emit "user=$USER_NAME"
emit "path=$NETWARE_PATH"
emit "dir_path=$DIR_PATH"
emit "unix_path=$UNIX_PATH"
emit "log=$LOG_FILE"
emit "finder_type=$FINDER_TYPE"
emit "finder_creator=$FINDER_CREATOR"
for helper in \
afp_entry_id_smoke \
afp_file_info_smoke \
afp_scan_info_smoke \
afp_temp_dir_handle_smoke \
afp_open_file_fork_smoke \
afp_set_file_info_smoke
do
if [ ! -x "$SCRIPT_DIR/$helper" ]; then
emit "Missing executable: $SCRIPT_DIR/$helper"
exit 2
fi
done
if [ "$CAPTURE_LOG" -eq 1 ]; then
if [ -r "$LOG_FILE" ]; then
# Capture only lines appended while this script is running.
tail -n 0 -F "$LOG_FILE" 2>/dev/null | grep --line-buffered AFP >"$LOG_TMP" &
LOG_PID=$!
sleep 1
else
emit "Log file is not readable, disabling log capture: $LOG_FILE"
CAPTURE_LOG=0
fi
fi
COMMON_PRINT="-S $SERVER -U $USER_NAME -P ******"
run_cmd \
"AFP Entry ID From Path Name" \
"./afp_entry_id_smoke $COMMON_PRINT '$NETWARE_PATH'" \
"$SCRIPT_DIR/afp_entry_id_smoke" -S "$SERVER" -U "$USER_NAME" -P "$PASSWORD" "$NETWARE_PATH"
run_cmd \
"AFP Entry ID From NetWare Handle" \
"./afp_entry_id_smoke --from-handle $COMMON_PRINT '$NETWARE_PATH'" \
"$SCRIPT_DIR/afp_entry_id_smoke" --from-handle -S "$SERVER" -U "$USER_NAME" -P "$PASSWORD" "$NETWARE_PATH"
run_cmd \
"AFP 2.0 Get File Information" \
"./afp_file_info_smoke $COMMON_PRINT '$NETWARE_PATH'" \
"$SCRIPT_DIR/afp_file_info_smoke" -S "$SERVER" -U "$USER_NAME" -P "$PASSWORD" "$NETWARE_PATH"
run_cmd \
"AFP 2.0 Scan File Information" \
"./afp_scan_info_smoke $COMMON_PRINT '$DIR_PATH'" \
"$SCRIPT_DIR/afp_scan_info_smoke" -S "$SERVER" -U "$USER_NAME" -P "$PASSWORD" "$DIR_PATH"
run_cmd \
"AFP Alloc Temporary Directory Handle" \
"./afp_temp_dir_handle_smoke $COMMON_PRINT '$DIR_PATH'" \
"$SCRIPT_DIR/afp_temp_dir_handle_smoke" -S "$SERVER" -U "$USER_NAME" -P "$PASSWORD" "$DIR_PATH"
run_cmd \
"AFP Open File Fork" \
"./afp_open_file_fork_smoke $COMMON_PRINT '$NETWARE_PATH'" \
"$SCRIPT_DIR/afp_open_file_fork_smoke" -S "$SERVER" -U "$USER_NAME" -P "$PASSWORD" "$NETWARE_PATH"
run_cmd \
"AFP Set File Information FinderInfo" \
"./afp_set_file_info_smoke $COMMON_PRINT --finder-info-only --type '$FINDER_TYPE' --creator '$FINDER_CREATOR' '$NETWARE_PATH'" \
"$SCRIPT_DIR/afp_set_file_info_smoke" -S "$SERVER" -U "$USER_NAME" -P "$PASSWORD" \
--finder-info-only --type "$FINDER_TYPE" --creator "$FINDER_CREATOR" "$NETWARE_PATH"
run_cmd \
"AFP Set File Information Invisible" \
"./afp_set_file_info_smoke $COMMON_PRINT --attributes-only --invisible '$NETWARE_PATH'" \
"$SCRIPT_DIR/afp_set_file_info_smoke" -S "$SERVER" -U "$USER_NAME" -P "$PASSWORD" \
--attributes-only --invisible "$NETWARE_PATH"
run_cmd \
"AFP Set File Information Clear Invisible" \
"./afp_set_file_info_smoke $COMMON_PRINT --attributes-only --clear-invisible '$NETWARE_PATH'" \
"$SCRIPT_DIR/afp_set_file_info_smoke" -S "$SERVER" -U "$USER_NAME" -P "$PASSWORD" \
--attributes-only --clear-invisible "$NETWARE_PATH"
if command -v getfattr >/dev/null 2>&1; then
run_cmd \
"Linux xattr: AFP FinderInfo" \
"getfattr -n user.org.mars-nwe.afp.finder-info -e hex '$UNIX_PATH'" \
getfattr -n user.org.mars-nwe.afp.finder-info -e hex "$UNIX_PATH"
run_cmd \
"Linux xattr: AFP Attributes" \
"getfattr -n user.org.mars-nwe.afp.attributes -e hex '$UNIX_PATH'" \
getfattr -n user.org.mars-nwe.afp.attributes -e hex "$UNIX_PATH"
run_cmd \
"Linux xattr: AFP Entry ID" \
"getfattr -n user.org.mars-nwe.afp.entry-id -e hex '$UNIX_PATH'" \
getfattr -n user.org.mars-nwe.afp.entry-id -e hex "$UNIX_PATH"
else
section "Linux xattr checks"
emit "getfattr not found; install the attr package to collect xattr output."
FAILURES=$((FAILURES + 1))
fi
finish_report
if [ "$FAILURES" -ne 0 ]; then
exit 1
fi
exit 0