This document outlines the end-to-end test plan for validating newly introduced modules (proxy system, CCXT exchanges, native exchanges) using live Mullvad SOCKS5 proxies.
Branch: feature/normalized-data-schema-crypto
Date: 2025-10-24
Purpose: Validate proxy routing, exchange connectivity, and data normalization in production-like conditions
- Proxy System Validation: Verify HTTP and WebSocket connections route correctly through SOCKS5 proxies
- CCXT Exchange Integration: Validate CCXT/CCXT-Pro feeds work with proxy configuration
- Native Exchange Integration: Validate native Backpack implementation with proxy support
- Data Normalization: Verify timestamp normalization and symbol mapping work across exchanges
- Regional Behavior: Document geofencing and regional restrictions
Artifact Location:
# Download latest Mullvad relay list
gh run download 18632839930 \
--repo tommy-ca/mulvad-relay-list \
-D /tmp/proxy_artifact
# View available endpoints
head /tmp/proxy_artifact/mullvad-relay-artifacts/mullvad_relays.csvKey Endpoints (as of 2025-10-19):
| Region | Endpoint | Usage |
|---|---|---|
| US East | socks5://us-nyc-wg-socks5-301.relays.mullvad.net:1080 |
Test geofencing |
| Europe | socks5://de-fra-wg-socks5-101.relays.mullvad.net:1080 |
Primary testing |
| Asia | socks5://sg-sin-wg-socks5-001.relays.mullvad.net:1080 |
Regional validation |
Required Dependencies:
pip install -e ".[dev]"
pip install ccxt ccxtpro aiohttp-socks python-socksEnvironment Variables:
# Primary proxy endpoint (rotate between regions)
export CRYPTOFEED_TEST_SOCKS_PROXY="socks5://de-fra-wg-socks5-101.relays.mullvad.net:1080"
# Test symbols (optional overrides)
export CRYPTOFEED_TEST_BINANCE_SYMBOL="BTCUSDT"
export CRYPTOFEED_TEST_BINANCE_WS_STREAM="btcusdt@trade"
export CRYPTOFEED_TEST_CCXT_SYMBOL="BTC/USDC:USDC"
export CRYPTOFEED_TEST_BACKPACK_CCXT_SYMBOL="BTC/USDC"
# Timeout configuration
export CRYPTOFEED_TEST_BINANCE_WS_TIMEOUT="10"
export CRYPTOFEED_TEST_CCXT_WS_TIMEOUT="20"
export CRYPTOFEED_TEST_CCXT_REST_TIMEOUT="15"
export CRYPTOFEED_TEST_BACKPACK_REST_TIMEOUT="10"Purpose: Validate proxy configuration, injection, and connection routing
pytest tests/unit/test_proxy_mvp.py -vValidates:
- Environment variable parsing
- YAML configuration loading
- Programmatic ProxySettings construction
- Precedence rules (env > YAML > programmatic)
Success Criteria: All 40+ unit tests pass
pytest tests/integration/test_proxy_integration.py -vValidates:
- HTTP connection proxy injection
- WebSocket connection proxy injection
- Exchange-specific proxy resolution
- Default proxy fallback
Success Criteria: All integration tests pass
Purpose: Validate real exchange connections through Mullvad proxies
export CRYPTOFEED_TEST_SOCKS_PROXY="socks5://de-fra-wg-socks5-101.relays.mullvad.net:1080"
pytest tests/integration/test_live_binance.py \
-v -m "live_proxy and live_binance" \
-k "ticker or orderbook or websocket"Validates:
- HTTP REST endpoint connectivity (
/api/v3/ticker/price,/api/v3/depth) - WebSocket stream connectivity (
btcusdt@trade) - Geofencing behavior (HTTP 451 handling)
- Proxy timeout configuration
Expected Results:
| Endpoint | US Proxy | EU Proxy | Asia Proxy |
|---|---|---|---|
| REST ticker | ✅ pass | ✅ pass | |
| REST depth | ✅ pass | ✅ pass | |
| WS trades | ✅ pass | ✅ pass |
Success Criteria: EU/Asia proxies return valid data; US proxy skips gracefully
pytest tests/integration/test_live_ccxt_hyperliquid.py \
-v -m "live_proxy and live_ccxt"Validates:
- CCXT REST transport with proxy (
fetch_order_book) - CCXT.pro WebSocket transport with proxy (
watch_trades) - Proxy configuration via
socksProxy/wsSocksProxy - Symbol normalization (Hyperliquid perpetuals)
Expected Results:
| Test | EU Proxy | Status |
|---|---|---|
| REST order book | ✅ | BTC/USDC:USDC L2 data |
| WS trades | ✅ | Real-time trade messages |
Success Criteria: Both REST and WS receive valid data within timeout
# CCXT-based Backpack (working)
pytest tests/integration/test_live_ccxt_backpack.py \
-v -m "live_proxy and live_ccxt"
# Native Backpack (known issue: parse error)
pytest tests/integration/test_live_backpack.py \
-v -m "live_proxy and live_backpack"Validates:
- Backpack CCXT REST (
fetch_markets,fetch_order_book) - Backpack CCXT.pro WebSocket (
watch_trades) - Native Backpack REST client
- Native Backpack WebSocket (
⚠️ known parse error 4002)
Expected Results:
| Implementation | REST | WebSocket | Status |
|---|---|---|---|
| CCXT | ✅ markets, order book | ✅ trades | Working |
| Native | ✅ markets | Partial |
Success Criteria: CCXT implementation fully functional; native WS documented as known issue
Purpose: Validate timestamp normalization and symbol mapping work correctly
pytest tests/unit/test_exchange.py -v -k "timestamp"Validates:
Exchange.timestamp_normalize()handles datetime objects- Millisecond detection (values >= 1e12)
- ISO-8601 string parsing (with/without 'Z')
- Numeric string parsing
Test Matrix:
| Input Type | Example | Expected Output |
|---|---|---|
| datetime | datetime(2024, 10, 24, 12, 0, tzinfo=UTC) |
1729771200.0 |
| int (seconds) | 1729771200 |
1729771200.0 |
| int (milliseconds) | 1729771200000 |
1729771200.0 |
| str (numeric) | "1729771200" |
1729771200.0 |
| str (ISO-8601) | "2024-10-24T12:00:00Z" |
1729771200.0 |
Success Criteria: All input formats normalize correctly
pytest tests/unit/test_exchange.py -v -k "bybit and symbol"Validates:
- Spot symbols:
BTCUSDT→BTC-USDT - Perpetual symbols:
BTCUSDT→BTC-USDTorBTCUSDTPERP→BTCUSDTPERP - Futures symbols: expiry date parsing
- Heuristic fallbacks for unmapped symbols
Success Criteria: Symbol mapping produces consistent normalized forms
pytest tests/unit/test_exchange.py -v -k "coinbase and symbol"Validates:
- Modern API format (
base_currency_id,quote_currency_id) - Legacy API format (
base_symbol,quote_symbol) - Product ID extraction
- tick_size metadata preservation
Success Criteria: Both modern and legacy formats parse correctly
Purpose: Validate multiple exchanges using different proxies simultaneously
# Run the existing concurrent proxy example
python examples/demo_concurrent_proxy.pyValidates:
- Per-exchange proxy configuration
- Concurrent HTTP/WS connections through different proxies
- No proxy lease conflicts
- Proper connection cleanup
Configuration (from example):
proxy:
enabled: true
default:
http:
url: "socks5://default-proxy:1080"
exchanges:
binance:
http:
url: "socks5://de-fra-wg-socks5-101.relays.mullvad.net:1080"
coinbase:
http:
url: "socks5://us-nyc-wg-socks5-301.relays.mullvad.net:1080"Success Criteria: All feeds connect and receive data without conflicts
# Create custom test script (see T4.2-stress-test.py below)
python tests/integration/T4.2-stress-test.pyValidates:
- Proxy pool behavior under load
- Connection limit handling
- Memory stability over 5-minute duration
- Graceful degradation on proxy failures
Success Criteria:
- All feeds initialize successfully
- No memory leaks (<5% growth over 5 minutes)
- Clean shutdown without hanging connections
Purpose: Document exchange behavior across different proxy regions
# Script to test all combinations
./tests/integration/regional_validation.shTest Matrix:
| Exchange | US Proxy | EU Proxy | Asia Proxy | Notes |
|---|---|---|---|---|
| Binance REST | ✅ | ✅ | US geofenced | |
| Binance WS | ✅ | ✅ | US geofenced | |
| Coinbase REST | ✅ | ✅ | ✅ | No restrictions |
| Coinbase WS | ✅ | ✅ | ✅ | No restrictions |
| Bybit REST | ✅ | ✅ | ✅ | No restrictions |
| Bybit WS | ✅ | ✅ | ✅ | No restrictions |
| Backpack (ccxt) | ✅ | ✅ | ✅ | No restrictions |
| Hyperliquid (ccxt) | ✅ | ✅ | ✅ | No restrictions |
Expected Results: Based on docs/proxy/live-testing.md
Success Criteria: Results match documented regional behavior
# Quick validation that core functionality works
pytest tests/unit/test_proxy_mvp.py -v --tb=short
pytest tests/integration/test_proxy_integration.py -v --tb=short
pytest tests/unit/test_ccxt_*.py -v --tb=shortGates Phase 2: All unit tests must pass
# Set EU proxy (most permissive)
export CRYPTOFEED_TEST_SOCKS_PROXY="socks5://de-fra-wg-socks5-101.relays.mullvad.net:1080"
# Run all live tests
pytest tests/integration/test_live_*.py -v -m "live_proxy"Gates Phase 3: At least 80% of live tests pass (allowing for transient network issues)
# Test each region sequentially
for region in US EU ASIA; do
export CRYPTOFEED_TEST_SOCKS_PROXY="socks5://$(get_proxy_for_region $region)"
pytest tests/integration/test_live_*.py -v -m "live_proxy" --junit-xml=results-${region}.xml
doneDeliverable: Regional behavior matrix documenting all combinations
# Long-running concurrent feed validation
python tests/integration/T4.2-stress-test.py --duration=3600 --feeds=20Deliverable: Performance report (memory, connection stability, error rates)
- ✅ Unit Tests: 100% pass (tests/unit/test_proxy_mvp.py, test_ccxt_*.py)
- ✅ Integration Tests: 100% pass (tests/integration/test_proxy_integration.py)
- ✅ Live Tests: ≥80% pass with EU proxy (allowing for transient failures)
- ✅ Regional Matrix: Documented behavior matches observations
- ✅ Stress Test: <5% memory growth, 0 deadlocks over 60 minutes
- ✅ Data Quality: All timestamps normalize to UTC float, symbols map consistently
⚠️ Binance US proxy: HTTP 451 (geofencing) - skip gracefully⚠️ Backpack native WS: Parse error 4002 - documented, use CCXT fallback⚠️ Transient network errors: <20% of live tests may fail due to proxy/network issues
- Test Results: XML reports per phase (
pytest --junit-xml) - Regional Matrix: CSV with exchange/region/endpoint/status
- Performance Metrics: Memory profile, connection counts, error logs
- Network Traces: Packet captures for debugging (optional)
docs/proxy/live-testing.md: Update regional observationsSPEC_STATUS.md: Mark E2E validation completeIMPLEMENTATION_SUMMARY.md: Add E2E results section
# tests/integration/T4.2-stress-test.py
"""
Stress test for concurrent proxy operations.
Run 20+ feeds simultaneously through Mullvad proxies for 60 minutes.
Monitor memory, connections, and error rates.
"""
import asyncio
import time
from cryptofeed import FeedHandler
from cryptofeed.defines import TRADES, L2_BOOK
# ... implementation# tests/integration/regional_validation.sh
"""
Test all exchange/region combinations and generate matrix.
"""
#!/bin/bash
# ... implementation| Phase | Duration | Parallel Execution |
|---|---|---|
| Phase 1 (Smoke) | 10 min | Sequential |
| Phase 2 (Live) | 20 min | Parallel by exchange |
| Phase 3 (Regional) | 45 min | Parallel by region |
| Phase 4 (Stress) | 60 min | Single long-running |
| Total | ~2.5 hours | With parallelization |
Recommendation: Run Phase 1-3 in CI/CD, Phase 4 manually before release
Mitigation:
- Test with 3 different relays per region
- Document alternative proxy sources (ssh tunnels, commercial VPNs)
- Graceful skip on proxy unreachable
Mitigation:
- Pin exchange behavior to specific API versions in tests
- Maintain fixtures for known-good responses
- Document API version in test comments
Mitigation:
- Retry logic with exponential backoff
- Mark flaky tests with
@pytest.mark.flaky(reruns=3) - Report pass rate, not just pass/fail
# 1. Download Mullvad relay list
gh run download 18632839930 --repo tommy-ca/mulvad-relay-list -D /tmp/proxy_artifact
# 2. Set environment
export CRYPTOFEED_TEST_SOCKS_PROXY="socks5://de-fra-wg-socks5-101.relays.mullvad.net:1080"
# 3. Run smoke tests
pytest tests/unit/test_proxy_mvp.py tests/integration/test_proxy_integration.py -v
# 4. Run live tests
pytest tests/integration/test_live_*.py -v -m "live_proxy"
# 5. View results
cat results-*.xml | grep -E "testsuite|testcase"| Issue | Solution |
|---|---|
ModuleNotFoundError: aiohttp_socks |
pip install aiohttp-socks |
Connection timeout |
Verify DNS for relay hostname, check firewall |
HTTP 451 |
Switch to EU/Asia proxy, or skip test |
SOCKS5 auth failed |
Mullvad relays require no auth, check URL format |
Parse error 4002 (Backpack) |
Expected, use CCXT implementation instead |
Document Status: ✅ Ready for execution
Last Updated: 2025-10-24
Owner: Engineering Team