Initial commit - Phase 3/4
🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
391
tests/unit/services/test_wifi_service.py
Normal file
391
tests/unit/services/test_wifi_service.py
Normal file
@@ -0,0 +1,391 @@
|
||||
"""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"
|
||||
Reference in New Issue
Block a user