Serialize rule writes and add tests
This commit is contained in:
@@ -3,9 +3,31 @@ set -euo pipefail
|
||||
|
||||
: "${PERSIST_MOCK_LOG:=/tmp/persist-mock.log}"
|
||||
: "${PERSIST_MOCK_FAIL:=0}"
|
||||
: "${PERSIST_MOCK_DELAY_SECS:=0}"
|
||||
: "${PERSIST_MOCK_ACTIVE_DIR:=}"
|
||||
: "${PERSIST_MOCK_FAIL_ON_CONCURRENT:=0}"
|
||||
|
||||
printf '%s %s\n' "$(basename -- "$0")" "$*" >>"${PERSIST_MOCK_LOG}"
|
||||
|
||||
cleanup() {
|
||||
[[ -n ${PERSIST_MOCK_ACTIVE_DIR} ]] || return 0
|
||||
rmdir "${PERSIST_MOCK_ACTIVE_DIR}" 2>/dev/null || true
|
||||
}
|
||||
|
||||
if [[ -n ${PERSIST_MOCK_ACTIVE_DIR} ]]; then
|
||||
if ! mkdir "${PERSIST_MOCK_ACTIVE_DIR}" 2>/dev/null; then
|
||||
if [[ ${PERSIST_MOCK_FAIL_ON_CONCURRENT} == 1 ]]; then
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
trap cleanup EXIT
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ ${PERSIST_MOCK_DELAY_SECS} != 0 ]]; then
|
||||
sleep "${PERSIST_MOCK_DELAY_SECS}"
|
||||
fi
|
||||
|
||||
if [[ ${PERSIST_MOCK_FAIL} == 1 ]]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@@ -13,6 +13,14 @@ status_of() {
|
||||
printf '%s\n' "${rc}"
|
||||
}
|
||||
|
||||
wait_status() {
|
||||
local pid=$1
|
||||
set +e
|
||||
wait "${pid}"
|
||||
WAIT_STATUS_RESULT=$?
|
||||
set -e
|
||||
}
|
||||
|
||||
TMP_DIR=$(mktemp -d)
|
||||
trap 'rm -rf "${TMP_DIR}"' EXIT
|
||||
|
||||
@@ -46,6 +54,7 @@ reset_mock_state() {
|
||||
: >"${PERSIST_MOCK_LOG}"
|
||||
unset IPTABLES_MOCK_FAIL_ON_N || true
|
||||
unset PERSIST_MOCK_FAIL || true
|
||||
unset PERSIST_MOCK_DELAY_SECS PERSIST_MOCK_ACTIVE_DIR PERSIST_MOCK_FAIL_ON_CONCURRENT || true
|
||||
storage_init
|
||||
}
|
||||
|
||||
@@ -91,4 +100,33 @@ assert_contains "$(storage_get "${uuid_delete_rollback}")" "uuid=${uuid_delete_r
|
||||
assert_contains "$(ipt_find_by_uuid "${uuid_delete_rollback}")" "MGMT:${uuid_delete_rollback}" 'persist_save failure on delete should restore runtime rules'
|
||||
assert_eq '2' "$(grep -Ec 'persist-mock\.sh save' "${PERSIST_MOCK_LOG}")" 'persist_save failure on delete should include add and delete save attempts'
|
||||
|
||||
reset_mock_state
|
||||
uuid_storage_delete_rollback=$(cmd_add_batch tcp 9200 127.0.0.1 93 4 'storage rollback delete')
|
||||
storage_delete_impl=$(declare -f storage_delete_unlocked)
|
||||
storage_delete_unlocked() {
|
||||
return 1
|
||||
}
|
||||
assert_eq '1' "$(status_of cmd_delete_uuid "${uuid_storage_delete_rollback}")" 'cmd_delete_uuid should fail when storage delete fails'
|
||||
assert_eq '1' "$(storage_count)" 'storage delete failure should keep storage record'
|
||||
assert_contains "$(storage_get "${uuid_storage_delete_rollback}")" "uuid=${uuid_storage_delete_rollback}" 'storage delete failure should keep original storage line'
|
||||
assert_contains "$(ipt_find_by_uuid "${uuid_storage_delete_rollback}")" "MGMT:${uuid_storage_delete_rollback}" 'storage delete failure should restore runtime rules'
|
||||
eval "${storage_delete_impl}"
|
||||
|
||||
reset_mock_state
|
||||
export PERSIST_MOCK_DELAY_SECS=0.2
|
||||
export PERSIST_MOCK_ACTIVE_DIR="${TMP_DIR}/persist-active"
|
||||
export PERSIST_MOCK_FAIL_ON_CONCURRENT=1
|
||||
cmd_add_batch tcp 9300 127.0.0.1 94 4 'parallel one' >"${TMP_DIR}/parallel-1.out" 2>"${TMP_DIR}/parallel-1.err" &
|
||||
pid1=$!
|
||||
sleep 0.05
|
||||
cmd_add_batch tcp 9301 127.0.0.1 95 4 'parallel two' >"${TMP_DIR}/parallel-2.out" 2>"${TMP_DIR}/parallel-2.err" &
|
||||
pid2=$!
|
||||
wait_status "${pid1}"
|
||||
assert_eq '0' "${WAIT_STATUS_RESULT}" 'first concurrent add should succeed'
|
||||
wait_status "${pid2}"
|
||||
assert_eq '0' "${WAIT_STATUS_RESULT}" 'second concurrent add should wait and succeed'
|
||||
assert_eq '2' "$(storage_count)" 'concurrent adds should persist both rules'
|
||||
assert_eq '2' "$(grep -Ec 'persist-mock\.sh save' "${PERSIST_MOCK_LOG}")" 'concurrent adds should serialize persist_save calls'
|
||||
unset PERSIST_MOCK_DELAY_SECS PERSIST_MOCK_ACTIVE_DIR PERSIST_MOCK_FAIL_ON_CONCURRENT
|
||||
|
||||
pass 'test_rules_unit.sh'
|
||||
|
||||
Reference in New Issue
Block a user