Files
foxhunt/tli/tests/e2e/test_fixtures.rs
jgrusewski 7458f1be01 feat(wave12): E2E validation complete - 225-feature pipeline ready
 Validation Results:
- PPO training: 24.2s (1 epoch, 950 samples, dim=225)
- Feature extraction: 105μs/bar (9.5x faster than target)
- Model checkpoint: 293KB (147KB actor + 146KB critic)
- GPU memory: 145MB used (96.4% headroom)
- Zero dimension mismatches

📊 Success Criteria (5/5):
 Feature dimension = 225 (Wave C 201 + Wave D 24)
 Model state_dim = 225
 Training completed without errors
 Checkpoint saved successfully
 No dimension mismatch errors

📁 Training Data Ready:
- ES.FUT: 2.9MB, 180 days
- NQ.FUT: 4.4MB, 180 days
- 6E.FUT: 2.8MB, 180 days
- ZN.FUT: 65KB, 90 days (clean)

🚀 Next: Full production model retraining (4 models, ~10min GPU time)

🤖 Generated with Claude Code (https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-22 22:48:04 +02:00

186 lines
5.2 KiB
Rust

//! Test Fixtures and Helpers for E2E Tests
//!
//! Provides reusable test data, helper functions, and utilities for E2E testing.
use std::collections::HashMap;
use tli::proto::ml_training::{TrainingJobSummary, TrainingStatus};
/// Create a test training job with default values
pub fn create_test_job(
job_id: &str,
model_type: &str,
status: TrainingStatus,
) -> TrainingJobSummary {
create_test_job_with_times(
job_id,
model_type,
status,
chrono::Utc::now().timestamp(),
0,
0,
)
}
/// Create a test training job with specific timestamps
pub fn create_test_job_with_times(
job_id: &str,
model_type: &str,
status: TrainingStatus,
created_at: i64,
started_at: i64,
completed_at: i64,
) -> TrainingJobSummary {
TrainingJobSummary {
job_id: job_id.to_string(),
model_type: model_type.to_string(),
status: status as i32,
created_at,
started_at,
completed_at,
description: format!("Test {} job for {}", model_type, job_id),
final_loss: 0.123,
best_validation_score: 0.456,
tags: create_test_tags(),
}
}
/// Create standard test tags
pub fn create_test_tags() -> HashMap<String, String> {
let mut tags = HashMap::new();
tags.insert("env".to_string(), "test".to_string());
tags.insert("version".to_string(), "1.0".to_string());
tags
}
/// Create a batch of test jobs for testing list/filter operations
pub fn create_test_job_batch() -> Vec<TrainingJobSummary> {
let base_time = chrono::Utc::now().timestamp();
vec![
create_test_job_with_times(
"train_tft_es_20251022_140000",
"TFT",
TrainingStatus::Running,
base_time,
base_time + 60,
0,
),
create_test_job_with_times(
"train_dqn_nq_20251022_133000",
"DQN",
TrainingStatus::Completed,
base_time - 3600,
base_time - 3540,
base_time - 3336,
),
create_test_job_with_times(
"train_ppo_es_20251022_130000",
"PPO",
TrainingStatus::Completed,
base_time - 7200,
base_time - 7140,
base_time - 7133,
),
create_test_job_with_times(
"train_mamba2_6e_20251022_120000",
"MAMBA_2",
TrainingStatus::Failed,
base_time - 14400,
base_time - 14340,
base_time - 14200,
),
create_test_job_with_times(
"train_tft_zn_20251022_110000",
"TFT",
TrainingStatus::Stopped,
base_time - 18000,
base_time - 17940,
base_time - 17800,
),
]
}
/// Helper function to extract job IDs from job list
pub fn extract_job_ids(jobs: &[TrainingJobSummary]) -> Vec<String> {
jobs.iter().map(|j| j.job_id.clone()).collect()
}
/// Helper function to filter jobs by status
pub fn filter_by_status(jobs: &[TrainingJobSummary], status: TrainingStatus) -> Vec<TrainingJobSummary> {
jobs.iter()
.filter(|j| j.status == status as i32)
.cloned()
.collect()
}
/// Helper function to filter jobs by model type
pub fn filter_by_model(jobs: &[TrainingJobSummary], model_type: &str) -> Vec<TrainingJobSummary> {
jobs.iter()
.filter(|j| j.model_type == model_type)
.cloned()
.collect()
}
/// Validate job structure
pub fn validate_job_structure(job: &TrainingJobSummary) -> bool {
!job.job_id.is_empty()
&& !job.model_type.is_empty()
&& job.status >= 0
&& job.created_at > 0
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_create_test_job() {
let job = create_test_job("test_1", "TFT", TrainingStatus::Pending);
assert_eq!(job.job_id, "test_1");
assert_eq!(job.model_type, "TFT");
assert_eq!(job.status, TrainingStatus::Pending as i32);
}
#[test]
fn test_create_test_job_batch() {
let jobs = create_test_job_batch();
assert_eq!(jobs.len(), 5);
assert_eq!(jobs[0].model_type, "TFT");
assert_eq!(jobs[1].model_type, "DQN");
assert_eq!(jobs[2].model_type, "PPO");
}
#[test]
fn test_filter_by_status() {
let jobs = create_test_job_batch();
let completed = filter_by_status(&jobs, TrainingStatus::Completed);
assert_eq!(completed.len(), 2);
}
#[test]
fn test_filter_by_model() {
let jobs = create_test_job_batch();
let tft_jobs = filter_by_model(&jobs, "TFT");
assert_eq!(tft_jobs.len(), 2);
}
#[test]
fn test_validate_job_structure() {
let job = create_test_job("test_1", "TFT", TrainingStatus::Pending);
assert!(validate_job_structure(&job));
let invalid_job = TrainingJobSummary {
job_id: "".to_string(),
..job
};
assert!(!validate_job_structure(&invalid_job));
}
#[test]
fn test_extract_job_ids() {
let jobs = create_test_job_batch();
let ids = extract_job_ids(&jobs);
assert_eq!(ids.len(), 5);
assert!(ids.contains(&"train_tft_es_20251022_140000".to_string()));
}
}