Improve test coverage for switch in Fritz (#161630)

This commit is contained in:
Simone Chemelli
2026-01-27 10:48:51 +01:00
committed by GitHub
parent 69ee3a15b6
commit 1f8a98609c
5 changed files with 698 additions and 14 deletions

View File

@@ -3,7 +3,7 @@
from __future__ import annotations
import logging
from typing import Any
from typing import TYPE_CHECKING, Any
from homeassistant.components.network import async_get_source_ip
from homeassistant.components.switch import SwitchEntity, SwitchEntityDescription
@@ -382,7 +382,7 @@ class FritzBoxPortSwitch(FritzBoxBaseSwitch):
self,
avm_wrapper: AvmWrapper,
device_friendly_name: str,
port_mapping: dict[str, Any] | None,
port_mapping: dict[str, Any],
port_name: str,
idx: int,
connection_type: str,
@@ -396,9 +396,6 @@ class FritzBoxPortSwitch(FritzBoxBaseSwitch):
self._idx = idx # needed for update routine
self._attr_entity_category = EntityCategory.CONFIG
if port_mapping is None:
return
switch_info = SwitchInfo(
description=f"Port forward {port_name}",
friendly_name=device_friendly_name,
@@ -438,9 +435,6 @@ class FritzBoxPortSwitch(FritzBoxBaseSwitch):
self._attributes[attr] = self.port_mapping[key]
async def _async_switch_on_off_executor(self, turn_on: bool) -> bool:
if self.port_mapping is None:
return False
self.port_mapping["NewEnabled"] = "1" if turn_on else "0"
resp = await self._avm_wrapper.async_add_port_mapping(
@@ -530,8 +524,8 @@ class FritzBoxProfileSwitch(FritzDeviceBase, SwitchEntity):
async def _async_handle_turn_on_off(self, turn_on: bool) -> bool:
"""Handle switch state change request."""
if not self.ip_address:
return False
if TYPE_CHECKING:
assert self.ip_address
await self._avm_wrapper.async_set_allow_wan_access(self.ip_address, turn_on)
self._avm_wrapper.devices[self._mac].wan_access = turn_on
self.async_write_ha_state()

View File

@@ -5,6 +5,8 @@ from unittest.mock import MagicMock, patch
from fritzconnection.core.processor import Service
from fritzconnection.lib.fritzhosts import FritzHosts
from fritzconnection.lib.fritzstatus import FritzStatus
from fritzconnection.lib.fritztools import ArgumentNamespace
import pytest
from .const import (
@@ -12,6 +14,9 @@ from .const import (
MOCK_HOST_ATTRIBUTES_DATA,
MOCK_MESH_DATA,
MOCK_MODELNAME,
MOCK_STATUS_AVM_DEVICE_LOG_DATA,
MOCK_STATUS_CONNECTION_DATA,
MOCK_STATUS_DEVICE_INFO_DATA,
)
LOGGER = logging.getLogger(__name__)
@@ -121,3 +126,25 @@ def fh_class_mock():
result.get_mesh_topology = MagicMock(return_value=MOCK_MESH_DATA)
result.get_hosts_attributes = MagicMock(return_value=MOCK_HOST_ATTRIBUTES_DATA)
yield result
@pytest.fixture
def fs_class_mock():
"""Fixture that sets up a mocked FritzStatus class."""
with patch(
"homeassistant.components.fritz.coordinator.FritzStatus",
new=FritzStatus,
) as result:
result.get_default_connection_service = MagicMock(
return_value=MOCK_STATUS_CONNECTION_DATA
)
result.get_device_info = MagicMock(
return_value=ArgumentNamespace(MOCK_STATUS_DEVICE_INFO_DATA)
)
result.get_monitor_data = MagicMock(return_value={})
result.get_cpu_temperatures = MagicMock(return_value=[42, 38])
result.get_avm_device_log = MagicMock(
return_value=MOCK_STATUS_AVM_DEVICE_LOG_DATA
)
result.has_wan_enabled = True
yield result

View File

@@ -1,5 +1,7 @@
"""Common stuff for Fritz!Tools tests."""
from fritzconnection.lib.fritzstatus import DefaultConnectionService
from homeassistant.components.fritz.const import DOMAIN
from homeassistant.const import (
CONF_DEVICES,
@@ -57,9 +59,17 @@ MOCK_FB_SERVICES: dict[str, dict] = {
"GetInfo": {
"NewSerialNumber": MOCK_MESH_MASTER_MAC,
"NewName": "TheName",
"NewManufacturerName": "AVM",
"NewManufacturerOUI": "00040E",
"NewModelName": MOCK_MODELNAME,
"NewDescription": f"{MOCK_MODELNAME} {MOCK_FIRMWARE}",
"NewProductClass": "AVMFB7590AX",
"NewSoftwareVersion": MOCK_FIRMWARE,
"NewHardwareVersion": MOCK_MODELNAME,
"NewSpecVersion": "1.0",
"NewDeviceLog": "long string here ...",
"NewUpTime": 2518179,
"NewProvisioningCode": "000.044.004.000",
},
},
"Hosts1": {
@@ -147,7 +157,27 @@ MOCK_FB_SERVICES: dict[str, dict] = {
"NewDownstreamMaxBitRate": 43430530,
"NewExternalIPAddress": "1.2.3.4",
},
"GetPortMappingNumberOfEntries": {},
"GetPortMappingNumberOfEntries": {
"NewPortMappingNumberOfEntries": 2,
},
"GetGenericPortMappingEntry": {
0: {
"NewInternalClient": "10.10.10.10",
"NewPortMappingDescription": "Test Port Mapping",
"NewInternalPort": 8080,
"NewExternalPort": 80,
"NewProtocol": "TCP",
"NewEnabled": True,
},
1: {
"NewInternalClient": "10.10.10.10",
"NewPortMappingDescription": "Test Port Mapping",
"NewInternalPort": 8081,
"NewExternalPort": 81,
"NewProtocol": "UDP",
"NewEnabled": True,
},
},
},
"WLANConfiguration1": {
"GetInfo": {
@@ -158,11 +188,15 @@ MOCK_FB_SERVICES: dict[str, dict] = {
"NewX_AVM-DE_PossibleBeaconTypes": "None,11i,11iandWPA3",
"NewStandard": "ax",
"NewBSSID": "1C:ED:6F:12:34:13",
"NewMACAddressControlEnabled": True,
},
"GetSSID": {
"NewSSID": "MyWifi",
},
"GetSecurityKeys": {"NewKeyPassphrase": "1234567890"},
"GetBeaconAdvertisement": {
"NewBeaconAdvertisementEnabled": True,
},
},
"X_AVM-DE_Homeauto1": {
"GetGenericDeviceInfos": [
@@ -938,6 +972,12 @@ MOCK_CALL_DEFLECTION_DATA = {
}
}
MOCK_STATUS_CONNECTION_DATA = DefaultConnectionService("1", "WANPPPConnection", "1")
MOCK_STATUS_DEVICE_INFO_DATA = MOCK_FB_SERVICES["DeviceInfo1"]["GetInfo"]
MOCK_STATUS_AVM_DEVICE_LOG_DATA = MOCK_FB_SERVICES["DeviceInfo1"]["GetInfo"][
"NewDeviceLog"
]
MOCK_USER_DATA = MOCK_CONFIG[DOMAIN][CONF_DEVICES][0]
MOCK_USER_INPUT_ADVANCED = MOCK_USER_DATA
MOCK_USER_INPUT_SIMPLE = {

View File

@@ -1,4 +1,104 @@
# serializer version: 1
# name: test_switch_setup[fc_data0][switch.mock_title_port_forward_test_port_mapping-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'switch',
'entity_category': <EntityCategory.CONFIG: 'config'>,
'entity_id': 'switch.mock_title_port_forward_test_port_mapping',
'has_entity_name': False,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'object_id_base': 'Mock Title Port forward Test Port Mapping',
'options': dict({
}),
'original_device_class': None,
'original_icon': 'mdi:check-network',
'original_name': 'Mock Title Port forward Test Port Mapping',
'platform': 'fritz',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': '1C:ED:6F:12:34:11-port_forward_test_port_mapping',
'unit_of_measurement': None,
})
# ---
# name: test_switch_setup[fc_data0][switch.mock_title_port_forward_test_port_mapping-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'friendly_name': 'Mock Title Port forward Test Port Mapping',
'icon': 'mdi:check-network',
}),
'context': <ANY>,
'entity_id': 'switch.mock_title_port_forward_test_port_mapping',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'on',
})
# ---
# name: test_switch_setup[fc_data0][switch.mock_title_port_forward_test_port_mapping_81-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'switch',
'entity_category': <EntityCategory.CONFIG: 'config'>,
'entity_id': 'switch.mock_title_port_forward_test_port_mapping_81',
'has_entity_name': False,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'object_id_base': 'Mock Title Port forward Test Port Mapping 81',
'options': dict({
}),
'original_device_class': None,
'original_icon': 'mdi:check-network',
'original_name': 'Mock Title Port forward Test Port Mapping 81',
'platform': 'fritz',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': '1C:ED:6F:12:34:11-port_forward_test_port_mapping_81',
'unit_of_measurement': None,
})
# ---
# name: test_switch_setup[fc_data0][switch.mock_title_port_forward_test_port_mapping_81-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'friendly_name': 'Mock Title Port forward Test Port Mapping 81',
'icon': 'mdi:check-network',
}),
'context': <ANY>,
'entity_id': 'switch.mock_title_port_forward_test_port_mapping_81',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'on',
})
# ---
# name: test_switch_setup[fc_data0][switch.mock_title_wi_fi_wifi_2_4ghz-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
@@ -148,6 +248,106 @@
'state': 'on',
})
# ---
# name: test_switch_setup[fc_data1][switch.mock_title_port_forward_test_port_mapping-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'switch',
'entity_category': <EntityCategory.CONFIG: 'config'>,
'entity_id': 'switch.mock_title_port_forward_test_port_mapping',
'has_entity_name': False,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'object_id_base': 'Mock Title Port forward Test Port Mapping',
'options': dict({
}),
'original_device_class': None,
'original_icon': 'mdi:check-network',
'original_name': 'Mock Title Port forward Test Port Mapping',
'platform': 'fritz',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': '1C:ED:6F:12:34:11-port_forward_test_port_mapping',
'unit_of_measurement': None,
})
# ---
# name: test_switch_setup[fc_data1][switch.mock_title_port_forward_test_port_mapping-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'friendly_name': 'Mock Title Port forward Test Port Mapping',
'icon': 'mdi:check-network',
}),
'context': <ANY>,
'entity_id': 'switch.mock_title_port_forward_test_port_mapping',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'on',
})
# ---
# name: test_switch_setup[fc_data1][switch.mock_title_port_forward_test_port_mapping_81-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'switch',
'entity_category': <EntityCategory.CONFIG: 'config'>,
'entity_id': 'switch.mock_title_port_forward_test_port_mapping_81',
'has_entity_name': False,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'object_id_base': 'Mock Title Port forward Test Port Mapping 81',
'options': dict({
}),
'original_device_class': None,
'original_icon': 'mdi:check-network',
'original_name': 'Mock Title Port forward Test Port Mapping 81',
'platform': 'fritz',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': '1C:ED:6F:12:34:11-port_forward_test_port_mapping_81',
'unit_of_measurement': None,
})
# ---
# name: test_switch_setup[fc_data1][switch.mock_title_port_forward_test_port_mapping_81-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'friendly_name': 'Mock Title Port forward Test Port Mapping 81',
'icon': 'mdi:check-network',
}),
'context': <ANY>,
'entity_id': 'switch.mock_title_port_forward_test_port_mapping_81',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'on',
})
# ---
# name: test_switch_setup[fc_data1][switch.mock_title_wi_fi_wifi-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
@@ -297,6 +497,106 @@
'state': 'on',
})
# ---
# name: test_switch_setup[fc_data2][switch.mock_title_port_forward_test_port_mapping-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'switch',
'entity_category': <EntityCategory.CONFIG: 'config'>,
'entity_id': 'switch.mock_title_port_forward_test_port_mapping',
'has_entity_name': False,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'object_id_base': 'Mock Title Port forward Test Port Mapping',
'options': dict({
}),
'original_device_class': None,
'original_icon': 'mdi:check-network',
'original_name': 'Mock Title Port forward Test Port Mapping',
'platform': 'fritz',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': '1C:ED:6F:12:34:11-port_forward_test_port_mapping',
'unit_of_measurement': None,
})
# ---
# name: test_switch_setup[fc_data2][switch.mock_title_port_forward_test_port_mapping-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'friendly_name': 'Mock Title Port forward Test Port Mapping',
'icon': 'mdi:check-network',
}),
'context': <ANY>,
'entity_id': 'switch.mock_title_port_forward_test_port_mapping',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'on',
})
# ---
# name: test_switch_setup[fc_data2][switch.mock_title_port_forward_test_port_mapping_81-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'switch',
'entity_category': <EntityCategory.CONFIG: 'config'>,
'entity_id': 'switch.mock_title_port_forward_test_port_mapping_81',
'has_entity_name': False,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'object_id_base': 'Mock Title Port forward Test Port Mapping 81',
'options': dict({
}),
'original_device_class': None,
'original_icon': 'mdi:check-network',
'original_name': 'Mock Title Port forward Test Port Mapping 81',
'platform': 'fritz',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': '1C:ED:6F:12:34:11-port_forward_test_port_mapping_81',
'unit_of_measurement': None,
})
# ---
# name: test_switch_setup[fc_data2][switch.mock_title_port_forward_test_port_mapping_81-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'friendly_name': 'Mock Title Port forward Test Port Mapping 81',
'icon': 'mdi:check-network',
}),
'context': <ANY>,
'entity_id': 'switch.mock_title_port_forward_test_port_mapping_81',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'on',
})
# ---
# name: test_switch_setup[fc_data2][switch.mock_title_wi_fi_wifi_2_4ghz-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
@@ -502,6 +802,106 @@
'state': 'off',
})
# ---
# name: test_switch_setup[fc_data3][switch.mock_title_port_forward_test_port_mapping-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'switch',
'entity_category': <EntityCategory.CONFIG: 'config'>,
'entity_id': 'switch.mock_title_port_forward_test_port_mapping',
'has_entity_name': False,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'object_id_base': 'Mock Title Port forward Test Port Mapping',
'options': dict({
}),
'original_device_class': None,
'original_icon': 'mdi:check-network',
'original_name': 'Mock Title Port forward Test Port Mapping',
'platform': 'fritz',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': '1C:ED:6F:12:34:11-port_forward_test_port_mapping',
'unit_of_measurement': None,
})
# ---
# name: test_switch_setup[fc_data3][switch.mock_title_port_forward_test_port_mapping-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'friendly_name': 'Mock Title Port forward Test Port Mapping',
'icon': 'mdi:check-network',
}),
'context': <ANY>,
'entity_id': 'switch.mock_title_port_forward_test_port_mapping',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'on',
})
# ---
# name: test_switch_setup[fc_data3][switch.mock_title_port_forward_test_port_mapping_81-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'switch',
'entity_category': <EntityCategory.CONFIG: 'config'>,
'entity_id': 'switch.mock_title_port_forward_test_port_mapping_81',
'has_entity_name': False,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'object_id_base': 'Mock Title Port forward Test Port Mapping 81',
'options': dict({
}),
'original_device_class': None,
'original_icon': 'mdi:check-network',
'original_name': 'Mock Title Port forward Test Port Mapping 81',
'platform': 'fritz',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': None,
'unique_id': '1C:ED:6F:12:34:11-port_forward_test_port_mapping_81',
'unit_of_measurement': None,
})
# ---
# name: test_switch_setup[fc_data3][switch.mock_title_port_forward_test_port_mapping_81-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'friendly_name': 'Mock Title Port forward Test Port Mapping 81',
'icon': 'mdi:check-network',
}),
'context': <ANY>,
'entity_id': 'switch.mock_title_port_forward_test_port_mapping_81',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'on',
})
# ---
# name: test_switch_setup[fc_data3][switch.mock_title_wi_fi_mywifi-entry]
EntityRegistryEntrySnapshot({
'aliases': set({

View File

@@ -2,17 +2,38 @@
from __future__ import annotations
from unittest.mock import patch
from copy import deepcopy
from unittest.mock import MagicMock, patch
from fritzconnection.core.exceptions import FritzActionError
from fritzconnection.lib.fritzstatus import DefaultConnectionService
import pytest
from syrupy.assertion import SnapshotAssertion
from homeassistant.components.fritz.const import DOMAIN
from homeassistant.const import Platform
from homeassistant.components.switch import (
DOMAIN as SWITCH_DOMAIN,
SERVICE_TURN_OFF,
SERVICE_TURN_ON,
)
from homeassistant.config_entries import ConfigEntryState
from homeassistant.const import (
ATTR_ENTITY_ID,
STATE_OFF,
STATE_ON,
STATE_UNAVAILABLE,
Platform,
)
from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry as er
from .const import MOCK_CALL_DEFLECTION_DATA, MOCK_FB_SERVICES, MOCK_USER_DATA
from .conftest import FritzConnectionMock
from .const import (
MOCK_CALL_DEFLECTION_DATA,
MOCK_FB_SERVICES,
MOCK_HOST_ATTRIBUTES_DATA,
MOCK_USER_DATA,
)
from tests.common import MockConfigEntry, snapshot_platform
@@ -194,3 +215,205 @@ async def test_switch_setup(
await hass.async_block_till_done(wait_background_tasks=True)
await snapshot_platform(hass, entity_registry, snapshot, entry.entry_id)
async def test_switch_no_device_conn_type(
hass: HomeAssistant,
fc_class_mock,
fh_class_mock,
fs_class_mock,
) -> None:
"""Test Fritz!Tools switches when no device connection type is available."""
entity_id = "switch.mock_title_port_forward_test_port_mapping"
entry = MockConfigEntry(domain=DOMAIN, data=MOCK_USER_DATA)
entry.add_to_hass(hass)
fs_class_mock.get_default_connection_service.return_value = (
DefaultConnectionService("", "", "")
)
assert await hass.config_entries.async_setup(entry.entry_id)
await hass.async_block_till_done(wait_background_tasks=True)
assert hass.states.get(entity_id) is None
async def test_switch_empty_port_entities_list(
hass: HomeAssistant,
fc_class_mock,
fh_class_mock,
fs_class_mock,
) -> None:
"""Test Fritz!Tools switches with empty port entities."""
entity_id = "switch.mock_title_port_forward_test_port_mapping"
entry = MockConfigEntry(domain=DOMAIN, data=MOCK_USER_DATA)
entry.add_to_hass(hass)
with patch(
"homeassistant.components.fritz.coordinator.AvmWrapper.async_get_num_port_mapping",
return_value=None,
):
assert await hass.config_entries.async_setup(entry.entry_id)
await hass.async_block_till_done(wait_background_tasks=True)
assert hass.states.get(entity_id) is None
async def test_switch_no_port_entities_list(
hass: HomeAssistant,
fc_class_mock,
fh_class_mock,
fs_class_mock,
) -> None:
"""Test Fritz!Tools switches with no port entities."""
entity_id = "switch.mock_title_port_forward_test_port_mapping"
entry = MockConfigEntry(domain=DOMAIN, data=MOCK_USER_DATA)
entry.add_to_hass(hass)
with patch(
"homeassistant.components.fritz.coordinator.AvmWrapper.async_get_port_mapping",
return_value=None,
):
assert await hass.config_entries.async_setup(entry.entry_id)
await hass.async_block_till_done(wait_background_tasks=True)
assert hass.states.get(entity_id) is None
async def test_switch_no_profile_entities_list(
hass: HomeAssistant,
fc_class_mock,
fh_class_mock,
) -> None:
"""Test Fritz!Tools switches with no profile entities."""
entity_id = "sswitch.printer_internet_access"
entry = MockConfigEntry(domain=DOMAIN, data=MOCK_USER_DATA)
entry.add_to_hass(hass)
services = deepcopy(MOCK_FB_SERVICES)
services.pop("X_AVM-DE_HostFilter1")
fc_class_mock.return_value = FritzConnectionMock(services)
assert await hass.config_entries.async_setup(entry.entry_id)
await hass.async_block_till_done(wait_background_tasks=True)
assert hass.states.get(entity_id) is None
async def test_switch_no_mesh_wifi_uplink(
hass: HomeAssistant,
fc_class_mock,
fh_class_mock,
) -> None:
"""Test Fritz!Tools switches when no mesh WiFi uplink."""
entry = MockConfigEntry(domain=DOMAIN, data=MOCK_USER_DATA)
entry.add_to_hass(hass)
fh_class_mock.get_mesh_topology.side_effect = FritzActionError(
"No mesh WiFi uplink"
)
assert await hass.config_entries.async_setup(entry.entry_id)
await hass.async_block_till_done(wait_background_tasks=True)
async def test_switch_device_no_wan_access(
hass: HomeAssistant,
fc_class_mock,
fh_class_mock,
) -> None:
"""Test Fritz!Tools switches when device has no WAN access."""
entity_id = "switch.printer_internet_access"
entry = MockConfigEntry(domain=DOMAIN, data=MOCK_USER_DATA)
entry.add_to_hass(hass)
attributes = [
{k: v for k, v in host.items() if k != "X_AVM-DE_WANAccess"}
for host in MOCK_HOST_ATTRIBUTES_DATA
]
fh_class_mock.get_hosts_attributes = MagicMock(return_value=attributes)
assert await hass.config_entries.async_setup(entry.entry_id)
await hass.async_block_till_done(wait_background_tasks=True)
assert (state := hass.states.get(entity_id))
assert state.state == STATE_UNAVAILABLE
@pytest.mark.parametrize(
("entity_id", "wrapper_method", "state_value"),
[
(
"switch.mock_title_port_forward_test_port_mapping",
"async_add_port_mapping",
STATE_OFF,
),
(
"switch.printer_internet_access",
"async_set_allow_wan_access",
STATE_ON,
),
],
)
async def test_switch_turn_on_off(
hass: HomeAssistant,
fc_class_mock,
fh_class_mock,
entity_id: str,
wrapper_method: str,
state_value: str,
) -> None:
"""Test Fritz!Tools switches turn on and turn off."""
entry = MockConfigEntry(domain=DOMAIN, data=MOCK_USER_DATA)
entry.add_to_hass(hass)
fc_class_mock.return_value = FritzConnectionMock(
MOCK_FB_SERVICES | MOCK_CALL_DEFLECTION_DATA
)
assert await hass.config_entries.async_setup(entry.entry_id)
await hass.async_block_till_done(wait_background_tasks=True)
assert entry.state is ConfigEntryState.LOADED
assert (state := hass.states.get(entity_id))
assert state.state == STATE_ON
with patch(
f"homeassistant.components.fritz.coordinator.AvmWrapper.{wrapper_method}",
) as mock_set_action:
await hass.services.async_call(
SWITCH_DOMAIN,
SERVICE_TURN_OFF,
{ATTR_ENTITY_ID: entity_id},
blocking=True,
)
mock_set_action.assert_called_once()
assert (state := hass.states.get(entity_id))
assert state.state == STATE_OFF
with patch(
f"homeassistant.components.fritz.coordinator.AvmWrapper.{wrapper_method}",
) as mock_set_action_2:
await hass.services.async_call(
SWITCH_DOMAIN,
SERVICE_TURN_ON,
{ATTR_ENTITY_ID: entity_id},
blocking=True,
)
mock_set_action_2.assert_called_once()
assert (state := hass.states.get(entity_id))
assert state.state == state_value