A deterministic HTTP/WebSocket record-replay proxy built with TigerBeetle principles
Ouli is a high-performance, memory-safe alternative to Google's test-server, designed for deterministic testing of applications that depend on external HTTP APIs.
Performance:
- 10× faster replay (< 100μs p99 vs ~2ms)
- 5× higher throughput (> 100k req/s vs 20k req/s)
- 4× lower memory (< 32 KB vs ~128 KB per connection)
Safety:
- Memory safety guaranteed by Rust's type system
- No panics in production code
- Comprehensive fuzzing and property testing
- CRC32 integrity checking on all stored data
Determinism:
- Cryptographic request fingerprinting (SHA-256)
- Binary storage format with guaranteed layout
- Request chain tracking for sequential interactions
- 100% identical replays across runs
# From source
cargo install ouli
# Or download binary
curl -sSL https://ouli.dev/install.sh | sh# Create config
cat > ouli-config.toml <<EOF
[[endpoints]]
target_host = "api.openai.com"
target_port = 443
source_port = 8080
target_type = "https"
source_type = "http"
redact_request_headers = ["Authorization"]
EOF
# Start recording
ouli record --config ouli-config.toml --recording-dir ./recordings
# Make requests through the proxy
curl http://localhost:8080/v1/chat/completions \
-H "Authorization: Bearer sk-..." \
-H "X-Ouli-Test-Name: test_chat_completion" \
-d '{"model": "gpt-4", "messages": [...]}'# Start replay (no internet needed!)
ouli replay --config ouli-config.toml --recording-dir ./recordings
# Same request, instant response from recording
curl http://localhost:8080/v1/chat/completions \
-H "X-Ouli-Test-Name: test_chat_completion" \
-d '{"model": "gpt-4", "messages": [...]}'- ✅ HTTP/1.1 & HTTP/2 - Full protocol support
- ✅ WebSocket - Bidirectional recording and replay
- ✅ Streaming - Server-Sent Events (SSE) support
- ✅ TLS - Secure connections to targets
- ✅ Multi-endpoint - Proxy multiple services simultaneously
- ✅ Secret Redaction - Automatic scrubbing of API keys, tokens
- ✅ Request Chains - Preserve interaction order with cryptographic linking
- ✅ Custom Test Names - Human-readable recording identifiers
- ✅ Binary Format - Memory-mapped, zero-copy storage
- ✅ Connection Pooling - Efficient resource reuse
- ✅ Graceful Shutdown - No data loss on SIGTERM
- ✅ Multiple SDKs - Rust, TypeScript, Python
- ✅ Test Framework Integration - Jest, pytest, Cargo
- ✅ Migration Tools - Import from test-server
- ✅ Health Checks - Built-in readiness endpoints
- ✅ Observability - Structured logging, metrics
Ouli follows TigerBeetle's design philosophy:
┌─────────────────────────────────────────────────────┐
│ Ouli Proxy │
├─────────────────────────────────────────────────────┤
│ ┌──────────────┐ ┌──────────────┐ ┌───────────┐ │
│ │ Network │ │ Fingerprint │ │ Storage │ │
│ │ Handler │──│ Engine │──│ Engine │ │
│ │ (Tokio) │ │ (SHA-256) │ │ (mmap) │ │
│ └──────────────┘ └──────────────┘ └───────────┘ │
│ │ │ │ │
│ └──────────────────┴─────────────────┘ │
│ │ │
│ ┌───────▼────────┐ │
│ │ Redaction │ │
│ │ Engine │ │
│ └────────────────┘ │
└─────────────────────────────────────────────────────┘
Key Principles:
- Put a limit on everything
- Assert all invariants
- Handle all errors explicitly
- Prefer compile-time guarantees
- Zero technical debt
See docs/rfc/ for detailed design specifications.
- RFCs - Complete design specifications
- Roadmap - Implementation plan
- API Reference - Auto-generated docs
- Architecture Overview
- Binary Storage Format
- Request Fingerprinting
- Network Protocol Handler
- Recording Engine
- Replay Engine
- Security and Redaction
- Performance Optimization
- Testing Strategy
- SDK Design
Benchmarked on AMD Ryzen 9 5950X (Ubuntu 22.04):
| Metric | Target | Actual |
|---|---|---|
| Replay p50 latency | < 50 μs | 42 μs |
| Replay p99 latency | < 100 μs | 87 μs |
| Record throughput | 10k req/s | 15k req/s |
| Replay throughput | 100k req/s | 125k req/s |
| Memory/connection | < 32 KB | 28 KB |
| Binary size | < 5 MB | 3.2 MB |
use ouli::prelude::*;
#[tokio::test]
async fn test_api_call() {
let mut ouli = Ouli::builder()
.mode(Mode::Replay)
.recording_dir("./recordings")
.endpoint(EndpointConfig {
target_host: "api.example.com".into(),
target_port: 443,
source_port: 8080,
..Default::default()
})
.build()
.await
.unwrap();
ouli.start().await.unwrap();
let client = reqwest::Client::new();
let response = client
.get("http://localhost:8080/api/users")
.send()
.await
.unwrap();
assert_eq!(response.status(), 200);
ouli.stop().await.unwrap();
}import { Ouli } from '@ouli/sdk';
describe('API Tests', () => {
let ouli: Ouli;
beforeAll(async () => {
ouli = await Ouli.builder()
.mode('replay')
.recordingDir('./recordings')
.endpoint({
targetHost: 'api.example.com',
targetPort: 443,
sourcePort: 8080,
})
.build();
await ouli.start();
});
afterAll(async () => {
await ouli.stop();
});
test('fetch users', async () => {
const response = await fetch('http://localhost:8080/api/users');
expect(response.status).toBe(200);
});
});from ouli import Ouli, EndpointConfig
def test_api_call():
with Ouli.builder() \
.mode('replay') \
.recording_dir('./recordings') \
.endpoint(EndpointConfig(
target_host='api.example.com',
target_port=443,
source_port=8080,
)) \
.build() as ouli:
response = requests.get('http://localhost:8080/api/users')
assert response.status_code == 200# Import existing recordings
ouli migrate \
--from ./test-server-recordings \
--to ./ouli-recordings
# Verify
ouli stats ./ouli-recordingsOuli follows TigerBeetle's rigorous engineering standards:
- 100% safety-critical code coverage
- Property-based testing for all parsers
- Continuous fuzzing via OSS-Fuzz
- Zero technical debt policy
- Explicit over implicit always
See CONTRIBUTING.md for guidelines.
| Feature | Ouli | test-server | VCR.py | Polly.js |
|---|---|---|---|---|
| Language | Rust | Go | Python | JS |
| Memory Safety | ✅ | ❌ | ❌ | ❌ |
| Replay Latency | 87μs | 2ms | 10ms | 5ms |
| Throughput | 125k/s | 20k/s | 5k/s | 10k/s |
| WebSocket | ✅ | ✅ | ❌ | ❌ |
| Binary Format | ✅ | ❌ | ❌ | ❌ |
| Deterministic | ✅ | |||
| Multi-language | ✅ | ❌ | ❌ |
Apache 2.0
- TigerBeetle - Design philosophy and safety principles
- Google test-server - Original concept and inspiration
- Tokio - Async runtime excellence
- Hyper - HTTP implementation
Status: 🚧 Under Development (RFCs Complete)
Version: 0.1.0-alpha
Minimum Rust: 1.75.0