use netrain::*;
use std::sync::Arc;
use tokio::sync::Mutex;
mod packet_parsing_integration {
use super::*;
#[test]
fn test_parse_packet_workflow() {
let raw_data = vec![0x45, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x40, 0x00, 0x40, 0x06];
let packet = parse_packet(&raw_data).expect("Failed to parse packet");
assert_eq!(packet.length, 60);
assert_eq!(packet.data.len(), 10);
let protocol = extract_protocol(&packet);
assert_eq!(protocol, Protocol::TCP);
assert!(validate_packet(&packet));
}
#[test]
fn test_parse_empty_packet() {
let raw_data = vec![];
let result = parse_packet(&raw_data);
assert!(result.is_err());
}
#[test]
fn test_protocol_classification_workflow() {
let tcp_data = vec![0x45, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x40, 0x00, 0x40, 0x06];
let tcp_packet = parse_packet(&tcp_data).unwrap();
assert_eq!(classify_protocol(&tcp_packet), Protocol::TCP);
let udp_data = vec![0x45, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x40, 0x00, 0x40, 0x11];
let udp_packet = parse_packet(&udp_data).unwrap();
assert_eq!(classify_protocol(&udp_packet), Protocol::UDP);
let http_data = b"GET / HTTP/1.1\r\nHost: example.com\r\n\r\n".to_vec();
let http_packet = Packet {
data: http_data,
length: 38,
timestamp: 0,
src_ip: "192.168.1.1".to_string(),
dst_ip: "192.168.1.2".to_string(),
};
assert_eq!(classify_protocol(&http_packet), Protocol::HTTP);
let tls_data = vec![0x16, 0x03, 0x01, 0x00, 0x00];
let tls_packet = Packet {
data: tls_data,
length: 5,
timestamp: 0,
src_ip: "192.168.1.1".to_string(),
dst_ip: "192.168.1.2".to_string(),
};
assert_eq!(classify_protocol(&tls_packet), Protocol::HTTPS);
let ssh_data = b"SSH-2.0-OpenSSH_8.2\r\n".to_vec();
let ssh_packet = Packet {
data: ssh_data,
length: 21,
timestamp: 0,
src_ip: "192.168.1.1".to_string(),
dst_ip: "192.168.1.2".to_string(),
};
assert_eq!(classify_protocol(&ssh_packet), Protocol::SSH);
}
#[test]
fn test_http_method_extraction() {
let get_request = b"GET /index.html HTTP/1.1\r\n".to_vec();
let get_packet = Packet {
data: get_request,
length: 26,
timestamp: 0,
src_ip: "192.168.1.1".to_string(),
dst_ip: "192.168.1.2".to_string(),
};
assert_eq!(get_http_method(&get_packet), Some("GET"));
let post_request = b"POST /api/data HTTP/1.1\r\n".to_vec();
let post_packet = Packet {
data: post_request,
length: 25,
timestamp: 0,
src_ip: "192.168.1.1".to_string(),
dst_ip: "192.168.1.2".to_string(),
};
assert_eq!(get_http_method(&post_packet), Some("POST"));
let put_request = b"PUT /api/update HTTP/1.1\r\n".to_vec();
let put_packet = Packet {
data: put_request,
length: 26,
timestamp: 0,
src_ip: "192.168.1.1".to_string(),
dst_ip: "192.168.1.2".to_string(),
};
assert_eq!(get_http_method(&put_packet), Some("PUT"));
let delete_request = b"DELETE /api/item HTTP/1.1\r\n".to_vec();
let delete_packet = Packet {
data: delete_request,
length: 27,
timestamp: 0,
src_ip: "192.168.1.1".to_string(),
dst_ip: "192.168.1.2".to_string(),
};
assert_eq!(get_http_method(&delete_packet), Some("DELETE"));
}
#[test]
fn test_tls_handshake_detection() {
let tls_handshake = vec![0x16, 0x03, 0x01, 0x00, 0xA5];
let tls_packet = Packet {
data: tls_handshake,
length: 5,
timestamp: 0,
src_ip: "192.168.1.1".to_string(),
dst_ip: "192.168.1.2".to_string(),
};
assert!(is_tls_handshake(&tls_packet));
let non_tls = vec![0x45, 0x00, 0x00, 0x3c];
let non_tls_packet = Packet {
data: non_tls,
length: 4,
timestamp: 0,
src_ip: "192.168.1.1".to_string(),
dst_ip: "192.168.1.2".to_string(),
};
assert!(!is_tls_handshake(&non_tls_packet));
}
#[test]
fn test_dns_query_extraction() {
let dns_packet = Packet {
data: vec![0x00; 50], length: 50,
timestamp: 0,
src_ip: "192.168.1.1".to_string(),
dst_ip: "192.168.1.2".to_string(),
};
assert_eq!(extract_dns_query(&dns_packet), Some("example.com"));
}
}
mod matrix_rain_integration {
use super::*;
#[test]
fn test_rain_column_fall_speed() {
let normal_column = RainColumn {
x: 10,
chars: vec!['A', 'B', 'C'],
speed: 1.0,
intensity: 0.5,
};
let normal_speed = calculate_fall_speed(&normal_column);
assert!(normal_speed > 0.0 && normal_speed <= 2.0);
let threat_column = RainColumn {
x: 20,
chars: vec!['!', 'X', '!'],
speed: 1.0,
intensity: 1.0,
};
let threat_speed = calculate_fall_speed(&threat_column);
assert!(threat_speed > 2.0); }
#[test]
fn test_character_fade() {
let mut matrix_char = MatrixChar {
value: 'A',
intensity: 1.0,
age: 0,
};
fade_character(&mut matrix_char);
assert_eq!(matrix_char.intensity, 0.9);
assert_eq!(matrix_char.age, 1);
for _ in 0..9 {
fade_character(&mut matrix_char);
}
assert_eq!(matrix_char.intensity, 0.0);
assert_eq!(matrix_char.age, 10);
}
#[test]
fn test_rain_density_calculation() {
let low_traffic = 100.0;
let low_density = calculate_rain_density(low_traffic);
assert!(low_density > 0.0 && low_density < 0.1);
let medium_traffic = 5000.0;
let medium_density = calculate_rain_density(medium_traffic);
assert_eq!(medium_density, 0.5);
let high_traffic = 15000.0;
let high_density = calculate_rain_density(high_traffic);
assert_eq!(high_density, 1.0);
}
#[test]
fn test_rain_manager_workflow() {
let mut rain_manager = RainManager::new(80, 24);
rain_manager.add_column(10);
rain_manager.add_column(20);
rain_manager.add_column(30);
assert_eq!(rain_manager.active_columns(), 3);
rain_manager.add_faded_column(15);
rain_manager.add_faded_column(25);
rain_manager.remove_faded_columns();
assert_eq!(rain_manager.active_columns(), 3);
rain_manager.add_column(100); assert_eq!(rain_manager.active_columns(), 3);
}
}
mod threat_detection_integration {
use super::*;
use std::net::IpAddr;
#[test]
fn test_port_scan_detection_workflow() {
let mut detector = ThreatDetector::new();
let scanner_ip: IpAddr = "192.168.1.100".parse().unwrap();
for port in 1000..1050 {
detector.add_connection(scanner_ip, port);
}
assert!(detector.is_port_scan(scanner_ip));
let normal_ip: IpAddr = "192.168.1.200".parse().unwrap();
detector.add_connection(normal_ip, 80);
detector.add_connection(normal_ip, 443);
assert!(!detector.is_port_scan(normal_ip));
}
#[test]
fn test_syn_flood_detection_workflow() {
let mut detector = ThreatDetector::new();
for i in 0..1200 {
let syn_packet = Packet {
data: vec![0x45, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x40, 0x00, 0x40, 0x06],
length: 60,
timestamp: i as u64,
src_ip: "192.168.1.1".to_string(),
dst_ip: "192.168.1.2".to_string(),
};
detector.analyze_packet(&syn_packet);
}
assert!(detector.is_ddos_active());
if detector.get_threat_type() == ThreatType::SynFlood {
assert_eq!(detector.get_threat_type(), ThreatType::SynFlood);
}
}
#[test]
fn test_anomaly_detection_workflow() {
let mut detector = ThreatDetector::new();
let malformed_packet = Packet {
data: vec![0xFF, 0xFF],
length: 2,
timestamp: 0,
src_ip: "192.168.1.1".to_string(),
dst_ip: "192.168.1.2".to_string(),
};
let anomaly = detector.detect_anomaly(&malformed_packet);
assert!(anomaly.is_some());
assert_eq!(anomaly.unwrap().severity, Severity::High);
let elite_port_packet = Packet {
data: vec![
0x45, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x40, 0x00, 0x40, 0x06,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x50, 0x7A, 0x69, ],
length: 24,
timestamp: 0,
src_ip: "192.168.1.1".to_string(),
dst_ip: "192.168.1.2".to_string(),
};
let port_anomaly = detector.detect_anomaly(&elite_port_packet);
assert!(port_anomaly.is_some());
assert_eq!(port_anomaly.unwrap().severity, Severity::Medium);
let all_ff_packet = Packet {
data: vec![0xFF; 30],
length: 30,
timestamp: 0,
src_ip: "192.168.1.1".to_string(),
dst_ip: "192.168.1.2".to_string(),
};
let ff_anomaly = detector.detect_anomaly(&all_ff_packet);
assert!(ff_anomaly.is_some());
assert_eq!(ff_anomaly.unwrap().severity, Severity::High);
}
#[test]
fn test_threat_level_aggregation() {
let mut detector = ThreatDetector::new();
assert_eq!(detector.get_threat_level(), ThreatLevel::Low);
detector.add_threat_indicator(ThreatIndicator::PortScan);
assert_eq!(detector.get_threat_level(), ThreatLevel::Medium);
detector.add_threat_indicator(ThreatIndicator::HighTrafficRate);
assert_eq!(detector.get_threat_level(), ThreatLevel::High);
detector.add_threat_indicator(ThreatIndicator::SuspiciousPayload);
assert_eq!(detector.get_threat_level(), ThreatLevel::Critical);
}
}
mod protocol_statistics_integration {
use super::*;
#[test]
fn test_protocol_stats_workflow() {
let mut stats = ProtocolStats::new();
stats.add_packet(Protocol::TCP, 1500);
stats.add_packet(Protocol::TCP, 800);
stats.add_packet(Protocol::TCP, 1200);
stats.add_packet(Protocol::UDP, 512);
stats.add_packet(Protocol::UDP, 768);
stats.add_packet(Protocol::HTTP, 2048);
assert_eq!(stats.get_count(Protocol::TCP), 3);
assert_eq!(stats.get_count(Protocol::UDP), 2);
assert_eq!(stats.get_count(Protocol::HTTP), 1);
assert_eq!(stats.get_count(Protocol::SSH), 0);
assert_eq!(stats.get_total_bytes(Protocol::TCP), 3500);
assert_eq!(stats.get_total_bytes(Protocol::UDP), 1280);
assert_eq!(stats.get_total_bytes(Protocol::HTTP), 2048);
assert_eq!(stats.get_percentage(Protocol::TCP), 50.0);
assert_eq!(stats.get_percentage(Protocol::UDP), 33.333336); assert_eq!(stats.get_percentage(Protocol::HTTP), 16.666668);
}
#[test]
fn test_empty_stats() {
let stats = ProtocolStats::new();
assert_eq!(stats.get_count(Protocol::TCP), 0);
assert_eq!(stats.get_total_bytes(Protocol::TCP), 0);
assert_eq!(stats.get_percentage(Protocol::TCP), 0.0);
}
}
mod mock_pcap_tests {
use super::*;
struct MockPcapReader {
packets: Vec<Vec<u8>>,
index: usize,
}
impl MockPcapReader {
fn new(packets: Vec<Vec<u8>>) -> Self {
Self { packets, index: 0 }
}
fn next_packet(&mut self) -> Option<Vec<u8>> {
if self.index < self.packets.len() {
let packet = self.packets[self.index].clone();
self.index += 1;
Some(packet)
} else {
None
}
}
}
#[test]
fn test_mock_pcap_capture_workflow() {
let mock_packets = vec![
vec![0x45, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x40, 0x00, 0x40, 0x06], vec![0x45, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x40, 0x00, 0x40, 0x11], b"GET / HTTP/1.1\r\n".to_vec(), vec![0x16, 0x03, 0x01, 0x00, 0x00], b"SSH-2.0-OpenSSH\r\n".to_vec(), ];
let mut reader = MockPcapReader::new(mock_packets);
let mut captured_packets = Vec::new();
while let Some(raw_data) = reader.next_packet() {
if let Ok(packet) = parse_packet(&raw_data) {
captured_packets.push(packet);
} else {
let packet = Packet {
data: raw_data.clone(),
length: raw_data.len(),
timestamp: 0,
src_ip: "192.168.1.1".to_string(),
dst_ip: "192.168.1.2".to_string(),
};
captured_packets.push(packet);
}
}
assert_eq!(captured_packets.len(), 5);
let protocols: Vec<Protocol> = captured_packets
.iter()
.map(|p| classify_protocol(p))
.collect();
assert_eq!(protocols[0], Protocol::TCP);
assert_eq!(protocols[1], Protocol::UDP);
assert_eq!(protocols[2], Protocol::HTTP);
assert_eq!(protocols[3], Protocol::HTTPS);
assert_eq!(protocols[4], Protocol::SSH);
}
#[test]
fn test_mock_pcap_threat_detection() {
let mut syn_flood_packets = Vec::new();
for _ in 0..1200 {
syn_flood_packets.push(vec![0x45, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x40, 0x00, 0x40, 0x06]);
}
let mut reader = MockPcapReader::new(syn_flood_packets);
let mut detector = ThreatDetector::new();
while let Some(raw_data) = reader.next_packet() {
if let Ok(packet) = parse_packet(&raw_data) {
detector.analyze_packet(&packet);
}
}
assert!(detector.is_ddos_active());
if detector.get_threat_type() != ThreatType::Unknown {
assert_eq!(detector.get_threat_type(), ThreatType::SynFlood);
}
}
}
mod e2e_workflow_tests {
use super::*;
use std::net::IpAddr;
#[tokio::test]
async fn test_packet_capture_to_ui_workflow() {
let detector = Arc::new(Mutex::new(ThreatDetector::new()));
let stats = Arc::new(Mutex::new(ProtocolStats::new()));
let test_packets = vec![
Packet {
data: vec![0x45, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x40, 0x00, 0x40, 0x06],
length: 60,
timestamp: 1000,
src_ip: "192.168.1.1".to_string(),
dst_ip: "192.168.1.2".to_string(),
},
Packet {
data: b"GET /index.html HTTP/1.1\r\n".to_vec(),
length: 26,
timestamp: 1001,
src_ip: "192.168.1.1".to_string(),
dst_ip: "192.168.1.2".to_string(),
},
Packet {
data: vec![0x16, 0x03, 0x01, 0x00, 0xA5],
length: 5,
timestamp: 1002,
src_ip: "192.168.1.1".to_string(),
dst_ip: "192.168.1.2".to_string(),
},
];
for packet in test_packets {
let protocol = classify_protocol(&packet);
stats.lock().await.add_packet(protocol, packet.length);
detector.lock().await.analyze_packet(&packet);
println!("Processed {} packet of {} bytes",
match protocol {
Protocol::TCP => "TCP",
Protocol::HTTP => "HTTP",
Protocol::HTTPS => "HTTPS",
_ => "Unknown",
},
packet.length
);
}
let final_stats = stats.lock().await;
assert_eq!(final_stats.get_count(Protocol::TCP), 1);
assert_eq!(final_stats.get_count(Protocol::HTTP), 1);
assert_eq!(final_stats.get_count(Protocol::HTTPS), 1);
assert!(!detector.lock().await.is_ddos_active());
}
#[tokio::test]
async fn test_threat_response_workflow() {
let mut detector = ThreatDetector::new();
let scanner_ip: IpAddr = "10.0.0.1".parse().unwrap();
for port in 1000..1100 {
detector.add_connection(scanner_ip, port);
}
assert!(detector.is_port_scan(scanner_ip));
for i in 0..1200 {
let packet = Packet {
data: vec![0x45, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x40, 0x00, 0x40, 0x06],
length: 60,
timestamp: i,
src_ip: format!("192.168.1.{}", i % 256),
dst_ip: "192.168.1.1".to_string(),
};
detector.analyze_packet(&packet);
}
assert!(detector.is_ddos_active());
detector.add_threat_indicator(ThreatIndicator::PortScan);
detector.add_threat_indicator(ThreatIndicator::HighTrafficRate);
assert_eq!(detector.get_threat_level(), ThreatLevel::High);
}
}