use super::*;
use anyhow::Result;
use std::io::Write;
use tempfile::NamedTempFile;
fn classify_name(registry: &ClusterRegistry, syscall: &str) -> Option<String> {
let fds = FdTable::new();
registry.classify(syscall, &[], &fds).map(|c| c.name.clone())
}
#[test]
fn test_default_transpiler_clusters() {
let registry =
ClusterRegistry::default_transpiler_clusters().expect("Failed to load default clusters");
assert!(registry.get_cluster("MemoryAllocation").is_some());
assert!(registry.get_cluster("FileIO").is_some());
assert!(registry.get_cluster("ProcessControl").is_some());
assert!(registry.get_cluster("Synchronization").is_some());
assert!(registry.get_cluster("Randomness").is_some());
assert!(registry.get_cluster("Networking").is_some());
let networking = registry.get_cluster("Networking").expect("test");
assert_eq!(networking.severity, Severity::Critical);
assert_eq!(networking.anomaly_threshold, 0.0);
}
#[test]
fn test_classify_standard_syscalls() {
let registry = ClusterRegistry::default_transpiler_clusters().expect("test");
assert_eq!(classify_name(®istry, "mmap").as_deref(), Some("MemoryAllocation"));
assert_eq!(classify_name(®istry, "brk").as_deref(), Some("MemoryAllocation"));
assert_eq!(classify_name(®istry, "read").as_deref(), Some("FileIO"));
assert_eq!(classify_name(®istry, "write").as_deref(), Some("FileIO"));
assert_eq!(classify_name(®istry, "fork").as_deref(), Some("ProcessControl"));
assert_eq!(classify_name(®istry, "futex").as_deref(), Some("Synchronization"));
assert_eq!(classify_name(®istry, "socket").as_deref(), Some("Networking"));
}
#[test]
fn test_future_proof_syscalls() {
let registry = ClusterRegistry::default_transpiler_clusters().expect("test");
assert_eq!(classify_name(®istry, "mmap3").as_deref(), Some("MemoryAllocation"));
assert_eq!(classify_name(®istry, "clone3").as_deref(), Some("ProcessControl"));
}
#[test]
fn test_gpu_cluster_with_filter() {
let registry = ClusterRegistry::default_transpiler_clusters().expect("test");
let fds = FdTable::new();
assert!(registry.classify("ioctl", &["3".to_string()], &fds).is_none());
let mut fds_gpu = FdTable::new();
fds_gpu.insert(3, "/dev/nvidia0".to_string());
let cluster = registry.classify("ioctl", &["3".to_string()], &fds_gpu);
assert!(cluster.is_some());
assert_eq!(cluster.expect("test").name, "GPU");
}
#[test]
fn test_anomaly_detection() {
let registry = ClusterRegistry::default_transpiler_clusters().expect("test");
let mem_cluster = registry.get_cluster("MemoryAllocation").expect("test");
assert!(!mem_cluster.is_anomalous(100, 140)); assert!(mem_cluster.is_anomalous(100, 160));
let net_cluster = registry.get_cluster("Networking").expect("test");
assert!(net_cluster.is_anomalous(0, 1)); assert!(!net_cluster.is_anomalous(0, 0)); }
#[test]
fn test_custom_toml_clusters() -> Result<()> {
let mut file = NamedTempFile::new()?;
writeln!(
file,
r#"
[[cluster]]
name = "TensorFlow"
description = "TensorFlow C API calls"
syscalls = ["dlopen", "dlsym"]
expected_for_transpiler = false
anomaly_threshold = 0.0
severity = "medium"
[cluster.args_filter]
arg_contains = "libtensorflow"
"#
)?;
file.flush()?;
let registry = ClusterRegistry::from_toml(file.path())?;
let cluster = registry.classify("dlopen", &["/usr/lib/libm.so".to_string()], &FdTable::new());
assert!(cluster.is_none());
let cluster =
registry.classify("dlopen", &["/usr/lib/libtensorflow.so".to_string()], &FdTable::new());
assert!(cluster.is_some());
assert_eq!(cluster.expect("test").name, "TensorFlow");
Ok(())
}
#[test]
fn test_duplicate_syscall_error() {
let mut file = NamedTempFile::new().expect("test");
writeln!(
file,
r#"
[[cluster]]
name = "ClusterA"
description = "First cluster"
syscalls = ["mmap", "read"]
expected_for_transpiler = true
anomaly_threshold = 0.5
severity = "medium"
[[cluster]]
name = "ClusterB"
description = "Second cluster"
syscalls = ["write", "mmap"]
expected_for_transpiler = true
anomaly_threshold = 0.5
severity = "medium"
"#
)
.expect("test");
file.flush().expect("test");
let result = ClusterRegistry::from_toml(file.path());
assert!(result.is_err());
let err_msg = result.unwrap_err().to_string();
assert!(err_msg.contains("Duplicate syscall 'mmap'"));
assert!(err_msg.contains("ClusterA"));
assert!(err_msg.contains("ClusterB"));
}
#[test]
fn test_expected_for_transpiler() {
let registry = ClusterRegistry::default_transpiler_clusters().expect("test");
assert!(registry.get_cluster("MemoryAllocation").expect("test").expected_for_transpiler);
assert!(registry.get_cluster("FileIO").expect("test").expected_for_transpiler);
assert!(!registry.get_cluster("Networking").expect("test").expected_for_transpiler);
assert!(!registry.get_cluster("Synchronization").expect("test").expected_for_transpiler);
assert!(!registry.get_cluster("GPU").expect("test").expected_for_transpiler);
}
#[test]
fn test_severity_prioritization() {
let registry = ClusterRegistry::default_transpiler_clusters().expect("test");
let networking = registry.get_cluster("Networking").expect("test");
let synchronization = registry.get_cluster("Synchronization").expect("test");
let process_control = registry.get_cluster("ProcessControl").expect("test");
let memory = registry.get_cluster("MemoryAllocation").expect("test");
assert!(networking.severity == Severity::Critical);
assert!(synchronization.severity == Severity::Critical);
assert!(process_control.severity > memory.severity);
}