mirror of
https://oauth2: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@github.com/m1ngsama/TNT.git
synced 2026-06-26 06:54:38 +08:00
test: cover connection limit regressions
This commit is contained in:
parent
6d5c77b850
commit
095491927a
11 changed files with 159 additions and 46 deletions
1
.github/workflows/ci.yml
vendored
1
.github/workflows/ci.yml
vendored
|
|
@ -36,6 +36,7 @@ jobs:
|
||||||
- name: Run comprehensive tests
|
- name: Run comprehensive tests
|
||||||
run: |
|
run: |
|
||||||
make test
|
make test
|
||||||
|
make connection-limit-test
|
||||||
cd tests
|
cd tests
|
||||||
./test_security_features.sh
|
./test_security_features.sh
|
||||||
# Skipping anonymous access test in CI as it requires interactive pty handling which might be flaky
|
# Skipping anonymous access test in CI as it requires interactive pty handling which might be flaky
|
||||||
|
|
|
||||||
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -17,3 +17,4 @@ tests/unit/test_system_message
|
||||||
tests/unit/test_help_text
|
tests/unit/test_help_text
|
||||||
tests/unit/test_support_text
|
tests/unit/test_support_text
|
||||||
tests/unit/test_cli_text
|
tests/unit/test_cli_text
|
||||||
|
tests/unit/test_ratelimit
|
||||||
|
|
|
||||||
6
Makefile
6
Makefile
|
|
@ -30,7 +30,7 @@ BINDIR ?= $(PREFIX)/bin
|
||||||
MANDIR ?= $(PREFIX)/share/man
|
MANDIR ?= $(PREFIX)/share/man
|
||||||
SYSTEMD_UNIT_DIR ?= $(PREFIX)/lib/systemd/system
|
SYSTEMD_UNIT_DIR ?= $(PREFIX)/lib/systemd/system
|
||||||
|
|
||||||
.PHONY: all clean install install-systemd uninstall uninstall-systemd debug release release-check release-check-strict asan valgrind check test test-advisory unit-test integration-test info
|
.PHONY: all clean install install-systemd uninstall uninstall-systemd debug release release-check release-check-strict asan valgrind check test test-advisory unit-test integration-test connection-limit-test info
|
||||||
|
|
||||||
all: $(TARGET)
|
all: $(TARGET)
|
||||||
|
|
||||||
|
|
@ -112,6 +112,10 @@ integration-test: all
|
||||||
@cd tests && PORT=$$(($${PORT:-2222} + 1)) ./test_exec_mode.sh
|
@cd tests && PORT=$$(($${PORT:-2222} + 1)) ./test_exec_mode.sh
|
||||||
@cd tests && PORT=$$(($${PORT:-2222} + 2)) ./test_interactive_input.sh
|
@cd tests && PORT=$$(($${PORT:-2222} + 2)) ./test_interactive_input.sh
|
||||||
|
|
||||||
|
connection-limit-test: all
|
||||||
|
@echo "Running connection limit tests..."
|
||||||
|
@cd tests && PORT=$${PORT:-2222} ./test_connection_limits.sh
|
||||||
|
|
||||||
# Show build info
|
# Show build info
|
||||||
info:
|
info:
|
||||||
@echo "Compiler: $(CC)"
|
@echo "Compiler: $(CC)"
|
||||||
|
|
|
||||||
|
|
@ -202,6 +202,7 @@ make clean # clean build artifacts
|
||||||
```sh
|
```sh
|
||||||
make test # run comprehensive test suite and fail on regressions
|
make test # run comprehensive test suite and fail on regressions
|
||||||
make test-advisory # run integration tests as advisory checks
|
make test-advisory # run integration tests as advisory checks
|
||||||
|
make connection-limit-test # verify per-IP concurrency and rate limits
|
||||||
|
|
||||||
# Individual tests
|
# Individual tests
|
||||||
cd tests
|
cd tests
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,12 @@
|
||||||
environments can use `make test-advisory` for the previous advisory behavior.
|
environments can use `make test-advisory` for the previous advisory behavior.
|
||||||
- Removed the duplicate `deploy.yml` CI workflow so automated checks stay
|
- Removed the duplicate `deploy.yml` CI workflow so automated checks stay
|
||||||
focused on CI while production deployment remains manual.
|
focused on CI while production deployment remains manual.
|
||||||
|
- Fixed the per-IP connection-rate limit to allow the configured number of
|
||||||
|
attempts before blocking, added unit coverage, and exposed
|
||||||
|
`make connection-limit-test` for the black-box limit regression test.
|
||||||
|
- Security feature checks now use isolated ports and temporary state
|
||||||
|
directories, so they no longer require `timeout`/`gtimeout` or write
|
||||||
|
`host_key` / `messages.log` into the test directory.
|
||||||
- NORMAL mode now opens at the latest visible messages instead of the oldest
|
- NORMAL mode now opens at the latest visible messages instead of the oldest
|
||||||
in-memory message. Use `k`/PageUp to browse older history and `G`/End to
|
in-memory message. Use `k`/PageUp to browse older history and `G`/End to
|
||||||
return to the latest messages.
|
return to the latest messages.
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ Every push or PR automatically runs:
|
||||||
- Build on Ubuntu
|
- Build on Ubuntu
|
||||||
- AddressSanitizer build
|
- AddressSanitizer build
|
||||||
- Unit and strict integration tests
|
- Unit and strict integration tests
|
||||||
|
- Per-IP concurrency and connection-rate limit tests
|
||||||
- Release/package preflight (`make release-check`)
|
- Release/package preflight (`make release-check`)
|
||||||
|
|
||||||
Check status:
|
Check status:
|
||||||
|
|
|
||||||
|
|
@ -161,6 +161,7 @@ make install # Install to /usr/local/bin
|
||||||
```sh
|
```sh
|
||||||
make test # Run all tests and fail on regressions
|
make test # Run all tests and fail on regressions
|
||||||
make test-advisory # Run integration tests as advisory checks
|
make test-advisory # Run integration tests as advisory checks
|
||||||
|
make connection-limit-test # Verify per-IP concurrency and rate limits
|
||||||
|
|
||||||
# Individual tests
|
# Individual tests
|
||||||
cd tests
|
cd tests
|
||||||
|
|
|
||||||
|
|
@ -134,7 +134,7 @@ bool ratelimit_check_ip(const char *ip) {
|
||||||
}
|
}
|
||||||
|
|
||||||
entry->recent_connection_count++;
|
entry->recent_connection_count++;
|
||||||
if (entry->recent_connection_count >= g_max_conn_rate_per_ip) {
|
if (entry->recent_connection_count > g_max_conn_rate_per_ip) {
|
||||||
entry->is_blocked = true;
|
entry->is_blocked = true;
|
||||||
entry->block_until = now + BLOCK_DURATION;
|
entry->block_until = now + BLOCK_DURATION;
|
||||||
pthread_mutex_unlock(&g_rate_limit_lock);
|
pthread_mutex_unlock(&g_rate_limit_lock);
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,9 @@ NC='\033[0m'
|
||||||
|
|
||||||
PASS=0
|
PASS=0
|
||||||
FAIL=0
|
FAIL=0
|
||||||
|
STATE_ROOT=$(mktemp -d "${TMPDIR:-/tmp}/tnt-security-test.XXXXXX")
|
||||||
|
SERVER_PIDS=""
|
||||||
|
NEXT_PORT=${PORT:-13600}
|
||||||
|
|
||||||
print_test() {
|
print_test() {
|
||||||
echo -e "\n${YELLOW}[TEST]${NC} $1"
|
echo -e "\n${YELLOW}[TEST]${NC} $1"
|
||||||
|
|
@ -27,8 +30,11 @@ fail() {
|
||||||
}
|
}
|
||||||
|
|
||||||
cleanup() {
|
cleanup() {
|
||||||
pkill -f "^\.\./tnt" 2>/dev/null || true
|
for pid in $SERVER_PIDS; do
|
||||||
sleep 1
|
kill "$pid" 2>/dev/null || true
|
||||||
|
wait "$pid" 2>/dev/null || true
|
||||||
|
done
|
||||||
|
rm -rf "$STATE_ROOT"
|
||||||
}
|
}
|
||||||
|
|
||||||
trap cleanup EXIT
|
trap cleanup EXIT
|
||||||
|
|
@ -43,23 +49,47 @@ if [ ! -f "$BIN" ]; then
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Detect timeout command
|
run_server_probe() {
|
||||||
TIMEOUT_CMD="timeout"
|
local name="$1"
|
||||||
if command -v gtimeout >/dev/null 2>&1; then
|
local port="$NEXT_PORT"
|
||||||
TIMEOUT_CMD="gtimeout"
|
local pid
|
||||||
|
local state_dir
|
||||||
|
local log_file
|
||||||
|
shift
|
||||||
|
|
||||||
|
NEXT_PORT=$((NEXT_PORT + 1))
|
||||||
|
state_dir="$STATE_ROOT/$name"
|
||||||
|
log_file="$state_dir/server.log"
|
||||||
|
mkdir -p "$state_dir"
|
||||||
|
|
||||||
|
"$@" "$BIN" -p "$port" -d "$state_dir" >"$log_file" 2>&1 &
|
||||||
|
pid=$!
|
||||||
|
SERVER_PIDS="$SERVER_PIDS $pid"
|
||||||
|
|
||||||
|
for _ in 1 2 3 4 5 6 7 8; do
|
||||||
|
if grep -q "TNT chat server listening" "$log_file"; then
|
||||||
|
kill "$pid" 2>/dev/null || true
|
||||||
|
wait "$pid" 2>/dev/null || true
|
||||||
|
return 0
|
||||||
fi
|
fi
|
||||||
|
if ! kill -0 "$pid" 2>/dev/null; then
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
sleep 1
|
||||||
|
done
|
||||||
|
|
||||||
|
kill "$pid" 2>/dev/null || true
|
||||||
|
wait "$pid" 2>/dev/null || true
|
||||||
|
sed -n '1,120p' "$log_file"
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
# Test 1: 4096-bit RSA Key Generation
|
# Test 1: 4096-bit RSA Key Generation
|
||||||
print_test "1. RSA 4096-bit Key Generation"
|
print_test "1. RSA 4096-bit Key Generation"
|
||||||
rm -f host_key
|
KEY_DIR="$STATE_ROOT/host-key"
|
||||||
$BIN &
|
|
||||||
PID=$!
|
|
||||||
sleep 8 # Wait for key generation
|
|
||||||
kill $PID 2>/dev/null || true
|
|
||||||
sleep 1
|
|
||||||
|
|
||||||
if [ -f host_key ]; then
|
if run_server_probe host-key env && [ -f "$KEY_DIR/host_key" ]; then
|
||||||
KEY_SIZE=$(ssh-keygen -l -f host_key 2>/dev/null | awk '{print $1}')
|
KEY_SIZE=$(ssh-keygen -l -f "$KEY_DIR/host_key" 2>/dev/null | awk '{print $1}')
|
||||||
if [ "$KEY_SIZE" = "4096" ]; then
|
if [ "$KEY_SIZE" = "4096" ]; then
|
||||||
pass "RSA key upgraded to 4096 bits (was 2048)"
|
pass "RSA key upgraded to 4096 bits (was 2048)"
|
||||||
else
|
else
|
||||||
|
|
@ -68,9 +98,9 @@ if [ -f host_key ]; then
|
||||||
|
|
||||||
# Check permissions
|
# Check permissions
|
||||||
if [[ "$OSTYPE" == "darwin"* ]]; then
|
if [[ "$OSTYPE" == "darwin"* ]]; then
|
||||||
PERMS=$(stat -f "%OLp" host_key)
|
PERMS=$(stat -f "%OLp" "$KEY_DIR/host_key")
|
||||||
else
|
else
|
||||||
PERMS=$(stat -c "%a" host_key)
|
PERMS=$(stat -c "%a" "$KEY_DIR/host_key")
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$PERMS" = "600" ]; then
|
if [ "$PERMS" = "600" ]; then
|
||||||
|
|
@ -86,33 +116,34 @@ fi
|
||||||
print_test "2. Environment Variable Configuration"
|
print_test "2. Environment Variable Configuration"
|
||||||
|
|
||||||
# Test bind address
|
# Test bind address
|
||||||
TNT_BIND_ADDR=127.0.0.1 $TIMEOUT_CMD 3 $BIN 2>&1 | grep -q "TNT chat server" && \
|
run_server_probe bind-addr env TNT_BIND_ADDR=127.0.0.1 && \
|
||||||
pass "TNT_BIND_ADDR configuration works" || fail "TNT_BIND_ADDR not working"
|
pass "TNT_BIND_ADDR configuration works" || fail "TNT_BIND_ADDR not working"
|
||||||
|
|
||||||
# Test with access token set (just verify it starts)
|
# Test with access token set (just verify it starts)
|
||||||
TNT_ACCESS_TOKEN="test123" $TIMEOUT_CMD 3 $BIN 2>&1 | grep -q "TNT chat server" && \
|
run_server_probe access-token env TNT_ACCESS_TOKEN="test123" && \
|
||||||
pass "TNT_ACCESS_TOKEN configuration accepted" || fail "TNT_ACCESS_TOKEN not working"
|
pass "TNT_ACCESS_TOKEN configuration accepted" || fail "TNT_ACCESS_TOKEN not working"
|
||||||
|
|
||||||
# Test max connections configuration
|
# Test max connections configuration
|
||||||
TNT_MAX_CONNECTIONS=10 $TIMEOUT_CMD 3 $BIN 2>&1 | grep -q "TNT chat server" && \
|
run_server_probe max-connections env TNT_MAX_CONNECTIONS=10 && \
|
||||||
pass "TNT_MAX_CONNECTIONS configuration accepted" || fail "TNT_MAX_CONNECTIONS not working"
|
pass "TNT_MAX_CONNECTIONS configuration accepted" || fail "TNT_MAX_CONNECTIONS not working"
|
||||||
|
|
||||||
# Test per-IP connection rate configuration
|
# Test per-IP connection rate configuration
|
||||||
TNT_MAX_CONN_RATE_PER_IP=20 $TIMEOUT_CMD 3 $BIN 2>&1 | grep -q "TNT chat server" && \
|
run_server_probe conn-rate env TNT_MAX_CONN_RATE_PER_IP=20 && \
|
||||||
pass "TNT_MAX_CONN_RATE_PER_IP configuration accepted" || fail "TNT_MAX_CONN_RATE_PER_IP not working"
|
pass "TNT_MAX_CONN_RATE_PER_IP configuration accepted" || fail "TNT_MAX_CONN_RATE_PER_IP not working"
|
||||||
|
|
||||||
# Test rate limit toggle
|
# Test rate limit toggle
|
||||||
TNT_RATE_LIMIT=0 $TIMEOUT_CMD 3 $BIN 2>&1 | grep -q "TNT chat server" && \
|
run_server_probe rate-toggle env TNT_RATE_LIMIT=0 && \
|
||||||
pass "TNT_RATE_LIMIT configuration accepted" || fail "TNT_RATE_LIMIT not working"
|
pass "TNT_RATE_LIMIT configuration accepted" || fail "TNT_RATE_LIMIT not working"
|
||||||
|
|
||||||
sleep 1
|
sleep 1
|
||||||
|
|
||||||
# Test 3: Input Validation in Message Log
|
# Test 3: Input Validation in Message Log
|
||||||
print_test "3. Message Log Sanitization"
|
print_test "3. Message Log Sanitization"
|
||||||
rm -f messages.log
|
MESSAGE_DIR="$STATE_ROOT/message-log"
|
||||||
|
mkdir -p "$MESSAGE_DIR"
|
||||||
|
|
||||||
# Create a test message log with potentially dangerous content
|
# Create a test message log with potentially dangerous content
|
||||||
cat > messages.log <<EOF
|
cat > "$MESSAGE_DIR/messages.log" <<EOF
|
||||||
2026-01-22T10:00:00Z|testuser|normal message
|
2026-01-22T10:00:00Z|testuser|normal message
|
||||||
2026-01-22T10:01:00Z|user|with|pipes|attempt to break format
|
2026-01-22T10:01:00Z|user|with|pipes|attempt to break format
|
||||||
2026-01-22T10:02:00Z|user
|
2026-01-22T10:02:00Z|user
|
||||||
|
|
@ -121,15 +152,9 @@ newline
|
||||||
2026-01-22T10:03:00Z|validuser|valid content
|
2026-01-22T10:03:00Z|validuser|valid content
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
# Start server and let it load messages
|
# Start server and let it load messages, then verify it kept valid entries.
|
||||||
$BIN &
|
if run_server_probe message-log env >/dev/null &&
|
||||||
PID=$!
|
grep -q "validuser" "$MESSAGE_DIR/messages.log"; then
|
||||||
sleep 3
|
|
||||||
kill $PID 2>/dev/null || true
|
|
||||||
sleep 1
|
|
||||||
|
|
||||||
# Check if server handled malformed log entries safely
|
|
||||||
if grep -q "validuser" messages.log; then
|
|
||||||
pass "Server loads messages from log file"
|
pass "Server loads messages from log file"
|
||||||
else
|
else
|
||||||
fail "Server message loading issue"
|
fail "Server message loading issue"
|
||||||
|
|
@ -215,21 +240,16 @@ fi
|
||||||
|
|
||||||
# Test 7: Resource Management (Dynamic Allocation)
|
# Test 7: Resource Management (Dynamic Allocation)
|
||||||
print_test "7. Resource Management (Large Log Files)"
|
print_test "7. Resource Management (Large Log Files)"
|
||||||
rm -f messages.log
|
LARGE_DIR="$STATE_ROOT/large-log"
|
||||||
|
mkdir -p "$LARGE_DIR"
|
||||||
# Create a large message log (2000 entries, more than old fixed 1000 limit)
|
# Create a large message log (2000 entries, more than old fixed 1000 limit)
|
||||||
for i in $(seq 1 2000); do
|
for i in $(seq 1 2000); do
|
||||||
echo "2026-01-22T$(printf "%02d" $((i/100))):$(printf "%02d" $((i%60))):00Z|user$i|message $i" >> messages.log
|
echo "2026-01-22T$(printf "%02d" $((i/100))):$(printf "%02d" $((i%60))):00Z|user$i|message $i" >> "$LARGE_DIR/messages.log"
|
||||||
done
|
done
|
||||||
|
|
||||||
$BIN &
|
|
||||||
PID=$!
|
|
||||||
sleep 4
|
|
||||||
kill $PID 2>/dev/null || true
|
|
||||||
sleep 1
|
|
||||||
|
|
||||||
# Check if server started successfully with large log
|
# Check if server started successfully with large log
|
||||||
if [ -f messages.log ]; then
|
if run_server_probe large-log env >/dev/null && [ -f "$LARGE_DIR/messages.log" ]; then
|
||||||
LINE_COUNT=$(wc -l < messages.log)
|
LINE_COUNT=$(wc -l < "$LARGE_DIR/messages.log")
|
||||||
if [ "$LINE_COUNT" -ge 2000 ]; then
|
if [ "$LINE_COUNT" -ge 2000 ]; then
|
||||||
pass "Server handles large message log (${LINE_COUNT} messages)"
|
pass "Server handles large message log (${LINE_COUNT} messages)"
|
||||||
else
|
else
|
||||||
|
|
|
||||||
|
|
@ -20,8 +20,9 @@ I18N_SRC = ../../src/i18n.c
|
||||||
SYSTEM_MESSAGE_SRC = ../../src/system_message.c
|
SYSTEM_MESSAGE_SRC = ../../src/system_message.c
|
||||||
HELP_TEXT_SRC = ../../src/help_text.c
|
HELP_TEXT_SRC = ../../src/help_text.c
|
||||||
SUPPORT_TEXT_SRC = ../../src/support_text.c
|
SUPPORT_TEXT_SRC = ../../src/support_text.c
|
||||||
|
RATELIMIT_SRC = ../../src/ratelimit.c
|
||||||
|
|
||||||
TESTS = test_utf8 test_message test_chat_room test_history_view test_i18n test_system_message test_help_text test_support_text test_cli_text
|
TESTS = test_utf8 test_message test_chat_room test_history_view test_i18n test_system_message test_help_text test_support_text test_cli_text test_ratelimit
|
||||||
|
|
||||||
.PHONY: all clean run
|
.PHONY: all clean run
|
||||||
|
|
||||||
|
|
@ -54,6 +55,9 @@ test_support_text: test_support_text.c $(SUPPORT_TEXT_SRC)
|
||||||
test_cli_text: test_cli_text.c $(CLI_TEXT_SRC) $(COMMON_SRC)
|
test_cli_text: test_cli_text.c $(CLI_TEXT_SRC) $(COMMON_SRC)
|
||||||
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
||||||
|
|
||||||
|
test_ratelimit: test_ratelimit.c $(RATELIMIT_SRC) $(COMMON_SRC)
|
||||||
|
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
||||||
|
|
||||||
run: all
|
run: all
|
||||||
@echo "=== Running UTF-8 Tests ==="
|
@echo "=== Running UTF-8 Tests ==="
|
||||||
./test_utf8
|
./test_utf8
|
||||||
|
|
@ -81,6 +85,9 @@ run: all
|
||||||
@echo ""
|
@echo ""
|
||||||
@echo "=== Running CLI Text Tests ==="
|
@echo "=== Running CLI Text Tests ==="
|
||||||
./test_cli_text
|
./test_cli_text
|
||||||
|
@echo ""
|
||||||
|
@echo "=== Running Rate Limit Tests ==="
|
||||||
|
./test_ratelimit
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f $(TESTS) *.o test_messages.log
|
rm -f $(TESTS) *.o test_messages.log
|
||||||
|
|
|
||||||
71
tests/unit/test_ratelimit.c
Normal file
71
tests/unit/test_ratelimit.c
Normal file
|
|
@ -0,0 +1,71 @@
|
||||||
|
/* Unit tests for connection and rate-limit accounting */
|
||||||
|
|
||||||
|
#include "../../include/ratelimit.h"
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#define TEST(name) static void test_##name()
|
||||||
|
#define RUN_TEST(name) do { \
|
||||||
|
printf("Running %s... ", #name); \
|
||||||
|
test_##name(); \
|
||||||
|
printf("✓\n"); \
|
||||||
|
tests_passed++; \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
static int tests_passed = 0;
|
||||||
|
|
||||||
|
TEST(per_ip_concurrent_limit_blocks_second_active_connection) {
|
||||||
|
const char *ip = "203.0.113.10";
|
||||||
|
|
||||||
|
setenv("TNT_RATE_LIMIT", "0", 1);
|
||||||
|
setenv("TNT_MAX_CONN_PER_IP", "1", 1);
|
||||||
|
ratelimit_init();
|
||||||
|
|
||||||
|
assert(ratelimit_check_ip(ip) == true);
|
||||||
|
assert(ratelimit_check_ip(ip) == false);
|
||||||
|
|
||||||
|
ratelimit_release_ip(ip);
|
||||||
|
assert(ratelimit_check_ip(ip) == true);
|
||||||
|
ratelimit_release_ip(ip);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(rate_limit_allows_configured_burst_then_blocks) {
|
||||||
|
const char *ip = "203.0.113.20";
|
||||||
|
|
||||||
|
setenv("TNT_RATE_LIMIT", "1", 1);
|
||||||
|
setenv("TNT_MAX_CONN_PER_IP", "10", 1);
|
||||||
|
setenv("TNT_MAX_CONN_RATE_PER_IP", "2", 1);
|
||||||
|
ratelimit_init();
|
||||||
|
|
||||||
|
assert(ratelimit_check_ip(ip) == true);
|
||||||
|
ratelimit_release_ip(ip);
|
||||||
|
assert(ratelimit_check_ip(ip) == true);
|
||||||
|
ratelimit_release_ip(ip);
|
||||||
|
assert(ratelimit_check_ip(ip) == false);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(global_limit_tracks_active_total) {
|
||||||
|
setenv("TNT_MAX_CONNECTIONS", "1", 1);
|
||||||
|
ratelimit_init();
|
||||||
|
|
||||||
|
assert(ratelimit_check_and_increment_total() == true);
|
||||||
|
assert(ratelimit_get_active_total() == 1);
|
||||||
|
assert(ratelimit_check_and_increment_total() == false);
|
||||||
|
|
||||||
|
ratelimit_decrement_total();
|
||||||
|
assert(ratelimit_get_active_total() == 0);
|
||||||
|
assert(ratelimit_check_and_increment_total() == true);
|
||||||
|
ratelimit_decrement_total();
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
printf("Running rate-limit unit tests...\n\n");
|
||||||
|
|
||||||
|
RUN_TEST(per_ip_concurrent_limit_blocks_second_active_connection);
|
||||||
|
RUN_TEST(rate_limit_allows_configured_burst_then_blocks);
|
||||||
|
RUN_TEST(global_limit_tracks_active_total);
|
||||||
|
|
||||||
|
printf("\n✓ All %d tests passed!\n", tests_passed);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue