This guide explains how to run and understand the test suite for RouteShield.
Before running tests, make sure you have all dependencies installed:
mix deps.getmix testmix test --covermix test test/route_shield/plug_test.exsmix test test/route_shield/plug_test.exs:42mix test.watchThe test suite is organized to mirror the application structure:
test/
├── test_helper.exs # Test setup and configuration
├── route_shield_test.exs # Main module tests
└── route_shield/
├── plug_test.exs # Plug integration tests
├── route_discovery_test.exs # Route discovery tests
└── rules/
├── rate_limit_test.exs # Rate limiting tests
└── ip_filter_test.exs # IP filtering tests
└── storage/
├── ets_test.exs # ETS storage tests
└── cache_test.exs # Cache refresh tests
Tests cover:
- Route matching (exact and parameterized paths)
- IP extraction from headers (x-forwarded-for, x-real-ip, remote_ip)
- Rule enforcement (IP filtering, rate limiting)
- Priority-based rule application
- Disabled rule handling
- Error responses (403, 429)
Tests cover:
- Token bucket algorithm
- Per-IP rate limiting
- Per-rule rate limiting
- Window expiration and token refill
- Edge cases (small windows, large limits)
- Bucket cleanup
Tests cover:
- Whitelist and blacklist functionality
- CIDR notation support (/0, /8, /24, /32)
- Multiple filter handling
- Precedence (blacklist over whitelist)
- Disabled filter handling
- Invalid IP/CIDR handling
Tests cover:
- Route discovery from router modules
- Custom
__route_shield_routes__/0function support - Route storage in ETS and database
- Route updates for existing routes
- Error handling
Tests cover:
- Route storage and retrieval
- Rule storage and retrieval
- Rate limit storage and retrieval
- IP filter storage and retrieval
- Time restriction storage and retrieval
- Filtering by enabled status
- Priority sorting
- Table clearing operations
Tests cover:
- Full cache refresh
- Individual component refresh (rules, rate limits, etc.)
- Rule-specific refresh
- Cache clearing before refresh
The test suite uses ETS tables for in-memory storage, which are:
- Initialized in
test_helper.exs - Cleared before each test via
setupblocks - Isolated per test to prevent interference
The tests use simple struct-based mocks for the repository instead of heavy mocking libraries. This keeps tests:
- Fast
- Simple
- Easy to understand
- Independent of external dependencies
For CI/CD pipelines, run:
mix test --coverThis will:
- Run all tests
- Generate coverage reports
- Exit with appropriate status codes
When adding new functionality:
- Add tests in the appropriate file matching the module structure
- Use descriptive test names that explain what is being tested
- Clean up ETS tables in
setupblocks - Test both success and failure cases
- Test edge cases (empty lists, nil values, boundary conditions)
Example:
defmodule RouteShield.NewFeatureTest do
use ExUnit.Case
setup do
# Clean up before each test
RouteShield.Storage.ETS.clear_all()
:ok
end
describe "new_functionality/1" do
test "handles success case" do
# Test implementation
end
test "handles error case" do
# Test implementation
end
end
endIf you see errors about ETS tables not existing:
- Make sure
test_helper.exsis properly loading - Check that
RouteShield.Storage.ETS.start_link()is called
If tests are affecting each other:
- Ensure each test has a
setupblock that clears ETS tables - Check that test data uses unique IDs
Rate limit tests use Process.sleep/1 for window expiration:
- These tests may be slower
- Consider using
@tag :slowfor such tests - Run them separately if needed:
mix test --exclude slow
The test suite is designed to be fast:
- Uses in-memory ETS tables (no database required)
- Minimal mocking overhead
- Parallel test execution (ExUnit default)
Typical test run time: < 5 seconds for the full suite.