use std::collections::HashMap;
use terraphim_agent::commands::{CommandDefinition, CommandParameter, ExecutionMode, RiskLevel};
fn create_test_command(
name: &str,
risk_level: RiskLevel,
execution_mode: ExecutionMode,
) -> CommandDefinition {
CommandDefinition {
name: name.to_string(),
description: format!("Test command for {}", name),
usage: Some(format!("{} [options]", name)),
category: Some("Testing".to_string()),
version: "1.0.0".to_string(),
risk_level,
execution_mode,
permissions: vec!["read".to_string(), "execute".to_string()],
knowledge_graph_required: vec![],
namespace: None,
aliases: vec![],
timeout: Some(30),
resource_limits: Some(terraphim_agent::commands::ResourceLimits {
max_memory_mb: Some(512),
max_cpu_time: Some(60),
max_disk_mb: Some(100),
network_access: false,
}),
parameters: vec![CommandParameter {
name: "input".to_string(),
param_type: "string".to_string(),
required: true,
description: Some("Input parameter".to_string()),
default_value: None,
validation: None,
allowed_values: None,
}],
}
}
#[cfg(test)]
mod local_execution_tests {
use super::*;
#[tokio::test]
async fn test_local_safe_command_execution() {
let command_def = create_test_command("safe-command", RiskLevel::Low, ExecutionMode::Local);
let mut parameters = HashMap::new();
parameters.insert("input".to_string(), "test".to_string());
assert_eq!(command_def.risk_level, RiskLevel::Low);
assert_eq!(command_def.execution_mode, ExecutionMode::Local);
assert!(command_def.permissions.contains(&"read".to_string()));
assert!(command_def.resource_limits.is_some());
let limits = command_def.resource_limits.as_ref().unwrap();
assert_eq!(limits.max_memory_mb, Some(512));
assert_eq!(limits.max_cpu_time, Some(60));
assert!(!limits.network_access);
}
#[tokio::test]
async fn test_local_command_timeout() {
let command_def = create_test_command("timeout-test", RiskLevel::Low, ExecutionMode::Local);
assert_eq!(command_def.timeout, Some(30));
}
#[tokio::test]
async fn test_local_command_resource_monitoring() {
let command_def =
create_test_command("resource-test", RiskLevel::Medium, ExecutionMode::Local);
assert!(command_def.resource_limits.is_some());
let limits = command_def.resource_limits.unwrap();
assert_eq!(limits.max_memory_mb, Some(512));
assert_eq!(limits.max_cpu_time, Some(60));
assert_eq!(limits.max_disk_mb, Some(100));
assert!(!limits.network_access);
}
}
#[cfg(test)]
mod firecracker_execution_tests {
use super::*;
#[tokio::test]
async fn test_firecracker_high_risk_command_execution() {
let command_def =
create_test_command("risky-command", RiskLevel::High, ExecutionMode::Firecracker);
let mut parameters = HashMap::new();
parameters.insert("input".to_string(), "sensitive_data".to_string());
assert_eq!(command_def.risk_level, RiskLevel::High);
assert_eq!(command_def.execution_mode, ExecutionMode::Firecracker);
assert!(command_def.permissions.contains(&"execute".to_string()));
assert!(command_def.resource_limits.is_some());
let limits = command_def.resource_limits.as_ref().unwrap();
assert_eq!(limits.max_memory_mb, Some(512));
assert_eq!(limits.max_cpu_time, Some(60));
assert!(!limits.network_access);
}
#[tokio::test]
async fn test_firecracker_critical_command_execution() {
let command_def = create_test_command(
"critical-command",
RiskLevel::Critical,
ExecutionMode::Firecracker,
);
assert_eq!(command_def.risk_level, RiskLevel::Critical);
assert_eq!(command_def.execution_mode, ExecutionMode::Firecracker);
assert!(command_def.resource_limits.is_some());
}
#[tokio::test]
async fn test_firecracker_vm_lifecycle() {
let command_def = create_test_command(
"vm-lifecycle-test",
RiskLevel::High,
ExecutionMode::Firecracker,
);
assert_eq!(command_def.timeout, Some(30));
assert!(command_def.resource_limits.is_some());
}
#[tokio::test]
async fn test_firecracker_network_isolation() {
let mut command_def = create_test_command(
"network-isolated",
RiskLevel::High,
ExecutionMode::Firecracker,
);
assert!(!command_def.resource_limits.as_ref().unwrap().network_access);
command_def.resource_limits.as_mut().unwrap().network_access = true;
assert!(command_def.resource_limits.as_ref().unwrap().network_access);
}
}
#[cfg(test)]
mod hybrid_execution_tests {
use super::*;
#[tokio::test]
async fn test_hybrid_mode_decision_logic() {
let test_cases = vec![
("safe-cmd", RiskLevel::Low, ExecutionMode::Local),
("medium-cmd", RiskLevel::Medium, ExecutionMode::Hybrid),
("risky-cmd", RiskLevel::High, ExecutionMode::Firecracker),
(
"critical-cmd",
RiskLevel::Critical,
ExecutionMode::Firecracker,
),
];
for (name, risk_level, expected_mode) in test_cases {
let command_def = create_test_command(name, risk_level.clone(), expected_mode.clone());
assert_eq!(
command_def.execution_mode,
expected_mode,
"Command '{}' with risk level {:?} should use {:?} mode",
name,
risk_level.clone(),
expected_mode.clone()
);
}
}
#[tokio::test]
async fn test_hybrid_mode_context_switching() {
let low_risk_cmd = create_test_command("low-risk", RiskLevel::Low, ExecutionMode::Hybrid);
let high_risk_cmd =
create_test_command("high-risk", RiskLevel::High, ExecutionMode::Hybrid);
assert_eq!(low_risk_cmd.execution_mode, ExecutionMode::Hybrid);
assert_eq!(high_risk_cmd.execution_mode, ExecutionMode::Hybrid);
}
#[tokio::test]
async fn test_hybrid_mode_fallback_behavior() {
let command_def =
create_test_command("fallback-test", RiskLevel::Medium, ExecutionMode::Hybrid);
assert!(command_def.timeout.is_some());
assert!(command_def.resource_limits.is_some());
assert!(!command_def.permissions.is_empty());
}
}
#[cfg(test)]
mod execution_mode_security_tests {
use super::*;
#[tokio::test]
async fn test_execution_mode_isolation() {
let local_cmd = create_test_command("local-test", RiskLevel::Low, ExecutionMode::Local);
let firecracker_cmd =
create_test_command("isolated-test", RiskLevel::High, ExecutionMode::Firecracker);
assert_eq!(local_cmd.execution_mode, ExecutionMode::Local);
assert_eq!(firecracker_cmd.execution_mode, ExecutionMode::Firecracker);
let local_limits = local_cmd.resource_limits.as_ref().unwrap();
let isolated_limits = firecracker_cmd.resource_limits.as_ref().unwrap();
assert_eq!(local_limits.max_memory_mb, Some(512));
assert_eq!(isolated_limits.max_memory_mb, Some(512));
}
#[tokio::test]
async fn test_execution_mode_resource_enforcement() {
let command_def = create_test_command(
"resource-enforcement",
RiskLevel::Medium,
ExecutionMode::Hybrid,
);
let limits = command_def.resource_limits.as_ref().unwrap();
assert!(limits.max_memory_mb.is_some());
assert!(limits.max_cpu_time.is_some());
assert!(limits.max_disk_mb.is_some());
assert!(command_def.timeout.is_some());
assert_eq!(command_def.timeout.unwrap(), 30);
}
#[tokio::test]
async fn test_execution_mode_error_handling() {
let test_cases = vec![
("local-error", RiskLevel::Low, ExecutionMode::Local),
("hybrid-error", RiskLevel::Medium, ExecutionMode::Hybrid),
(
"firecracker-error",
RiskLevel::High,
ExecutionMode::Firecracker,
),
];
for (name, risk_level, mode) in test_cases {
let command_def = create_test_command(name, risk_level.clone(), mode.clone());
assert_eq!(command_def.name, name);
assert_eq!(command_def.risk_level, risk_level);
assert_eq!(command_def.execution_mode, mode);
}
}
}
#[cfg(test)]
mod performance_tests {
use super::*;
use std::time::Instant;
#[tokio::test]
async fn test_command_parsing_performance() {
let start = Instant::now();
for i in 0..1000 {
let _cmd = create_test_command(
&format!("perf-test-{}", i),
RiskLevel::Low,
ExecutionMode::Local,
);
}
let duration = start.elapsed();
assert!(
duration.as_millis() < 100,
"Creating 1000 command definitions should take less than 100ms, took {:?}",
duration
);
}
#[tokio::test]
async fn test_parameter_validation_performance() {
let _command_def =
create_test_command("param-perf-test", RiskLevel::Medium, ExecutionMode::Hybrid);
let start = Instant::now();
for i in 0..10000 {
let mut params = HashMap::new();
params.insert("input".to_string(), format!("value-{}", i));
assert!(params.contains_key("input"));
}
let duration = start.elapsed();
assert!(
duration.as_millis() < 50,
"Validating 10000 parameter sets should take less than 50ms, took {:?}",
duration
);
}
#[tokio::test]
async fn test_registry_search_performance() {
let commands: Vec<_> = (0..1000)
.map(|i| {
create_test_command(&format!("cmd-{}", i), RiskLevel::Low, ExecutionMode::Local)
})
.collect();
let start = Instant::now();
let results: Vec<_> = commands.iter().filter(|cmd| cmd.name == "cmd-42").collect();
let duration = start.elapsed();
assert_eq!(results.len(), 1, "Should find exactly one command");
assert!(
duration.as_millis() < 10,
"Searching 1000 commands should take less than 10ms, took {:?}",
duration
);
}
}