//! Integration tests for Phase 4 WireGuard Engine, Client Config Generator, and QR Code system. use chrono::Utc; use ipnet::IpNet; use nx9_wg_core::crypto::{generate_keypair, generate_preshared_key}; use nx9_wg_core::types::wireguard::{ Interface, InterfaceRole, Peer, PeerProfile, PeerState, PeerType, }; use nx9_wireguard::{ ClientConfigBuilder, SimulatedWireGuardEngine, WireGuardEngine, generate_qr_ascii, generate_qr_data_url, generate_qr_png_bytes, generate_qr_svg, }; use std::str::FromStr; use uuid::Uuid; #[tokio::test] async fn test_wireguard_engine_lifecycle_and_telemetry() { let engine = SimulatedWireGuardEngine::new(); let (srv_priv, srv_pub) = generate_keypair(); let (peer1_priv, peer1_pub) = generate_keypair(); let (peer2_priv, peer2_pub) = generate_keypair(); let now = Utc::now().naive_utc(); let iface = Interface { id: Uuid::new_v4(), name: "wg0".to_string(), role: InterfaceRole::Overlay, private_key: srv_priv, public_key: srv_pub.clone(), listen_port: Some(51820), address_v4: IpNet::from_str("10.0.0.1/24").unwrap(), address_v6: None, mtu: Some(1420), dns: Some("1.1.1.1".to_string()), enabled: true, pre_up: None, post_up: None, pre_down: None, post_down: None, created_at: now, updated_at: now, }; let p1 = Peer { id: Uuid::new_v4(), interface_id: iface.id, name: "laptop-user".to_string(), peer_type: PeerType::RoadWarrior, state: PeerState::Active, public_key: peer1_pub.clone(), private_key: Some(peer1_priv), preshared_key: Some(generate_preshared_key()), endpoint: Some("198.51.100.2:45000".to_string()), allowed_ips: "10.0.0.2/32".to_string(), server_allowed_ips: None, address_v4: Some(IpNet::from_str("10.0.0.2/32").unwrap()), address_v6: None, dns: None, mtu: None, persistent_keepalive: Some(25), profile: PeerProfile::FullTunnel, expires_at: None, last_handshake_at: None, created_at: now, updated_at: now, }; let p2 = Peer { id: Uuid::new_v4(), interface_id: iface.id, name: "phone-user".to_string(), peer_type: PeerType::RoadWarrior, state: PeerState::Disabled, // disabled peer should NOT be in active kernel set public_key: peer2_pub.clone(), private_key: Some(peer2_priv), preshared_key: None, endpoint: None, allowed_ips: "10.0.0.3/32".to_string(), server_allowed_ips: None, address_v4: Some(IpNet::from_str("10.0.0.3/32").unwrap()), address_v6: None, dns: None, mtu: None, persistent_keepalive: None, profile: PeerProfile::FullTunnel, expires_at: None, last_handshake_at: None, created_at: now, updated_at: now, }; // 1. Sync interface with engine engine .sync_interface(&iface, &[p1.clone(), p2.clone()]) .await .expect("sync interface"); // 2. Read live interface stats let stats = engine .get_interface_stats("wg0") .await .expect("get stats") .expect("interface exists"); assert_eq!(stats.name, "wg0"); assert_eq!(stats.public_key, srv_pub.as_str()); assert_eq!(stats.addresses, vec!["10.0.0.1/24".to_string()]); assert_eq!(stats.mtu, Some(1420)); assert!(stats.is_up); assert_eq!( stats.peers.len(), 1, "only active peers should be synchronized" ); assert_eq!(stats.peers[0].public_key, peer1_pub.as_str()); // 3. Simulate peer traffic activity engine .simulate_peer_activity("wg0", peer1_pub.as_str(), 1024, 2048) .await .expect("simulate activity"); let updated_stats = engine.get_interface_stats("wg0").await.unwrap().unwrap(); assert_eq!(updated_stats.peers[0].rx_bytes, 1024); assert_eq!(updated_stats.peers[0].tx_bytes, 2048); assert!(updated_stats.peers[0].last_handshake_at.is_some()); // 4. Delete interface engine.delete_interface("wg0").await.expect("delete"); let after_del = engine.get_interface_stats("wg0").await.expect("query"); assert!(after_del.is_none()); } #[test] fn test_client_config_and_qr_codes() { let (srv_priv, srv_pub) = generate_keypair(); let (peer_priv, peer_pub) = generate_keypair(); let psk = generate_preshared_key(); let now = Utc::now().naive_utc(); let iface = Interface { id: Uuid::new_v4(), name: "wg0".to_string(), role: InterfaceRole::Overlay, private_key: srv_priv, public_key: srv_pub, listen_port: Some(51820), address_v4: IpNet::from_str("10.0.0.1/24").unwrap(), address_v6: None, mtu: Some(1420), dns: Some("1.1.1.1".to_string()), enabled: true, pre_up: None, post_up: None, pre_down: None, post_down: None, created_at: now, updated_at: now, }; let peer = Peer { id: Uuid::new_v4(), interface_id: iface.id, name: "ipad-charlie".to_string(), peer_type: PeerType::RoadWarrior, state: PeerState::Active, public_key: peer_pub, private_key: Some(peer_priv), preshared_key: Some(psk), endpoint: None, allowed_ips: "10.0.0.5/32".to_string(), server_allowed_ips: None, address_v4: Some(IpNet::from_str("10.0.0.5/32").unwrap()), address_v6: None, dns: None, mtu: None, persistent_keepalive: Some(25), profile: PeerProfile::FullTunnel, expires_at: None, last_handshake_at: None, created_at: now, updated_at: now, }; let config_str = ClientConfigBuilder::build(&peer, &iface, "203.0.113.10").unwrap(); assert!(config_str.contains("[Interface]")); assert!(config_str.contains("[Peer]")); assert!(config_str.contains("Endpoint = 203.0.113.10:51820")); // Verify all QR code output formats let svg = generate_qr_svg(&config_str).unwrap(); assert!(svg.contains("