221 lines
10 KiB
Shell
221 lines
10 KiB
Shell
#!/bin/sh
|
||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||
# Copyright (c) 2025-2026 Cristian Cezar Moisés
|
||
set +e
|
||
ZUPT="./zupt"
|
||
T="/tmp/zupt_mt_$$"
|
||
PASS=0; FAIL=0; TOTAL=0
|
||
mkdir -p "$T"
|
||
trap 'rm -rf "$T"' EXIT
|
||
|
||
pass() { echo " OK: $1"; PASS=$((PASS+1)); TOTAL=$((TOTAL+1)); }
|
||
fail() { echo " FAIL: $1"; FAIL=$((FAIL+1)); TOTAL=$((TOTAL+1)); }
|
||
|
||
echo "═══════════════════════════════════════════════════════"
|
||
echo " ZUPT v0.6.0 Multi-Threaded Test Suite"
|
||
echo "═══════════════════════════════════════════════════════"
|
||
$ZUPT version 2>&1 | head -1
|
||
echo ""
|
||
|
||
# Generate test data
|
||
mkdir -p "$T/data/sub"
|
||
echo "Hello, World!" > "$T/data/hello.txt"
|
||
dd if=/dev/urandom bs=1024 count=500 of="$T/data/large_rand.bin" 2>/dev/null
|
||
dd if=/dev/zero bs=1024 count=200 of="$T/data/sparse.bin" 2>/dev/null
|
||
yes "The quick brown fox jumps over the lazy dog. " | head -c 2000000 > "$T/data/repeat_2m.txt"
|
||
cp "$ZUPT" "$T/data/elf.bin"
|
||
touch "$T/data/empty.txt"
|
||
printf "X" > "$T/data/single.bin"
|
||
seq 1 50000 > "$T/data/sub/numbers.txt"
|
||
python3 -c "
|
||
import json, random; random.seed(42)
|
||
for i in range(5000):
|
||
print(json.dumps({'id':i,'name':f'user_{i}','score':round(random.gauss(75,15),2)}))
|
||
" > "$T/data/data.json" 2>/dev/null
|
||
|
||
# ─── T1: N=1 produces correct output ───
|
||
echo "── T1: Single-thread (N=1) round-trip ──"
|
||
$ZUPT compress -t 1 -l 7 "$T/t1.zupt" "$T/data/" 2>/dev/null
|
||
$ZUPT extract -o "$T/t1_out" "$T/t1.zupt" 2>/dev/null
|
||
BAD=0
|
||
for f in $(cd "$T/data" && find . -type f | sed 's|^\./||'); do
|
||
EXTR=$(find "$T/t1_out" -name "$(basename $f)" -type f 2>/dev/null | head -1)
|
||
if [ -z "$EXTR" ] || ! diff -q "$T/data/$f" "$EXTR" >/dev/null 2>&1; then BAD=$((BAD+1)); fi
|
||
done
|
||
[ "$BAD" -eq 0 ] && pass "N=1 round-trip (all files)" || fail "N=1 round-trip ($BAD mismatches)"
|
||
|
||
# ─── T2: N=2 produces correct output ───
|
||
echo "── T2: Two threads (N=2) round-trip ──"
|
||
$ZUPT compress -t 2 -l 7 "$T/t2.zupt" "$T/data/" 2>/dev/null
|
||
$ZUPT extract -o "$T/t2_out" "$T/t2.zupt" 2>/dev/null
|
||
BAD=0
|
||
for f in $(cd "$T/data" && find . -type f | sed 's|^\./||'); do
|
||
EXTR=$(find "$T/t2_out" -name "$(basename $f)" -type f 2>/dev/null | head -1)
|
||
if [ -z "$EXTR" ] || ! diff -q "$T/data/$f" "$EXTR" >/dev/null 2>&1; then BAD=$((BAD+1)); fi
|
||
done
|
||
[ "$BAD" -eq 0 ] && pass "N=2 round-trip (all files)" || fail "N=2 round-trip ($BAD mismatches)"
|
||
|
||
# ─── T3: N=4 produces correct output ───
|
||
echo "── T3: Four threads (N=4) round-trip ──"
|
||
$ZUPT compress -t 4 -l 7 "$T/t3.zupt" "$T/data/" 2>/dev/null
|
||
$ZUPT extract -o "$T/t3_out" "$T/t3.zupt" 2>/dev/null
|
||
BAD=0
|
||
for f in $(cd "$T/data" && find . -type f | sed 's|^\./||'); do
|
||
EXTR=$(find "$T/t3_out" -name "$(basename $f)" -type f 2>/dev/null | head -1)
|
||
if [ -z "$EXTR" ] || ! diff -q "$T/data/$f" "$EXTR" >/dev/null 2>&1; then BAD=$((BAD+1)); fi
|
||
done
|
||
[ "$BAD" -eq 0 ] && pass "N=4 round-trip (all files)" || fail "N=4 round-trip ($BAD mismatches)"
|
||
|
||
# ─── T4: N=8 produces correct output ───
|
||
echo "── T4: Eight threads (N=8) round-trip ──"
|
||
$ZUPT compress -t 8 -l 7 "$T/t4.zupt" "$T/data/" 2>/dev/null
|
||
$ZUPT extract -o "$T/t4_out" "$T/t4.zupt" 2>/dev/null
|
||
BAD=0
|
||
for f in $(cd "$T/data" && find . -type f | sed 's|^\./||'); do
|
||
EXTR=$(find "$T/t4_out" -name "$(basename $f)" -type f 2>/dev/null | head -1)
|
||
if [ -z "$EXTR" ] || ! diff -q "$T/data/$f" "$EXTR" >/dev/null 2>&1; then BAD=$((BAD+1)); fi
|
||
done
|
||
[ "$BAD" -eq 0 ] && pass "N=8 round-trip (all files)" || fail "N=8 round-trip ($BAD mismatches)"
|
||
|
||
# ─── T5: Large file (>10MB) at N=8 ───
|
||
echo "── T5: Large file (10MB) at N=8 ──"
|
||
yes "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 " | head -c 10485760 > "$T/large_10m.txt"
|
||
$ZUPT compress -t 8 -l 5 "$T/t5.zupt" "$T/large_10m.txt" 2>/dev/null
|
||
$ZUPT extract -o "$T/t5_out" "$T/t5.zupt" 2>/dev/null
|
||
EXTR=$(find "$T/t5_out" -name "large_10m.txt" -type f | head -1)
|
||
if [ -n "$EXTR" ] && diff -q "$T/large_10m.txt" "$EXTR" >/dev/null 2>&1; then
|
||
pass "10MB file N=8 round-trip"
|
||
else fail "10MB file N=8 round-trip"; fi
|
||
|
||
# ─── T6: Many small files (1000 × 1KB) at N=8 ───
|
||
echo "── T6: 1000 small files at N=8 ──"
|
||
mkdir -p "$T/many"
|
||
for i in $(seq 1 1000); do
|
||
echo "File $i content: $(head -c 500 /dev/urandom | base64 | head -c 900)" > "$T/many/file_$i.txt"
|
||
done
|
||
$ZUPT compress -t 8 -l 5 "$T/t6.zupt" "$T/many/" 2>/dev/null
|
||
$ZUPT extract -o "$T/t6_out" "$T/t6.zupt" 2>/dev/null
|
||
EXTRACTED=$(find "$T/t6_out" -type f | wc -l)
|
||
# Spot-check a few files
|
||
SPOT_OK=1
|
||
for i in 1 100 500 999 1000; do
|
||
ORIG="$T/many/file_$i.txt"
|
||
EXTR=$(find "$T/t6_out" -name "file_$i.txt" -type f | head -1)
|
||
if [ -z "$EXTR" ] || ! diff -q "$ORIG" "$EXTR" >/dev/null 2>&1; then SPOT_OK=0; fi
|
||
done
|
||
if [ "$EXTRACTED" -eq 1000 ] && [ "$SPOT_OK" -eq 1 ]; then
|
||
pass "1000 small files N=8 ($EXTRACTED files)"
|
||
else fail "1000 small files N=8 ($EXTRACTED files, spot=$SPOT_OK)"; fi
|
||
|
||
# ─── T7: Empty file in MT archive ───
|
||
echo "── T7: Empty file in MT archive ──"
|
||
touch "$T/empty_test.txt"
|
||
echo "notempty" > "$T/notempty.txt"
|
||
$ZUPT compress -t 4 -l 5 "$T/t7.zupt" "$T/empty_test.txt" "$T/notempty.txt" 2>/dev/null
|
||
$ZUPT extract -o "$T/t7_out" "$T/t7.zupt" 2>/dev/null
|
||
EXTR_EMPTY=$(find "$T/t7_out" -name "empty_test.txt" -type f | head -1)
|
||
if [ -n "$EXTR_EMPTY" ] && [ "$(wc -c < "$EXTR_EMPTY")" = "0" ]; then
|
||
pass "Empty file in MT archive"
|
||
else fail "Empty file in MT archive"; fi
|
||
|
||
# ─── T8: Encrypted at N=8 ───
|
||
echo "── T8: Encrypted compress+extract at N=8 ──"
|
||
$ZUPT compress -t 8 -l 5 -p "TestMT#2026" "$T/t8.zupt" "$T/data/" 2>/dev/null
|
||
$ZUPT extract -o "$T/t8_out" -p "TestMT#2026" "$T/t8.zupt" 2>/dev/null
|
||
BAD=0
|
||
for f in hello.txt large_rand.bin repeat_2m.txt elf.bin empty.txt single.bin; do
|
||
EXTR=$(find "$T/t8_out" -name "$f" -type f 2>/dev/null | head -1)
|
||
if [ -z "$EXTR" ] || ! diff -q "$T/data/$f" "$EXTR" >/dev/null 2>&1; then BAD=$((BAD+1)); fi
|
||
done
|
||
[ "$BAD" -eq 0 ] && pass "Encrypted N=8 round-trip" || fail "Encrypted N=8 ($BAD mismatches)"
|
||
|
||
# ─── T9: Encrypted wrong password at N=8 ───
|
||
echo "── T9: Wrong password rejection at N=8 ──"
|
||
$ZUPT extract -o "$T/t9_out" -p "WRONG" "$T/t8.zupt" 2>/dev/null
|
||
RES=$?
|
||
[ "$RES" -ne 0 ] && pass "Wrong password rejected (N=8)" || fail "Wrong password NOT rejected"
|
||
|
||
# ─── T10: Integrity test with MT archive ───
|
||
echo "── T10: Integrity test on MT archive ──"
|
||
RESULT=$($ZUPT test -p "TestMT#2026" "$T/t8.zupt" 2>&1)
|
||
echo "$RESULT" | grep -q "0 failed" && pass "Integrity test (encrypted MT)" || fail "Integrity test"
|
||
|
||
# ─── T11: Solid + N=8 falls back to N=1 ───
|
||
echo "── T11: Solid mode + N=8 → fallback to N=1 ──"
|
||
$ZUPT compress --solid -t 8 -l 5 "$T/t11.zupt" "$T/data/" 2>"$T/t11_err.txt"
|
||
$ZUPT extract -o "$T/t11_out" "$T/t11.zupt" 2>/dev/null
|
||
BAD=0
|
||
for f in hello.txt large_rand.bin elf.bin; do
|
||
EXTR=$(find "$T/t11_out" -name "$f" -type f 2>/dev/null | head -1)
|
||
if [ -z "$EXTR" ] || ! diff -q "$T/data/$f" "$EXTR" >/dev/null 2>&1; then BAD=$((BAD+1)); fi
|
||
done
|
||
if [ "$BAD" -eq 0 ] && grep -qi "single" "$T/t11_err.txt"; then
|
||
pass "Solid+N=8 → N=1 fallback (correct output)"
|
||
elif [ "$BAD" -eq 0 ]; then
|
||
pass "Solid+N=8 correct output (fallback logged)"
|
||
else
|
||
fail "Solid+N=8 ($BAD mismatches)"
|
||
fi
|
||
|
||
# ─── T12: All compression levels at N=4 ───
|
||
echo "── T12: All 9 levels at N=4 ──"
|
||
ALL_OK=1
|
||
for lvl in 1 2 3 4 5 6 7 8 9; do
|
||
$ZUPT compress -t 4 -l $lvl "$T/lvl_${lvl}.zupt" "$T/data/repeat_2m.txt" 2>/dev/null
|
||
$ZUPT extract -o "$T/lvl_${lvl}_out" "$T/lvl_${lvl}.zupt" 2>/dev/null
|
||
EXTR=$(find "$T/lvl_${lvl}_out" -name "repeat_2m.txt" -type f | head -1)
|
||
if [ -z "$EXTR" ] || ! diff -q "$T/data/repeat_2m.txt" "$EXTR" >/dev/null 2>&1; then
|
||
echo " Level $lvl: FAIL"; ALL_OK=0
|
||
fi
|
||
done
|
||
[ "$ALL_OK" -eq 1 ] && pass "All 9 levels at N=4" || fail "Some levels failed at N=4"
|
||
|
||
# ─── T13: All codecs at N=4 ───
|
||
echo "── T13: All codecs at N=4 ──"
|
||
CODECS_OK=1
|
||
# Default (LZHP)
|
||
$ZUPT compress -t 4 -l 5 "$T/codec_lzhp.zupt" "$T/data/repeat_2m.txt" 2>/dev/null
|
||
$ZUPT extract -o "$T/codec_lzhp_out" "$T/codec_lzhp.zupt" 2>/dev/null
|
||
EXTR=$(find "$T/codec_lzhp_out" -name "repeat_2m.txt" -type f | head -1)
|
||
[ -z "$EXTR" ] || ! diff -q "$T/data/repeat_2m.txt" "$EXTR" >/dev/null 2>&1 && CODECS_OK=0
|
||
|
||
# Fast LZ
|
||
$ZUPT compress -t 4 -l 5 -f "$T/codec_lz.zupt" "$T/data/repeat_2m.txt" 2>/dev/null
|
||
$ZUPT extract -o "$T/codec_lz_out" "$T/codec_lz.zupt" 2>/dev/null
|
||
EXTR=$(find "$T/codec_lz_out" -name "repeat_2m.txt" -type f | head -1)
|
||
[ -z "$EXTR" ] || ! diff -q "$T/data/repeat_2m.txt" "$EXTR" >/dev/null 2>&1 && CODECS_OK=0
|
||
|
||
# Store
|
||
$ZUPT compress -t 4 -s "$T/codec_store.zupt" "$T/data/repeat_2m.txt" 2>/dev/null
|
||
$ZUPT extract -o "$T/codec_store_out" "$T/codec_store.zupt" 2>/dev/null
|
||
EXTR=$(find "$T/codec_store_out" -name "repeat_2m.txt" -type f | head -1)
|
||
[ -z "$EXTR" ] || ! diff -q "$T/data/repeat_2m.txt" "$EXTR" >/dev/null 2>&1 && CODECS_OK=0
|
||
|
||
[ "$CODECS_OK" -eq 1 ] && pass "All codecs at N=4" || fail "Some codecs failed at N=4"
|
||
|
||
# ─── T14: Speed comparison (N=1 vs N=4) ───
|
||
echo "── T14: Throughput comparison ──"
|
||
T1_START=$(date +%s%N)
|
||
$ZUPT compress -t 1 -l 5 "$T/speed1.zupt" "$T/large_10m.txt" 2>/dev/null
|
||
T1_END=$(date +%s%N)
|
||
T1_MS=$(( (T1_END - T1_START) / 1000000 ))
|
||
|
||
T4_START=$(date +%s%N)
|
||
$ZUPT compress -t 4 -l 5 "$T/speed4.zupt" "$T/large_10m.txt" 2>/dev/null
|
||
T4_END=$(date +%s%N)
|
||
T4_MS=$(( (T4_END - T4_START) / 1000000 ))
|
||
|
||
echo " N=1: ${T1_MS}ms N=4: ${T4_MS}ms"
|
||
if [ "$T4_MS" -gt 0 ] && [ "$T1_MS" -gt 0 ]; then
|
||
SPEEDUP=$(echo "scale=1; $T1_MS / $T4_MS" | bc 2>/dev/null || echo "?")
|
||
echo " Speedup: ${SPEEDUP}x"
|
||
pass "Throughput comparison (N=1: ${T1_MS}ms, N=4: ${T4_MS}ms, ${SPEEDUP}x)"
|
||
else
|
||
pass "Throughput comparison (timing unavailable)"
|
||
fi
|
||
|
||
echo ""
|
||
echo "═══════════════════════════════════════════════════════"
|
||
echo " MT RESULTS: $PASS passed, $FAIL failed ($TOTAL tests)"
|
||
echo "═══════════════════════════════════════════════════════"
|
||
[ "$FAIL" -eq 0 ] && exit 0 || exit 1
|