Files
nx9-wg/crates/nx9-wg-db/tests/test_network_repositories.rs
T
2026-09-02 15:19:19 +05:30

290 lines
8.5 KiB
Rust

//! Tests for Network, Route, and Firewall Rule repositories.
use chrono::Utc;
use ipnet::IpNet;
use nx9_wg_core::crypto::generate_keypair;
use nx9_wg_core::types::firewall::{
FirewallAction, FirewallDirection, FirewallProtocol, FirewallRule,
};
use nx9_wg_core::types::network::{Network, Route};
use nx9_wg_core::types::wireguard::{Interface, InterfaceRole};
use nx9_wg_db::Store;
use std::net::IpAddr;
use std::str::FromStr;
use uuid::Uuid;
#[tokio::test]
async fn test_network_and_route_crud() {
let store = Store::connect_in_memory().await.expect("connect");
store.migrate().await.expect("migrate");
let now = Utc::now().naive_utc();
let net_id = Uuid::new_v4();
let net = Network {
id: net_id,
name: "Home Lab".to_string(),
cidr: IpNet::from_str("192.168.10.0/24").expect("cidr"),
enabled: true,
description: Some("Internal lab subnet".to_string()),
created_at: now,
updated_at: now,
};
store.create_network(&net).await.expect("create_network");
let fetched_net = store
.get_network(net_id)
.await
.expect("get")
.expect("found");
assert_eq!(fetched_net.name, "Home Lab");
assert_eq!(fetched_net.cidr.to_string(), "192.168.10.0/24");
assert!(fetched_net.enabled);
// Test routes
let route_id = Uuid::new_v4();
let route = Route {
id: route_id,
network_id: Some(net_id),
interface_id: None,
destination: IpNet::from_str("192.168.10.0/24").expect("dest cidr"),
gateway: Some(IpAddr::from_str("10.0.0.1").expect("gateway")),
interface_name: None,
metric: Some(100),
enabled: true,
description: Some("Lab route via wg gateway".to_string()),
created_at: now,
updated_at: now,
};
store.create_route(&route).await.expect("create_route");
let fetched_route = store
.get_route(route_id)
.await
.expect("get")
.expect("route found");
assert_eq!(fetched_route.network_id, Some(net_id));
assert_eq!(
fetched_route.gateway,
Some(IpAddr::from_str("10.0.0.1").unwrap())
);
assert_eq!(fetched_route.metric, Some(100));
// Enable/disable route
store
.set_route_enabled(route_id, false)
.await
.expect("disable");
let disabled_route = store
.get_route(route_id)
.await
.expect("get")
.expect("route");
assert!(!disabled_route.enabled);
// List routes for network
let net_routes = store
.list_routes_for_network(net_id)
.await
.expect("list net routes");
assert_eq!(net_routes.len(), 1);
// Deleting network sets route's network_id to NULL (ON DELETE SET NULL)
store.delete_network(net_id).await.expect("delete network");
let route_after_net_delete = store
.get_route(route_id)
.await
.expect("get")
.expect("route");
assert!(
route_after_net_delete.network_id.is_none(),
"network_id must be SET NULL when network is deleted"
);
}
#[tokio::test]
async fn test_firewall_rule_crud_and_priority_ordering() {
let store = Store::connect_in_memory().await.expect("connect");
store.migrate().await.expect("migrate");
let now = Utc::now().naive_utc();
let iface_id = Uuid::new_v4();
let (priv_k, pub_k) = generate_keypair();
let iface = Interface {
id: iface_id,
name: "wg0".to_string(),
role: InterfaceRole::Overlay,
private_key: priv_k,
public_key: pub_k,
listen_port: Some(51820),
address_v4: IpNet::from_str("10.0.0.1/24").unwrap(),
address_v6: None,
mtu: None,
dns: None,
enabled: true,
pre_up: None,
post_up: None,
pre_down: None,
post_down: None,
created_at: now,
updated_at: now,
};
store
.create_interface(&iface)
.await
.expect("create interface");
let rule1_id = Uuid::new_v4();
let rule1 = FirewallRule {
id: rule1_id,
name: "Allow SSH".to_string(),
interface_id: Some(iface_id),
peer_id: None,
direction: FirewallDirection::In,
action: FirewallAction::Accept,
protocol: FirewallProtocol::Tcp,
source: None,
destination: None,
source_port: None,
destination_port: Some(22),
port_range: None,
priority: 50,
enabled: true,
description: Some("SSH access".to_string()),
created_at: now,
updated_at: now,
};
let rule2_id = Uuid::new_v4();
let rule2 = FirewallRule {
id: rule2_id,
name: "Drop All Other".to_string(),
interface_id: Some(iface_id),
peer_id: None,
direction: FirewallDirection::In,
action: FirewallAction::Drop,
protocol: FirewallProtocol::Any,
source: None,
destination: None,
source_port: None,
destination_port: None,
port_range: None,
priority: 100,
enabled: true,
description: Some("Default drop".to_string()),
created_at: now,
updated_at: now,
};
store
.create_firewall_rule(&rule2)
.await
.expect("create rule2");
store
.create_firewall_rule(&rule1)
.await
.expect("create rule1");
// List rules should order by priority ASC (rule1 priority 50 comes before rule2 priority 100)
let rules = store.list_firewall_rules().await.expect("list rules");
assert_eq!(rules.len(), 2);
assert_eq!(rules[0].id, rule1_id);
assert_eq!(rules[0].priority, 50);
assert_eq!(rules[1].id, rule2_id);
assert_eq!(rules[1].priority, 100);
// List rules for interface
let iface_rules = store
.list_firewall_rules_for_interface(iface_id)
.await
.expect("list iface rules");
assert_eq!(iface_rules.len(), 2);
// Enable/disable rule
store
.set_firewall_rule_enabled(rule1_id, false)
.await
.expect("disable");
let disabled = store
.get_firewall_rule(rule1_id)
.await
.expect("get")
.expect("rule");
assert!(!disabled.enabled);
// Delete rule
store.delete_firewall_rule(rule1_id).await.expect("delete");
assert!(
store
.get_firewall_rule(rule1_id)
.await
.expect("get")
.is_none()
);
// Peer-specific rule with port range
let peer_id = Uuid::new_v4();
let peer = nx9_wg_core::types::wireguard::Peer {
id: peer_id,
interface_id: iface_id,
name: "test-peer-fw".to_string(),
peer_type: nx9_wg_core::types::wireguard::PeerType::RoadWarrior,
state: nx9_wg_core::types::wireguard::PeerState::Active,
public_key: nx9_wg_core::types::wireguard::WireGuardPublicKey::new(
"testpubkey12345678901234567890123456789012=".to_string(),
),
private_key: None,
preshared_key: None,
endpoint: None,
allowed_ips: "10.0.0.2/32".to_string(),
server_allowed_ips: None,
address_v4: Some("10.0.0.2/32".parse().unwrap()),
address_v6: None,
dns: None,
mtu: None,
persistent_keepalive: None,
profile: nx9_wg_core::types::wireguard::PeerProfile::FullTunnel,
expires_at: None,
last_handshake_at: None,
created_at: now,
updated_at: now,
};
store.create_peer(&peer).await.expect("create peer");
let peer_rule_id = Uuid::new_v4();
let peer_rule = FirewallRule {
id: peer_rule_id,
name: "Peer Port Range Rule".to_string(),
interface_id: Some(iface_id),
peer_id: Some(peer_id),
direction: FirewallDirection::In,
action: FirewallAction::Accept,
protocol: FirewallProtocol::TcpUdp,
source: None,
destination: None,
source_port: None,
destination_port: None,
port_range: Some("8000-8100".to_string()),
priority: 25,
enabled: true,
description: Some("Custom peer range".to_string()),
created_at: now,
updated_at: now,
};
store
.create_firewall_rule(&peer_rule)
.await
.expect("create peer rule");
let peer_rules = store
.list_firewall_rules_for_peer(peer_id)
.await
.expect("list peer rules");
assert_eq!(peer_rules.len(), 1);
assert_eq!(peer_rules[0].port_range.as_deref(), Some("8000-8100"));
assert_eq!(peer_rules[0].protocol, FirewallProtocol::TcpUdp);
}