Files
foxhunt/testing/integration/framework.rs
jgrusewski 4ba8eebc05 cleanup: declarative rewrites for migrations/services/testing TODOs
migrations:
- 001_trading_events.sql, 003_audit_system.sql: the hard-coded
  node_id literals (`trading-node-01`, `audit-node-01`,
  `ml-node-01`, `system-node-01`, `change-tracker-01`) are
  overridden per-deployment by later migrations rather than read
  from the environment. Describe that in the inline comment.
- 004_compliance_views.sql: `generate_compliance_report` is a log
  stub — actual report generation is performed by the compliance
  service. Say so explicitly.

services:
- ml_training_service/tests/orchestrator_225_features_test.rs: the
  empty `#[ignore]`d placeholder for the 225-feature orchestrator
  loader has been removed; it held no assertions and only tracked
  a TODO (feedback_no_stubs.md).
- trading_agent_service/src/service.rs: portfolio volatility uses
  the diagonal-only approximation because cross-asset return
  correlations are not maintained in this service. Document that.
- trading_service/src/services/risk.rs: `get_risk_metrics` uses
  `calculate_marginal_var` + asset-class fallback; describe why
  `calculate_comprehensive_var` is not wired at this boundary.
- trading_service/tests/auth_comprehensive.rs: delete the entire
  commented-out legacy BackupCodeValidator test block — the old
  `generate_backup_codes` / `store_backup_code` /
  `verify_backup_code` surface no longer exists, and MFA
  integration tests already cover the new API.

testing:
- harness/grpc_clients.rs: no BacktestingServiceClient proto
  exists; reword the stale TODO import line.
- chaos/*: reword the family of "TODO: Implement ..." stubs as
  "Currently a no-op / synthetic result" descriptions so readers
  know exactly how much of the chaos framework is live.
- compliance_automation_tests.rs: delete the file; it was a giant
  /* ... */ block referencing a nonexistent compliance module
  and was not wired into any Cargo target.
- framework.rs: describe why `setup()` uses `println!` instead of
  `tracing_subscriber` (tracing_subscriber is not a dep of this
  integration crate).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 08:51:26 +02:00

190 lines
5.4 KiB
Rust

//! Test framework utilities for Foxhunt HFT system
#![allow(unused_crate_dependencies)]
use rust_decimal::Decimal;
/// Test framework for setting up common test infrastructure
pub struct TestFramework {
pub config: TestConfig,
}
/// Configuration for test setup
#[derive(Debug, Clone)]
pub struct TestConfig {
pub initial_capital: Decimal,
pub test_symbols: Vec<String>,
pub enable_logging: bool,
}
impl Default for TestConfig {
fn default() -> Self {
Self {
initial_capital: Decimal::from(100000),
test_symbols: vec!["BTCUSD".to_string(), "ETHUSD".to_string()],
enable_logging: false,
}
}
}
impl TestFramework {
pub fn new(config: TestConfig) -> Self {
Self { config }
}
pub fn with_default() -> Self {
Self::new(TestConfig::default())
}
pub async fn setup(&self) -> anyhow::Result<()> {
if self.config.enable_logging {
// Structured logging (tracing_subscriber) is not a dep of this
// integration crate; tests rely on stdout println!. Callers
// that want structured logs should run via the workspace
// test harness which initialises tracing at its entry point.
println!("Logging enabled (tracing_subscriber not available)");
}
Ok(())
}
}
/// Test safety module for error-free testing
pub mod test_safety {
use std::fmt::Debug;
use std::time::Duration;
/// Safe test result type
pub type TestResult<T> = Result<T, TestSafetyError>;
/// Test safety error types
#[derive(Debug, Clone)]
pub enum TestSafetyError {
AssertionFailed {
field: String,
expected: String,
actual: String,
},
ThreadJoinFailed {
thread_type: String,
},
Timeout {
operation: String,
timeout_ms: u64,
},
CalculationFailed {
operation: String,
details: String,
},
}
impl std::fmt::Display for TestSafetyError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
TestSafetyError::AssertionFailed {
field,
expected,
actual,
} => {
write!(
f,
"Assertion failed for {}: expected {}, got {}",
field, expected, actual
)
},
TestSafetyError::ThreadJoinFailed { thread_type } => {
write!(f, "Thread join failed for: {}", thread_type)
},
TestSafetyError::Timeout {
operation,
timeout_ms,
} => {
write!(
f,
"Operation {} timed out after {}ms",
operation, timeout_ms
)
},
TestSafetyError::CalculationFailed { operation, details } => {
write!(f, "Calculation failed for {}: {}", operation, details)
},
}
}
}
impl std::error::Error for TestSafetyError {}
/// Safe assertion function
pub fn safe_assert(
condition: bool,
field: &str,
expected: &str,
actual: impl std::fmt::Display,
) -> TestResult<()> {
if condition {
Ok(())
} else {
Err(TestSafetyError::AssertionFailed {
field: field.to_string(),
expected: expected.to_string(),
actual: actual.to_string(),
})
}
}
/// Safe equality assertion
pub fn safe_assert_eq<T: PartialEq + Debug>(
actual: &T,
expected: &T,
field: &str,
) -> TestResult<()> {
if actual == expected {
Ok(())
} else {
Err(TestSafetyError::AssertionFailed {
field: field.to_string(),
expected: format!("{:?}", expected),
actual: format!("{:?}", actual),
})
}
}
/// HFT Performance validator
pub struct HftPerformanceValidator {
pub max_latency_micros: u64,
pub min_throughput_ops_per_sec: u64,
}
impl HftPerformanceValidator {
pub fn new() -> Self {
Self {
max_latency_micros: 50, // 50μs max latency
min_throughput_ops_per_sec: 10_000, // 10k ops/sec min
}
}
pub fn validate_latency(&self, duration: Duration) -> TestResult<()> {
let micros = duration.as_micros() as u64;
safe_assert(
micros <= self.max_latency_micros,
"latency",
&format!("{}μs", self.max_latency_micros),
format!("{}μs", micros),
)
}
pub fn validate_throughput(&self, ops_per_sec: u64) -> TestResult<()> {
safe_assert(
ops_per_sec >= self.min_throughput_ops_per_sec,
"throughput",
&format!("{} ops/sec", self.min_throughput_ops_per_sec),
format!("{} ops/sec", ops_per_sec),
)
}
}
impl Default for HftPerformanceValidator {
fn default() -> Self {
Self::new()
}
}
}