feat: implement production-ready features from improvement plan phase 2.5 & 2.6
Phase 2.5: Fix Foundation (CRITICAL) - Fixed 4 failing tests by adding cache attribute to mock_client fixture - Created comprehensive cache tests for Pages endpoint (test_pages_cache.py) - Added missing dependencies: pydantic[email] and aiohttp to core requirements - Updated requirements.txt with proper dependency versions - Achieved 82.67% test coverage with 454 passing tests Phase 2.6: Production Essentials - Implemented structured logging (wikijs/logging.py) * JSON and text log formatters * Configurable log levels and output destinations * Integration with client operations - Implemented metrics and telemetry (wikijs/metrics.py) * Request tracking with duration, status codes, errors * Latency percentiles (min, max, avg, p50, p95, p99) * Error rate calculation * Thread-safe metrics collection - Implemented rate limiting (wikijs/ratelimit.py) * Token bucket algorithm for request throttling * Per-endpoint rate limiting support * Configurable timeout handling * Burst capacity management - Created SECURITY.md policy * Vulnerability reporting procedures * Security best practices * Response timelines * Supported versions Documentation - Added comprehensive logging guide (docs/logging.md) - Added metrics and telemetry guide (docs/metrics.md) - Added rate limiting guide (docs/rate_limiting.md) - Updated README.md with production features section - Updated IMPROVEMENT_PLAN_2.md with completed checkboxes Testing - Created test suite for logging (tests/test_logging.py) - Created test suite for metrics (tests/test_metrics.py) - Created test suite for rate limiting (tests/test_ratelimit.py) - All 454 tests passing - Test coverage: 82.67% Breaking Changes: None Dependencies Added: pydantic[email], email-validator, dnspython 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
73
tests/test_ratelimit.py
Normal file
73
tests/test_ratelimit.py
Normal file
@@ -0,0 +1,73 @@
|
||||
"""Tests for rate limiting functionality."""
|
||||
import time
|
||||
import pytest
|
||||
from wikijs.ratelimit import RateLimiter, PerEndpointRateLimiter
|
||||
|
||||
|
||||
def test_rate_limiter_init():
|
||||
"""Test rate limiter initialization."""
|
||||
limiter = RateLimiter(requests_per_second=10.0)
|
||||
|
||||
assert limiter.rate == 10.0
|
||||
assert limiter.burst == 10
|
||||
|
||||
|
||||
def test_rate_limiter_acquire():
|
||||
"""Test acquiring tokens."""
|
||||
limiter = RateLimiter(requests_per_second=100.0)
|
||||
|
||||
# Should be able to acquire immediately
|
||||
assert limiter.acquire(timeout=1.0) is True
|
||||
|
||||
|
||||
def test_rate_limiter_burst():
|
||||
"""Test burst behavior."""
|
||||
limiter = RateLimiter(requests_per_second=10.0, burst=5)
|
||||
|
||||
# Should be able to acquire up to burst size
|
||||
for _ in range(5):
|
||||
assert limiter.acquire(timeout=0.1) is True
|
||||
|
||||
|
||||
def test_rate_limiter_timeout():
|
||||
"""Test timeout behavior."""
|
||||
limiter = RateLimiter(requests_per_second=1.0)
|
||||
|
||||
# Exhaust tokens
|
||||
assert limiter.acquire(timeout=1.0) is True
|
||||
|
||||
# Next acquire should timeout quickly
|
||||
assert limiter.acquire(timeout=0.1) is False
|
||||
|
||||
|
||||
def test_rate_limiter_reset():
|
||||
"""Test rate limiter reset."""
|
||||
limiter = RateLimiter(requests_per_second=1.0)
|
||||
|
||||
# Exhaust tokens
|
||||
limiter.acquire()
|
||||
|
||||
# Reset
|
||||
limiter.reset()
|
||||
|
||||
# Should be able to acquire again
|
||||
assert limiter.acquire(timeout=0.1) is True
|
||||
|
||||
|
||||
def test_per_endpoint_rate_limiter():
|
||||
"""Test per-endpoint rate limiting."""
|
||||
limiter = PerEndpointRateLimiter(default_rate=10.0)
|
||||
|
||||
# Set different rate for specific endpoint
|
||||
limiter.set_limit("/api/special", 5.0)
|
||||
|
||||
# Should use endpoint-specific rate
|
||||
assert limiter.acquire("/api/special", timeout=1.0) is True
|
||||
|
||||
|
||||
def test_per_endpoint_default_rate():
|
||||
"""Test default rate for endpoints."""
|
||||
limiter = PerEndpointRateLimiter(default_rate=100.0)
|
||||
|
||||
# Should use default rate for unknown endpoint
|
||||
assert limiter.acquire("/api/unknown", timeout=1.0) is True
|
||||
Reference in New Issue
Block a user