using System; using System.Threading.Tasks; using Paca.Mobile.Core; using Paca.Server.Gateway; using Xunit; namespace Paca.Tests.Mobile; /// /// Gate 127 ~ 132: 3G/4G/5G WAN 게이트웨이 및 Wi-Fi ↔ 셀룰러 무중단 로밍 기계적 검증 /// public class MobileWanGatewayRoamingGateTests { [Fact] public void Gate127_ConnectCode_Generation_And_Validation() { var code = PacaConnectCodeGenerator.GenerateCode(); Assert.NotNull(code); Assert.StartsWith("PACA-", code); Assert.True(PacaConnectCodeGenerator.IsValid(code)); Assert.False(PacaConnectCodeGenerator.IsValid("INVALID-CODE")); Assert.False(PacaConnectCodeGenerator.IsValid("")); Assert.False(PacaConnectCodeGenerator.IsValid(null)); } [Fact] public void Gate128_WanGatewayConfig_State_Management() { var gateway = new WanGatewayManager(deviceName: "Encep-Studio-PC", localPort: 52100); // 기본 상태는 비활성 Assert.False(gateway.IsActive); Assert.Equal(GatewayMode.Disabled, gateway.CurrentMode); // 원격 릴레이/터널 활성화 시뮬레이션 gateway.EnableCloudTunnel("https://relay.paca.app/tunnel-9876", "PACA-884123"); Assert.True(gateway.IsActive); Assert.Equal(GatewayMode.CloudTunnel, gateway.CurrentMode); Assert.Equal("https://relay.paca.app/tunnel-9876", gateway.PublicEndpoint); Assert.Equal("PACA-884123", gateway.ConnectCode); } [Fact] public void Gate129_Upnp_Mapping_Profile_Creation() { var gateway = new WanGatewayManager(deviceName: "Encep-Studio-PC", localPort: 52100); gateway.EnableDirectPortMapping(publicIp: "203.0.113.50", externalPort: 52100); Assert.True(gateway.IsActive); Assert.Equal(GatewayMode.DirectPortMapping, gateway.CurrentMode); Assert.Equal("http://203.0.113.50:52100", gateway.PublicEndpoint); } [Fact] public void Gate130_RoamingProfile_Serialization() { var profile = new RoamingDeviceProfile( DeviceId: "device-uuid-1234", DeviceName: "Encep-Desktop", LanEndpoint: "http://192.168.0.15:52100", WanEndpoint: "https://relay.paca.app/tunnel-9876", AuthToken: "token-secret-abc", ConnectCode: "PACA-884123" ); Assert.Equal("http://192.168.0.15:52100", profile.GetEndpointFor(NetworkEnvironment.LocalWifi)); Assert.Equal("https://relay.paca.app/tunnel-9876", profile.GetEndpointFor(NetworkEnvironment.CellularWan)); } [Fact] public void Gate131_RoamingConnectionManager_Auto_Failover() { var profile = new RoamingDeviceProfile( DeviceId: "device-uuid-1234", DeviceName: "Encep-Desktop", LanEndpoint: "http://192.168.0.15:52100", WanEndpoint: "https://relay.paca.app/tunnel-9876", AuthToken: "token-secret-abc", ConnectCode: "PACA-884123" ); var roaming = new RoamingConnectionManager(profile); // 초기 Wi-Fi 상태 -> LAN 우선 roaming.UpdateNetworkState(NetworkEnvironment.LocalWifi); Assert.Equal("http://192.168.0.15:52100", roaming.ActiveEndpoint); Assert.False(roaming.IsRoamingOnCellular); // LAN 연결 실패 또는 셀룰러 환경 진입 -> WAN 게이트웨이로 핫-페일오버 roaming.RecordConnectionFailure(); Assert.Equal("https://relay.paca.app/tunnel-9876", roaming.ActiveEndpoint); Assert.True(roaming.IsRoamingOnCellular); // Wi-Fi 재접속 및 헬스체크 복구 -> LAN 복귀 roaming.UpdateNetworkState(NetworkEnvironment.LocalWifi); roaming.RecordConnectionSuccess(); Assert.Equal("http://192.168.0.15:52100", roaming.ActiveEndpoint); Assert.False(roaming.IsRoamingOnCellular); } [Fact] public void Gate132_RoamingConnectionManager_Fallback_When_Wan_Empty() { var profile = new RoamingDeviceProfile( DeviceId: "dev-only-lan", DeviceName: "Desktop-LAN", LanEndpoint: "http://192.168.1.10:52100", WanEndpoint: null, // WAN 미설정 상태 AuthToken: "tok", ConnectCode: null ); var roaming = new RoamingConnectionManager(profile); roaming.UpdateNetworkState(NetworkEnvironment.CellularWan); // WAN이 없으면 LAN 주소를 유지하되 오류 상태 경고 플래그 Assert.Equal("http://192.168.1.10:52100", roaming.ActiveEndpoint); Assert.True(roaming.RequiresWanSetup); } }