97 lines
4.0 KiB
Bash
97 lines
4.0 KiB
Bash
#!/usr/bin/env bash
|
||
set -euo pipefail
|
||
|
||
ROOT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)
|
||
# shellcheck source=tests/lib/assert.sh
|
||
source "${ROOT_DIR}/tests/lib/assert.sh"
|
||
|
||
maybe_enter_namespace() {
|
||
if (( EUID == 0 )); then
|
||
return 0
|
||
fi
|
||
|
||
if [[ ${IPF_IN_NAMESPACE:-0} == 1 ]]; then
|
||
return 0
|
||
fi
|
||
|
||
if command -v unshare >/dev/null 2>&1 && unshare -Urn true >/dev/null 2>&1; then
|
||
exec unshare -Urn env IPF_IN_NAMESPACE=1 bash "$0"
|
||
fi
|
||
|
||
printf 'SKIP: 交互测试需要 root 或可用的 unshare。\n'
|
||
exit 0
|
||
}
|
||
|
||
maybe_enter_namespace
|
||
|
||
TMP_DIR=$(mktemp -d)
|
||
trap 'rm -rf "${TMP_DIR}"' EXIT
|
||
|
||
export IPF_STORAGE_DIR="${TMP_DIR}/storage"
|
||
export IPF_STORAGE_DB="${IPF_STORAGE_DIR}/rules.db"
|
||
export IPF_LOCK_FILE="${IPF_STORAGE_DIR}/.lock"
|
||
export IPTABLES_MOCK_DIR="${TMP_DIR}/iptables-mock"
|
||
export IPTABLES_MOCK_LOG="${TMP_DIR}/iptables.log"
|
||
export IPTABLES_BIN="${ROOT_DIR}/tests/mocks/iptables"
|
||
export IP6TABLES_BIN="${ROOT_DIR}/tests/mocks/ip6tables"
|
||
export IPTABLES_SAVE_BIN="${ROOT_DIR}/tests/mocks/iptables-save"
|
||
export IP6TABLES_SAVE_BIN="${ROOT_DIR}/tests/mocks/ip6tables-save"
|
||
export NETFILTER_PERSISTENT_BIN="${ROOT_DIR}/tests/mocks/persist-mock.sh"
|
||
export PERSIST_MOCK_LOG="${TMP_DIR}/persist.log"
|
||
export IPF_SKIP_ENV_CHECK=1
|
||
export IPF_FORCE_PLAIN_UI=1
|
||
|
||
# shellcheck source=lib/common.sh
|
||
source "${ROOT_DIR}/lib/common.sh"
|
||
# shellcheck source=lib/storage.sh
|
||
source "${ROOT_DIR}/lib/storage.sh"
|
||
# shellcheck source=lib/persist.sh
|
||
source "${ROOT_DIR}/lib/persist.sh"
|
||
# shellcheck source=lib/iptables_ops.sh
|
||
source "${ROOT_DIR}/lib/iptables_ops.sh"
|
||
# shellcheck source=lib/rules_mgr.sh
|
||
source "${ROOT_DIR}/lib/rules_mgr.sh"
|
||
|
||
reset_mock_state() {
|
||
rm -rf "${IPTABLES_MOCK_DIR}" "${IPF_STORAGE_DIR}"
|
||
mkdir -p "${IPTABLES_MOCK_DIR}" "${IPF_STORAGE_DIR}"
|
||
: >"${IPTABLES_MOCK_LOG}"
|
||
: >"${PERSIST_MOCK_LOG}"
|
||
storage_init
|
||
}
|
||
|
||
reset_mock_state
|
||
export IPF_TEST_INPUTS=$'4\n2\n1\n8080\n1\n127.0.0.1\n80\ninteractive web\ny\n5\n1\n3\n1\ny\n0\n'
|
||
|
||
output=$("${ROOT_DIR}/iptables-forward.sh" 2>&1)
|
||
|
||
assert_contains "${output}" '== 环境状态 ==' 'interactive flow should open environment status view'
|
||
assert_contains "${output}" '规则总数: 0' 'environment status should show empty rule count before adding'
|
||
assert_contains "${output}" '== 添加新的转发规则 ==' 'interactive flow should enter add screen'
|
||
assert_contains "${output}" '描述: interactive web' 'interactive add summary should echo description'
|
||
assert_contains "${output}" '规则已保存到磁盘。' 'interactive flow should exercise menu save action'
|
||
assert_contains "${output}" 'interactive web' 'interactive list/delete flow should display the created description'
|
||
assert_contains "${output}" '规则已添加,UUID=' 'interactive flow should add one managed rule'
|
||
assert_contains "${output}" '已退出。' 'interactive flow should return cleanly from main menu'
|
||
|
||
assert_eq '0' "$(wc -l < "${IPF_STORAGE_DB}")" 'interactive add/delete flow should leave storage empty'
|
||
assert_eq '0' "$(wc -l < "${IPTABLES_MOCK_DIR}/state.v4")" 'interactive add/delete flow should leave runtime mock state empty'
|
||
assert_eq '4' "$(grep -Ec ' -A ' "${IPTABLES_MOCK_LOG}")" 'interactive add flow should emit four IPv4 add commands'
|
||
assert_eq '4' "$(grep -Ec ' -D ' "${IPTABLES_MOCK_LOG}")" 'interactive delete should emit four delete commands'
|
||
assert_eq '3' "$(grep -Ec 'persist-mock\.sh save' "${PERSIST_MOCK_LOG}")" 'interactive add/menu-save/delete flow should persist three times'
|
||
|
||
reset_mock_state
|
||
uuid=$(cmd_add_batch tcp 8081 127.0.0.1 81 4 'degraded menu' 2>/dev/null)
|
||
"${IPTABLES_BIN}" -D FORWARD \
|
||
-p tcp -s 127.0.0.1 --sport 81 \
|
||
-m conntrack --ctstate ESTABLISHED,RELATED \
|
||
-j ACCEPT \
|
||
-m comment --comment "MGMT:${uuid}"
|
||
export IPF_TEST_INPUTS=$'0\n'
|
||
|
||
degraded_output=$("${ROOT_DIR}/iptables-forward.sh" 2>&1)
|
||
assert_contains "${degraded_output}" '运行态: [!]' 'main menu should surface degraded runtime status'
|
||
assert_contains "${degraded_output}" '规则数: 1' 'main menu should still show current rule count'
|
||
|
||
pass 'test_interactive.sh'
|