Files
foxhunt/testing/e2e/src/market_data_helper.rs
jgrusewski 9c3d741a08 refactor: restructure repo — crates/, bin/, testing/ layout
Move 17 library crates into crates/, CLI binary into bin/fxt,
consolidate 10 test crates into testing/, split config crate
from deployment config files.

Root directory reduced from 38+ to ~17 directories.
All Cargo.toml paths and build.rs proto refs updated.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 11:56:00 +01:00

133 lines
4.0 KiB
Rust

//! Market Data Helper for E2E Tests
//!
//! Provides utilities to publish test market data events that can be streamed
//! through the Trading Service's `stream_market_data` endpoint.
use anyhow::Result;
use tokio::time::{interval, Duration};
use tracing::info;
/// Start a background task that publishes test market data events
///
/// This helper publishes periodic market data events to enable E2E tests
/// that depend on market data streaming. Events are published at 10 Hz (100ms intervals).
///
/// # Arguments
/// * `symbols` - List of symbols to generate market data for
/// * `duration_secs` - How long to run the generator (0 = run indefinitely)
///
/// # Returns
/// A handle that can be used to stop the generator
pub fn start_test_market_data_publisher(
symbols: Vec<String>,
duration_secs: u64,
) -> tokio::task::JoinHandle<()> {
info!(
"🎲 Starting test market data publisher for symbols: {:?}",
symbols
);
tokio::spawn(async move {
let mut tick = interval(Duration::from_millis(100)); // 10 Hz
let mut sequence = 0u64;
let start_time = tokio::time::Instant::now();
loop {
// Check if we should stop (duration_secs == 0 means run forever)
if duration_secs > 0 && start_time.elapsed().as_secs() >= duration_secs {
info!("⏱️ Test market data publisher stopped after {} seconds", duration_secs);
break;
}
tick.tick().await;
for symbol in &symbols {
let base_price = match symbol.as_str() {
"AAPL" => 150.0,
"GOOGL" => 2800.0,
"MSFT" => 300.0,
"AMZN" => 3300.0,
_ => 100.0,
};
let price = base_price + (sequence as f64 * 0.01) % 10.0;
let volume = 100.0 + (sequence as f64 * 10.0) % 1000.0;
// Note: In production, this would publish to an event bus or message queue
// For E2E tests, the Trading Service will generate synthetic market data
// when stream_market_data is called with no real data provider
// Log at DEBUG level to avoid flooding test output
tracing::debug!(
symbol = %symbol,
price = price,
volume = volume,
sequence = sequence,
"Published test market data"
);
}
sequence += 1;
}
})
}
/// Publish a single burst of market data events for testing
///
/// Useful for tests that need a specific number of market data events.
///
/// # Arguments
/// * `symbol` - Symbol to generate data for
/// * `count` - Number of events to generate
/// * `base_price` - Starting price
pub async fn publish_market_data_burst(
symbol: &str,
count: usize,
base_price: f64,
) -> Result<()> {
info!(
"📊 Publishing {} test market data events for {}",
count, symbol
);
for i in 0..count {
let price = base_price + (i as f64 * 0.01);
let volume = 100.0 + (i as f64);
tracing::debug!(
symbol = %symbol,
price = price,
volume = volume,
sequence = i,
"Published test market data burst event"
);
// In E2E tests, the Trading Service generates synthetic data
// This function mainly serves to document the expected data format
}
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
#[tokio::test]
async fn test_market_data_publisher_lifecycle() {
let handle = start_test_market_data_publisher(
vec!["TEST".to_string()],
1, // Run for 1 second
);
// Wait for publisher to finish
let _ = tokio::time::timeout(Duration::from_secs(2), handle).await;
}
#[tokio::test]
async fn test_market_data_burst() {
let result = publish_market_data_burst("TEST", 10, 100.0).await;
assert!(result.is_ok());
}
}