158 lines
4.5 KiB
Rust
158 lines
4.5 KiB
Rust
//! Unit tests for native Linux WireGuard conversion utilities and error invariants.
|
|
//!
|
|
//! These tests verify CIDR parsing, endpoint parsing, key decoding, and peer
|
|
//! filtering without requiring CAP_NET_ADMIN or kernel mutation.
|
|
|
|
use base64::Engine as _;
|
|
use nx9_wg_core::types::wireguard::PeerState;
|
|
use nx9_wireguard::WireGuardError;
|
|
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
|
|
|
|
#[test]
|
|
fn test_ipv4_cidr_parsing() {
|
|
let net: ipnet::IpNet = "10.0.0.2/32".parse().unwrap();
|
|
assert_eq!(net.addr(), IpAddr::V4(Ipv4Addr::new(10, 0, 0, 2)));
|
|
assert_eq!(net.prefix_len(), 32);
|
|
}
|
|
|
|
#[test]
|
|
fn test_ipv6_cidr_parsing() {
|
|
let net: ipnet::IpNet = "fd00::2/128".parse().unwrap();
|
|
assert!(net.addr().is_ipv6());
|
|
assert_eq!(net.prefix_len(), 128);
|
|
}
|
|
|
|
#[test]
|
|
fn test_multiple_allowed_ips_parsing() {
|
|
let csv = "10.0.0.2/32, fd00::2/128";
|
|
let nets: Vec<ipnet::IpNet> = csv
|
|
.split(',')
|
|
.map(|s| s.trim())
|
|
.filter(|s| !s.is_empty())
|
|
.map(|s| s.parse::<ipnet::IpNet>().unwrap())
|
|
.collect();
|
|
assert_eq!(nets.len(), 2);
|
|
assert!(nets[0].addr().is_ipv4());
|
|
assert!(nets[1].addr().is_ipv6());
|
|
}
|
|
|
|
#[test]
|
|
fn test_empty_allowed_ips() {
|
|
let csv = "";
|
|
let nets: Vec<ipnet::IpNet> = csv
|
|
.split(',')
|
|
.map(|s| s.trim())
|
|
.filter(|s| !s.is_empty())
|
|
.filter_map(|s| s.parse::<ipnet::IpNet>().ok())
|
|
.collect();
|
|
assert!(nets.is_empty());
|
|
}
|
|
|
|
#[test]
|
|
fn test_invalid_cidr_rejected() {
|
|
let result = "invalid/cidr".parse::<ipnet::IpNet>();
|
|
assert!(result.is_err());
|
|
}
|
|
|
|
#[test]
|
|
fn test_ipv4_endpoint_parsing() {
|
|
let addr: SocketAddr = "198.51.100.2:45000".parse().unwrap();
|
|
assert_eq!(addr.ip(), IpAddr::V4(Ipv4Addr::new(198, 51, 100, 2)));
|
|
assert_eq!(addr.port(), 45000);
|
|
}
|
|
|
|
#[test]
|
|
fn test_ipv6_endpoint_parsing() {
|
|
let addr: SocketAddr = "[2001:db8::1]:51820".parse().unwrap();
|
|
assert!(addr.ip().is_ipv6());
|
|
assert_eq!(addr.port(), 51820);
|
|
}
|
|
|
|
#[test]
|
|
fn test_invalid_endpoint_rejected() {
|
|
let result = "not-an-endpoint".parse::<SocketAddr>();
|
|
assert!(result.is_err());
|
|
}
|
|
|
|
#[test]
|
|
fn test_base64_key_decode_valid() {
|
|
let key_bytes = [0xAAu8; 32];
|
|
let b64 = base64::engine::general_purpose::STANDARD.encode(key_bytes);
|
|
let decoded = base64::engine::general_purpose::STANDARD
|
|
.decode(&b64)
|
|
.unwrap();
|
|
assert_eq!(decoded.len(), 32);
|
|
let mut arr = [0u8; 32];
|
|
arr.copy_from_slice(&decoded);
|
|
assert_eq!(arr, key_bytes);
|
|
}
|
|
|
|
#[test]
|
|
fn test_base64_key_decode_wrong_length() {
|
|
let short_key = [0xBBu8; 16];
|
|
let b64 = base64::engine::general_purpose::STANDARD.encode(short_key);
|
|
let decoded = base64::engine::general_purpose::STANDARD
|
|
.decode(&b64)
|
|
.unwrap();
|
|
assert_ne!(decoded.len(), 32);
|
|
}
|
|
|
|
#[test]
|
|
fn test_base64_key_decode_invalid_base64() {
|
|
let result = base64::engine::general_purpose::STANDARD.decode("not!valid!base64!!!");
|
|
assert!(result.is_err());
|
|
}
|
|
|
|
#[test]
|
|
fn test_peer_state_filtering() {
|
|
let states = [
|
|
PeerState::Active,
|
|
PeerState::Disabled,
|
|
PeerState::Revoked,
|
|
PeerState::Expired,
|
|
];
|
|
|
|
let active_count = states.iter().filter(|s| **s == PeerState::Active).count();
|
|
assert_eq!(active_count, 1, "only Active peers should be synchronized");
|
|
}
|
|
|
|
#[test]
|
|
fn test_error_display_no_key_leakage() {
|
|
let err = WireGuardError::Key("invalid base64".to_string());
|
|
let display = format!("{err}");
|
|
assert!(!display.contains("secret"));
|
|
assert!(!display.contains("private"));
|
|
assert!(display.contains("invalid base64"));
|
|
}
|
|
|
|
#[test]
|
|
fn test_error_variants_exist() {
|
|
let _ = format!("{}", WireGuardError::InterfaceNotFound("wg0".into()));
|
|
let _ = format!("{}", WireGuardError::WrongInterfaceType("eth0".into()));
|
|
let _ = format!("{}", WireGuardError::Unsupported("no kernel module".into()));
|
|
let _ = format!("{}", WireGuardError::InvalidEndpoint("bad:ep".into()));
|
|
let _ = format!("{}", WireGuardError::InvalidAllowedIp("bad/cidr".into()));
|
|
}
|
|
|
|
#[test]
|
|
fn test_prefix_length_preservation() {
|
|
let cases = [
|
|
("10.0.0.0/8", 8),
|
|
("10.0.0.0/16", 16),
|
|
("10.0.0.0/24", 24),
|
|
("10.0.0.1/32", 32),
|
|
("fd00::/64", 64),
|
|
("fd00::1/128", 128),
|
|
("0.0.0.0/0", 0),
|
|
("::/0", 0),
|
|
];
|
|
for (cidr, expected_prefix) in cases {
|
|
let net: ipnet::IpNet = cidr.parse().unwrap();
|
|
assert_eq!(
|
|
net.prefix_len(),
|
|
expected_prefix,
|
|
"prefix mismatch for {cidr}"
|
|
);
|
|
}
|
|
}
|