From 3fa06b4c1525b303301d0ffe1c12c76bad9a0ad1 Mon Sep 17 00:00:00 2001 From: Mario Fetka Date: Sat, 30 May 2026 10:35:22 +0000 Subject: [PATCH] tests: add AFP smoke-suite report helper 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 --- tests/linux/CMakeLists.txt | 8 + tests/linux/README.md | 37 +++++ tests/linux/afp_smoke_suite.sh | 276 +++++++++++++++++++++++++++++++++ 3 files changed, 321 insertions(+) create mode 100755 tests/linux/afp_smoke_suite.sh diff --git a/tests/linux/CMakeLists.txt b/tests/linux/CMakeLists.txt index 4f6c572..2de8534 100644 --- a/tests/linux/CMakeLists.txt +++ b/tests/linux/CMakeLists.txt @@ -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}) diff --git a/tests/linux/README.md b/tests/linux/README.md index 242f5a9..61314de 100644 --- a/tests/linux/README.md +++ b/tests/linux/README.md @@ -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: diff --git a/tests/linux/afp_smoke_suite.sh b/tests/linux/afp_smoke_suite.sh new file mode 100755 index 0000000..e4bc5cb --- /dev/null +++ b/tests/linux/afp_smoke_suite.sh @@ -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 <&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