"""Unit tests for WiFiService. Tests the WiFiService business logic layer, ensuring: - WiFi status queries - Network scanning and connection - Mode switching - Saved network management - Error handling and error codes """ import pytest from unittest.mock import AsyncMock, Mock from app.backend.services.wifi_service import WiFiService from app.backend.managers.wifi_manager import WiFiMode, WiFiStatus, WiFiNetwork, WiFiInterface class TestWiFiServiceStatus: """Test WiFi status queries.""" @pytest.mark.asyncio async def test_get_status_success(self, mock_wifi_manager): """Test successful WiFi status retrieval.""" # Arrange test_interface = WiFiInterface( name="wlan0", mac="00:11:22:33:44:55", is_usb=False, is_up=True, connected=False, ssid=None, ip_address="10.3.141.1" ) mock_wifi_manager.get_status.return_value = WiFiStatus( mode=WiFiMode.AP, interfaces=[test_interface], current_ssid=None, current_ip=None, ap_ssid="dangerous-pi", ap_ip="10.3.141.1", supports_dual=False ) service = WiFiService(mock_wifi_manager) # Act result = await service.get_status() # Assert assert result.success is True assert result.data["mode"] == "ap" assert len(result.data["interfaces"]) == 1 assert result.data["interfaces"][0]["name"] == "wlan0" assert result.data["access_point"]["ssid"] == "dangerous-pi" assert result.data["supports_dual"] is False @pytest.mark.asyncio async def test_get_status_with_client_connection(self, mock_wifi_manager): """Test WiFi status with client connection.""" # Arrange test_interface = WiFiInterface( name="wlan0", mac="00:11:22:33:44:55", is_usb=False, is_up=True, connected=True, ssid="MyNetwork", ip_address="192.168.1.100" ) mock_wifi_manager.get_status.return_value = WiFiStatus( mode=WiFiMode.CLIENT, interfaces=[test_interface], current_ssid="MyNetwork", current_ip="192.168.1.100", ap_ssid="dangerous-pi", ap_ip="10.3.141.1", supports_dual=False ) service = WiFiService(mock_wifi_manager) # Act result = await service.get_status() # Assert assert result.success is True assert result.data["mode"] == "client" assert result.data["client"]["ssid"] == "MyNetwork" assert result.data["client"]["ip"] == "192.168.1.100" @pytest.mark.asyncio async def test_get_status_exception(self, mock_wifi_manager): """Test WiFi status query with exception.""" # Arrange mock_wifi_manager.get_status.side_effect = Exception("WiFi error") service = WiFiService(mock_wifi_manager) # Act result = await service.get_status() # Assert assert result.success is False assert result.error.code == "wifi_status_error" assert "WiFi error" in result.error.details class TestWiFiServiceNetworkScanning: """Test network scanning.""" @pytest.mark.asyncio async def test_scan_networks_success(self, mock_wifi_manager): """Test successful network scan.""" # Arrange test_networks = [ WiFiNetwork( ssid="TestNetwork", bssid="AA:BB:CC:DD:EE:FF", signal_strength=-45, frequency=2437, encrypted=True, in_use=False ), WiFiNetwork( ssid="OpenNetwork", bssid="11:22:33:44:55:66", signal_strength=-65, frequency=2462, encrypted=False, in_use=False ) ] mock_wifi_manager.scan_networks.return_value = test_networks service = WiFiService(mock_wifi_manager) # Act result = await service.scan_networks() # Assert assert result.success is True assert result.data["count"] == 2 assert len(result.data["networks"]) == 2 assert result.data["networks"][0]["ssid"] == "TestNetwork" assert result.data["networks"][0]["encrypted"] is True assert result.data["networks"][1]["ssid"] == "OpenNetwork" assert result.data["networks"][1]["encrypted"] is False @pytest.mark.asyncio async def test_scan_networks_with_interface(self, mock_wifi_manager): """Test network scan with specific interface.""" # Arrange mock_wifi_manager.scan_networks.return_value = [] service = WiFiService(mock_wifi_manager) # Act result = await service.scan_networks(interface="wlan1") # Assert assert result.success is True mock_wifi_manager.scan_networks.assert_called_once_with("wlan1") @pytest.mark.asyncio async def test_scan_networks_exception(self, mock_wifi_manager): """Test network scan with exception.""" # Arrange mock_wifi_manager.scan_networks.side_effect = Exception("Scan failed") service = WiFiService(mock_wifi_manager) # Act result = await service.scan_networks() # Assert assert result.success is False assert result.error.code == "wifi_scan_error" class TestWiFiServiceConnection: """Test network connection management.""" @pytest.mark.asyncio async def test_connect_success(self, mock_wifi_manager): """Test successful network connection.""" # Arrange mock_wifi_manager.connect_to_network.return_value = True mock_wifi_manager.get_status.return_value = WiFiStatus( mode=WiFiMode.CLIENT, interfaces=[], current_ssid="TestNetwork", current_ip="192.168.1.100", ap_ssid=None, ap_ip=None, supports_dual=False ) service = WiFiService(mock_wifi_manager) # Act result = await service.connect( ssid="TestNetwork", password="testpass123" ) # Assert assert result.success is True assert "TestNetwork" in result.data["message"] assert result.data["ssid"] == "TestNetwork" assert result.data["ip"] == "192.168.1.100" mock_wifi_manager.connect_to_network.assert_called_once_with( ssid="TestNetwork", password="testpass123", interface=None, hidden=False ) @pytest.mark.asyncio async def test_connect_open_network(self, mock_wifi_manager): """Test connection to open network.""" # Arrange mock_wifi_manager.connect_to_network.return_value = True mock_wifi_manager.get_status.return_value = WiFiStatus( mode=WiFiMode.CLIENT, interfaces=[], current_ssid="OpenNet", current_ip="192.168.1.50", ap_ssid=None, ap_ip=None, supports_dual=False ) service = WiFiService(mock_wifi_manager) # Act result = await service.connect(ssid="OpenNet", password=None) # Assert assert result.success is True mock_wifi_manager.connect_to_network.assert_called_once_with( ssid="OpenNet", password=None, interface=None, hidden=False ) @pytest.mark.asyncio async def test_connect_failure(self, mock_wifi_manager): """Test failed network connection.""" # Arrange mock_wifi_manager.connect_to_network.return_value = False service = WiFiService(mock_wifi_manager) # Act result = await service.connect(ssid="BadNetwork", password="wrong") # Assert assert result.success is False assert result.error.code == "connection_failed" @pytest.mark.asyncio async def test_disconnect_success(self, mock_wifi_manager): """Test successful disconnect.""" # Arrange mock_wifi_manager.disconnect_from_network.return_value = True service = WiFiService(mock_wifi_manager) # Act result = await service.disconnect() # Assert assert result.success is True assert "Disconnected" in result.data["message"] @pytest.mark.asyncio async def test_disconnect_failure(self, mock_wifi_manager): """Test failed disconnect.""" # Arrange mock_wifi_manager.disconnect_from_network.return_value = False service = WiFiService(mock_wifi_manager) # Act result = await service.disconnect() # Assert assert result.success is False assert result.error.code == "disconnect_failed" class TestWiFiServiceModeSwitch: """Test WiFi mode switching.""" @pytest.mark.asyncio async def test_set_mode_ap(self, mock_wifi_manager): """Test switching to AP mode.""" # Arrange mock_wifi_manager.set_mode.return_value = True service = WiFiService(mock_wifi_manager) # Act result = await service.set_mode("ap") # Assert assert result.success is True assert result.data["mode"] == "ap" @pytest.mark.asyncio async def test_set_mode_client(self, mock_wifi_manager): """Test switching to client mode.""" # Arrange mock_wifi_manager.set_mode.return_value = True service = WiFiService(mock_wifi_manager) # Act result = await service.set_mode("client") # Assert assert result.success is True assert result.data["mode"] == "client" @pytest.mark.asyncio async def test_set_mode_invalid(self, mock_wifi_manager): """Test invalid mode.""" # Arrange service = WiFiService(mock_wifi_manager) # Act result = await service.set_mode("invalid_mode") # Assert assert result.success is False assert result.error.code == "invalid_mode" @pytest.mark.asyncio async def test_set_mode_dual_not_supported(self, mock_wifi_manager): """Test dual mode without USB adapter.""" # Arrange mock_wifi_manager.set_mode.side_effect = ValueError("Dual mode requires USB WiFi adapter") service = WiFiService(mock_wifi_manager) # Act result = await service.set_mode("dual") # Assert assert result.success is False assert result.error.code == "mode_not_supported" class TestWiFiServiceSavedNetworks: """Test saved network management.""" @pytest.mark.asyncio async def test_get_saved_networks_success(self, mock_wifi_manager): """Test retrieving saved networks.""" # Arrange saved = [ {"id": "0", "ssid": "HomeNet", "enabled": True}, {"id": "1", "ssid": "WorkNet", "enabled": False} ] mock_wifi_manager.get_saved_networks.return_value = saved service = WiFiService(mock_wifi_manager) # Act result = await service.get_saved_networks() # Assert assert result.success is True assert result.data["count"] == 2 assert result.data["networks"][0]["ssid"] == "HomeNet" @pytest.mark.asyncio async def test_forget_network_success(self, mock_wifi_manager): """Test forgetting a saved network.""" # Arrange mock_wifi_manager.forget_network.return_value = True service = WiFiService(mock_wifi_manager) # Act result = await service.forget_network("OldNetwork") # Assert assert result.success is True assert "OldNetwork" in result.data["message"] mock_wifi_manager.forget_network.assert_called_once_with("OldNetwork") @pytest.mark.asyncio async def test_forget_network_not_found(self, mock_wifi_manager): """Test forgetting non-existent network.""" # Arrange mock_wifi_manager.forget_network.return_value = False service = WiFiService(mock_wifi_manager) # Act result = await service.forget_network("NonExistent") # Assert assert result.success is False assert result.error.code == "network_not_found"