- CLI binary: bin/gniza -> bin/gniza4cp - Install path: /usr/local/gniza4cp/ - Config path: /etc/gniza4cp/ - Log path: /var/log/gniza4cp/ - WHM plugin: gniza4cp-whm/ - cPanel plugin: cpanel/gniza4cp/ - AdminBin: Gniza4cp::Restore - Perl modules: Gniza4cpWHM::*, Gniza4cpCPanel::* - DaisyUI theme: gniza4cp - All internal references, branding, paths updated - Git remote updated to gniza4cp repo
331 lines
9.5 KiB
Bash
Executable File
331 lines
9.5 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# gniza4cp tests — utility functions
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
BASE_DIR="$(dirname "$SCRIPT_DIR")"
|
|
|
|
source "$BASE_DIR/lib/constants.sh"
|
|
source "$BASE_DIR/lib/utils.sh"
|
|
source "$BASE_DIR/lib/logging.sh"
|
|
source "$BASE_DIR/lib/config.sh"
|
|
source "$BASE_DIR/lib/accounts.sh"
|
|
|
|
TESTS_RUN=0
|
|
TESTS_PASSED=0
|
|
TESTS_FAILED=0
|
|
|
|
assert_eq() {
|
|
local expected="$1"
|
|
local actual="$2"
|
|
local msg="${3:-assertion}"
|
|
((TESTS_RUN++))
|
|
if [[ "$expected" == "$actual" ]]; then
|
|
((TESTS_PASSED++))
|
|
echo " ${C_GREEN}PASS${C_RESET}: $msg"
|
|
else
|
|
((TESTS_FAILED++))
|
|
echo " ${C_RED}FAIL${C_RESET}: $msg"
|
|
echo " expected: '$expected'"
|
|
echo " actual: '$actual'"
|
|
fi
|
|
}
|
|
|
|
assert_ok() {
|
|
local msg="${1:-assertion}"
|
|
((TESTS_RUN++))
|
|
((TESTS_PASSED++))
|
|
echo " ${C_GREEN}PASS${C_RESET}: $msg"
|
|
}
|
|
|
|
assert_fail() {
|
|
local msg="${1:-assertion}"
|
|
((TESTS_RUN++))
|
|
((TESTS_FAILED++))
|
|
echo " ${C_RED}FAIL${C_RESET}: $msg"
|
|
}
|
|
|
|
print_summary() {
|
|
echo ""
|
|
echo "=============================="
|
|
echo "Tests: $TESTS_RUN | Passed: $TESTS_PASSED | Failed: $TESTS_FAILED"
|
|
echo "=============================="
|
|
(( TESTS_FAILED > 0 )) && exit 1
|
|
exit 0
|
|
}
|
|
|
|
# ── Tests: utils.sh ───────────────────────────────────────────
|
|
|
|
echo "Testing utils.sh..."
|
|
|
|
# timestamp format
|
|
ts=$(timestamp)
|
|
if [[ "$ts" =~ ^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{6}$ ]]; then
|
|
assert_ok "timestamp format matches YYYY-MM-DDTHHMMSS"
|
|
else
|
|
assert_fail "timestamp format: got '$ts'"
|
|
fi
|
|
|
|
# human_size
|
|
assert_eq "500 B" "$(human_size 500)" "human_size 500B"
|
|
assert_eq "1.0 KB" "$(human_size 1024)" "human_size 1KB"
|
|
assert_eq "1.0 MB" "$(human_size 1048576)" "human_size 1MB"
|
|
assert_eq "1.0 GB" "$(human_size 1073741824)" "human_size 1GB"
|
|
assert_eq "2.5 GB" "$(human_size 2684354560)" "human_size 2.5GB"
|
|
assert_eq "5.3 KB" "$(human_size 5500)" "human_size 5.3KB"
|
|
|
|
# human_duration
|
|
assert_eq "5s" "$(human_duration 5)" "human_duration 5s"
|
|
assert_eq "2m 30s" "$(human_duration 150)" "human_duration 2m30s"
|
|
assert_eq "1h 5m 30s" "$(human_duration 3930)" "human_duration 1h5m30s"
|
|
|
|
# require_cmd
|
|
if require_cmd bash 2>/dev/null; then
|
|
assert_ok "require_cmd bash"
|
|
else
|
|
assert_fail "require_cmd bash"
|
|
fi
|
|
|
|
# ── Tests: accounts.sh filter ─────────────────────────────────
|
|
|
|
echo ""
|
|
echo "Testing accounts.sh filter_accounts..."
|
|
|
|
# filter with exclusions
|
|
EXCLUDE_ACCOUNTS="nobody,system"
|
|
INCLUDE_ACCOUNTS=""
|
|
result=$(filter_accounts $'alice\nbob\nnobody\nsystem\ncharlie')
|
|
assert_eq $'alice\nbob\ncharlie' "$result" "filter excludes nobody,system"
|
|
|
|
# filter with inclusions
|
|
INCLUDE_ACCOUNTS="alice,bob"
|
|
EXCLUDE_ACCOUNTS="nobody"
|
|
result=$(filter_accounts $'alice\nbob\nnobody\ncharlie')
|
|
assert_eq $'alice\nbob' "$result" "filter includes only alice,bob"
|
|
|
|
# filter with both include and exclude
|
|
INCLUDE_ACCOUNTS="alice,bob,nobody"
|
|
EXCLUDE_ACCOUNTS="nobody"
|
|
result=$(filter_accounts $'alice\nbob\nnobody')
|
|
assert_eq $'alice\nbob' "$result" "filter include+exclude: nobody excluded from include list"
|
|
|
|
# ── Tests: config.sh validation ───────────────────────────────
|
|
|
|
echo ""
|
|
echo "Testing config.sh validation..."
|
|
|
|
# Suppress log output for validation tests
|
|
LOG_FILE="/dev/null"
|
|
|
|
# Create a temp file to use as fake SSH key
|
|
_test_key=$(mktemp)
|
|
trap 'rm -f "$_test_key"' EXIT
|
|
|
|
# Test validation with invalid LOG_LEVEL
|
|
NOTIFY_ON="failure"
|
|
LOG_LEVEL="invalid"
|
|
if validate_config 2>/dev/null; then
|
|
assert_fail "validate_config should fail with invalid LOG_LEVEL"
|
|
else
|
|
assert_ok "validate_config catches invalid LOG_LEVEL"
|
|
fi
|
|
|
|
# Test validation with valid config (REMOTE_* not validated here — per-remote only)
|
|
NOTIFY_ON="failure"
|
|
LOG_LEVEL="info"
|
|
if validate_config 2>/dev/null; then
|
|
assert_ok "validate_config passes with valid config"
|
|
else
|
|
assert_fail "validate_config should pass with valid config"
|
|
fi
|
|
|
|
# Test invalid NOTIFY_ON
|
|
NOTIFY_ON="invalid"
|
|
if validate_config 2>/dev/null; then
|
|
assert_fail "validate_config should fail with invalid NOTIFY_ON"
|
|
else
|
|
assert_ok "validate_config catches invalid NOTIFY_ON"
|
|
fi
|
|
|
|
# ── Tests: validate_timestamp ────────────────────────────────
|
|
|
|
echo ""
|
|
echo "Testing validate_timestamp..."
|
|
|
|
if validate_timestamp "2024-01-15T023000" 2>/dev/null; then
|
|
assert_ok "validate_timestamp accepts valid format"
|
|
else
|
|
assert_fail "validate_timestamp should accept 2024-01-15T023000"
|
|
fi
|
|
|
|
if validate_timestamp "2024-12-31T235959" 2>/dev/null; then
|
|
assert_ok "validate_timestamp accepts end-of-year"
|
|
else
|
|
assert_fail "validate_timestamp should accept 2024-12-31T235959"
|
|
fi
|
|
|
|
if validate_timestamp "not-a-timestamp" 2>/dev/null; then
|
|
assert_fail "validate_timestamp should reject garbage"
|
|
else
|
|
assert_ok "validate_timestamp rejects garbage input"
|
|
fi
|
|
|
|
if validate_timestamp "2024-01-15 02:30:00" 2>/dev/null; then
|
|
assert_fail "validate_timestamp should reject spaces/colons"
|
|
else
|
|
assert_ok "validate_timestamp rejects spaces/colons"
|
|
fi
|
|
|
|
if validate_timestamp "" 2>/dev/null; then
|
|
assert_fail "validate_timestamp should reject empty string"
|
|
else
|
|
assert_ok "validate_timestamp rejects empty string"
|
|
fi
|
|
|
|
# ── Tests: validate_account_name ─────────────────────────────
|
|
|
|
echo ""
|
|
echo "Testing validate_account_name..."
|
|
|
|
if validate_account_name "alice" 2>/dev/null; then
|
|
assert_ok "validate_account_name accepts 'alice'"
|
|
else
|
|
assert_fail "validate_account_name should accept 'alice'"
|
|
fi
|
|
|
|
if validate_account_name "user123" 2>/dev/null; then
|
|
assert_ok "validate_account_name accepts 'user123'"
|
|
else
|
|
assert_fail "validate_account_name should accept 'user123'"
|
|
fi
|
|
|
|
if validate_account_name "my-site" 2>/dev/null; then
|
|
assert_ok "validate_account_name accepts 'my-site'"
|
|
else
|
|
assert_fail "validate_account_name should accept 'my-site'"
|
|
fi
|
|
|
|
if validate_account_name "Root" 2>/dev/null; then
|
|
assert_fail "validate_account_name should reject uppercase"
|
|
else
|
|
assert_ok "validate_account_name rejects uppercase"
|
|
fi
|
|
|
|
if validate_account_name "123user" 2>/dev/null; then
|
|
assert_fail "validate_account_name should reject leading digit"
|
|
else
|
|
assert_ok "validate_account_name rejects leading digit"
|
|
fi
|
|
|
|
if validate_account_name "../etc/passwd" 2>/dev/null; then
|
|
assert_fail "validate_account_name should reject path traversal"
|
|
else
|
|
assert_ok "validate_account_name rejects path traversal"
|
|
fi
|
|
|
|
if validate_account_name "" 2>/dev/null; then
|
|
assert_fail "validate_account_name should reject empty"
|
|
else
|
|
assert_ok "validate_account_name rejects empty string"
|
|
fi
|
|
|
|
if validate_account_name "a]b" 2>/dev/null; then
|
|
assert_fail "validate_account_name should reject special chars"
|
|
else
|
|
assert_ok "validate_account_name rejects special chars"
|
|
fi
|
|
|
|
# ── Tests: _safe_source_config ───────────────────────────────
|
|
|
|
echo ""
|
|
echo "Testing _safe_source_config..."
|
|
|
|
_test_conf=$(mktemp)
|
|
cat > "$_test_conf" <<'CONF'
|
|
# Comment line
|
|
MYKEY="hello world"
|
|
ANOTHER='single quoted'
|
|
BARE=noquotes
|
|
|
|
# blank lines above
|
|
NUMERIC=42
|
|
CONF
|
|
|
|
# Clear any previous values
|
|
unset MYKEY ANOTHER BARE NUMERIC 2>/dev/null || true
|
|
|
|
_safe_source_config "$_test_conf"
|
|
assert_eq "hello world" "$MYKEY" "_safe_source_config reads double-quoted value"
|
|
assert_eq "single quoted" "$ANOTHER" "_safe_source_config reads single-quoted value"
|
|
assert_eq "noquotes" "$BARE" "_safe_source_config reads bare value"
|
|
assert_eq "42" "$NUMERIC" "_safe_source_config reads numeric value"
|
|
|
|
# Test that malicious content is not executed
|
|
_test_conf2=$(mktemp)
|
|
cat > "$_test_conf2" <<'CONF'
|
|
SAFE_KEY="safe"
|
|
$(echo pwned)
|
|
`rm -rf /`
|
|
CONF
|
|
|
|
unset SAFE_KEY 2>/dev/null || true
|
|
_safe_source_config "$_test_conf2"
|
|
assert_eq "safe" "$SAFE_KEY" "_safe_source_config reads safe key from malicious file"
|
|
rm -f "$_test_conf" "$_test_conf2"
|
|
|
|
# ── Tests: config.sh validation (new fields) ────────────────
|
|
|
|
echo ""
|
|
echo "Testing config.sh validation (numeric + RSYNC_EXTRA_OPTS)..."
|
|
|
|
# Valid config baseline
|
|
NOTIFY_ON="failure"
|
|
LOG_LEVEL="info"
|
|
SMTP_HOST=""
|
|
SSH_TIMEOUT="30"
|
|
SSH_RETRIES="3"
|
|
LOG_RETAIN="90"
|
|
RSYNC_EXTRA_OPTS=""
|
|
|
|
if validate_config 2>/dev/null; then
|
|
assert_ok "validate_config passes with valid numeric fields"
|
|
else
|
|
assert_fail "validate_config should pass with valid config"
|
|
fi
|
|
|
|
# Invalid SSH_TIMEOUT
|
|
SSH_TIMEOUT="abc"
|
|
if validate_config 2>/dev/null; then
|
|
assert_fail "validate_config should fail with non-numeric SSH_TIMEOUT"
|
|
else
|
|
assert_ok "validate_config catches non-numeric SSH_TIMEOUT"
|
|
fi
|
|
SSH_TIMEOUT="30"
|
|
|
|
# Invalid SSH_RETRIES
|
|
SSH_RETRIES="abc"
|
|
if validate_config 2>/dev/null; then
|
|
assert_fail "validate_config should fail with non-numeric SSH_RETRIES"
|
|
else
|
|
assert_ok "validate_config catches non-numeric SSH_RETRIES"
|
|
fi
|
|
SSH_RETRIES="3"
|
|
|
|
# Invalid RSYNC_EXTRA_OPTS (shell metacharacters)
|
|
RSYNC_EXTRA_OPTS='--rsh="evil command"'
|
|
if validate_config 2>/dev/null; then
|
|
assert_fail "validate_config should fail with dangerous RSYNC_EXTRA_OPTS"
|
|
else
|
|
assert_ok "validate_config catches dangerous RSYNC_EXTRA_OPTS"
|
|
fi
|
|
|
|
# Valid RSYNC_EXTRA_OPTS
|
|
RSYNC_EXTRA_OPTS="--compress --bwlimit=1000"
|
|
if validate_config 2>/dev/null; then
|
|
assert_ok "validate_config accepts valid RSYNC_EXTRA_OPTS"
|
|
else
|
|
assert_fail "validate_config should accept --compress --bwlimit=1000"
|
|
fi
|
|
RSYNC_EXTRA_OPTS=""
|
|
|
|
print_summary
|