tests: add initial salvage layout smoke

This commit is contained in:
Mario Fetka
2026-05-31 09:19:58 +00:00
parent 10d092bf71
commit a539df7d3c
4 changed files with 163 additions and 0 deletions

View File

@@ -5,3 +5,4 @@
# project CMakeLists.txt does not grow with each test group.
add_subdirectory(afp)
add_subdirectory(salvage)

View File

@@ -0,0 +1,28 @@
# Optional NetWare salvage/deleted-entry smoke-test helpers.
#
# The first helper is a layout contract test for the upcoming recycle-backed
# nwsalvage backend. It has no ncpfs dependency and does not require a running
# mars_nwe server.
set(SALVAGE_LAYOUT_SMOKE_SCRIPT
${CMAKE_CURRENT_BINARY_DIR}/salvage_layout_smoke.sh
)
add_custom_command(
OUTPUT ${SALVAGE_LAYOUT_SMOKE_SCRIPT}
COMMAND ${CMAKE_COMMAND} -E copy_if_different
${CMAKE_CURRENT_SOURCE_DIR}/salvage_layout_smoke.sh
${SALVAGE_LAYOUT_SMOKE_SCRIPT}
COMMAND ${CMAKE_COMMAND} -E env chmod +x ${SALVAGE_LAYOUT_SMOKE_SCRIPT}
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/salvage_layout_smoke.sh
COMMENT "Copying salvage layout smoke helper"
VERBATIM
)
add_custom_target(salvage_layout_smoke ALL
DEPENDS ${SALVAGE_LAYOUT_SMOKE_SCRIPT}
)
set_property(DIRECTORY APPEND PROPERTY ADDITIONAL_CLEAN_FILES
${SALVAGE_LAYOUT_SMOKE_SCRIPT}
)

36
tests/salvage/README.md Normal file
View File

@@ -0,0 +1,36 @@
# Salvage smoke tests
This directory is reserved for NetWare salvage/deleted-entry coverage. The
backend is intentionally shared by NCP salvage calls and the later AFP `0x13`
`Get Macintosh Info On Deleted Files` adapter; AFP must not grow a parallel
local deleted-file scanner.
The first executable coverage is layout-only. It records the repository
contract before `src/nwsalvage.c` exists:
- deleted file payloads live below the recycle repository,
- per-object JSON metadata lives below the salvage repository,
- there is no large per-directory index file,
- stale JSON metadata is detectable when the matching recycle payload is gone.
Default repository names come from the `nwserv.conf`/`nw.ini` template options:
```text
48 1
49 .recycle .salvage
```
Expected layout for a deleted `SYS:PUBLIC/PMDFLTS.INI` owned by `SUPERVISOR`:
```text
SYS/.recycle/SUPERVISOR/PUBLIC/PMDFLTS.INI
SYS/.salvage/SUPERVISOR/PUBLIC/PMDFLTS.INI.json
```
Future runtime tests should add direct coverage for:
- `NCP 0x2222 / 22 / 27` Scan Salvageable Files (old),
- `NCP 0x2222 / 87 / 16` Scan Salvageable Files,
- `NCP 0x2222 / 87 / 17` Recover Salvageable File,
- `NCP 0x2222 / 87 / 18` Purge Salvageable File,
- AFP `0x13` as a thin adapter over the shared salvage backend.

View File

@@ -0,0 +1,98 @@
#!/usr/bin/env bash
# Validate the planned recycle-backed salvage metadata layout without requiring
# a running mars_nwe server. This is a contract test for the upcoming
# nwsalvage backend, not an implementation of the backend itself.
set -u
ROOT=""
RECYCLE_NAME=".recycle"
SALVAGE_NAME=".salvage"
KEEP_ROOT=0
usage() {
cat <<USAGE
Usage: $0 [options]
Options:
--root DIR Use DIR as the temporary test root
--repo-names R S Recycle and salvage repository names (default: $RECYCLE_NAME $SALVAGE_NAME)
--keep-root Do not remove the generated temporary root
-h, --help Show this help
The smoke creates a mock SYS tree, moves one deleted-file payload below the
recycle repository, writes one JSON metadata object below the salvage repository,
and verifies that stale JSON can be detected after the recycle payload vanishes.
USAGE
}
fail() {
echo "FAIL: $*" >&2
exit 1
}
while [ $# -gt 0 ]; do
case "$1" in
--root)
ROOT=$2; shift 2 ;;
--repo-names)
RECYCLE_NAME=$2; SALVAGE_NAME=$3; shift 3 ;;
--keep-root)
KEEP_ROOT=1; shift ;;
-h|--help)
usage; exit 0 ;;
*)
usage >&2; fail "unknown option: $1" ;;
esac
done
if [ -z "$ROOT" ]; then
ROOT=$(mktemp -d "${TMPDIR:-/tmp}/mars-salvage-layout.XXXXXX") || exit 1
else
mkdir -p "$ROOT" || exit 1
fi
cleanup() {
if [ "$KEEP_ROOT" -eq 0 ]; then
rm -rf "$ROOT"
else
echo "kept test root: $ROOT"
fi
}
trap cleanup EXIT
SYS="$ROOT/SYS"
LIVE_FILE="$SYS/PUBLIC/PMDFLTS.INI"
RECYCLE_FILE="$SYS/$RECYCLE_NAME/SUPERVISOR/PUBLIC/PMDFLTS.INI"
SALVAGE_JSON="$SYS/$SALVAGE_NAME/SUPERVISOR/PUBLIC/PMDFLTS.INI.json"
FLAT_INDEX="$SYS/$SALVAGE_NAME/SUPERVISOR/PUBLIC/.index.json"
mkdir -p "$(dirname "$LIVE_FILE")" || exit 1
printf 'sample payload\n' > "$LIVE_FILE" || exit 1
mkdir -p "$(dirname "$RECYCLE_FILE")" "$(dirname "$SALVAGE_JSON")" || exit 1
mv "$LIVE_FILE" "$RECYCLE_FILE" || exit 1
cat > "$SALVAGE_JSON" <<JSON
{
"volume": "SYS",
"owner": "SUPERVISOR",
"original_path": "PUBLIC/PMDFLTS.INI",
"recycle_path": "$RECYCLE_NAME/SUPERVISOR/PUBLIC/PMDFLTS.INI"
}
JSON
[ -f "$RECYCLE_FILE" ] || fail "missing recycle payload: $RECYCLE_FILE"
[ -f "$SALVAGE_JSON" ] || fail "missing per-object JSON metadata: $SALVAGE_JSON"
[ ! -e "$FLAT_INDEX" ] || fail "unexpected per-directory index file: $FLAT_INDEX"
grep -q '"original_path": "PUBLIC/PMDFLTS.INI"' "$SALVAGE_JSON" || \
fail "metadata does not record original path"
grep -q '"recycle_path": "'"$RECYCLE_NAME"'/SUPERVISOR/PUBLIC/PMDFLTS.INI"' "$SALVAGE_JSON" || \
fail "metadata does not record recycle payload path"
rm -f "$RECYCLE_FILE" || exit 1
[ ! -f "$RECYCLE_FILE" ] || fail "recycle payload still exists after purge simulation"
[ -f "$SALVAGE_JSON" ] || fail "stale JSON should still be present before cleanup"
echo "stale metadata detected: $SALVAGE_JSON -> missing $RECYCLE_FILE"
echo "salvage layout smoke passed"