Add tests for sonos switch platform (#51142)
* add tests * refactor async_added_to_hass * fix tests and race condition * use async_get * typo
This commit is contained in:
parent
7dff4d6ad7
commit
f7f8672eea
4 changed files with 84 additions and 19 deletions
|
@ -420,8 +420,6 @@ class SonosSpeaker:
|
||||||
|
|
||||||
async_dispatcher_send(self.hass, SONOS_ALARM_UPDATE, self)
|
async_dispatcher_send(self.hass, SONOS_ALARM_UPDATE, self)
|
||||||
|
|
||||||
self.async_write_entity_states()
|
|
||||||
|
|
||||||
async def async_update_battery_info(self, battery_dict: dict[str, Any]) -> None:
|
async def async_update_battery_info(self, battery_dict: dict[str, Any]) -> None:
|
||||||
"""Update battery info using the decoded SonosEvent."""
|
"""Update battery info using the decoded SonosEvent."""
|
||||||
self._last_battery_event = dt_util.utcnow()
|
self._last_battery_event = dt_util.utcnow()
|
||||||
|
|
|
@ -43,11 +43,6 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
|
||||||
entity = SonosAlarmEntity(alarm_id, speaker)
|
entity = SonosAlarmEntity(alarm_id, speaker)
|
||||||
async_add_entities([entity])
|
async_add_entities([entity])
|
||||||
configured_alarms.add(alarm_id)
|
configured_alarms.add(alarm_id)
|
||||||
config_entry.async_on_unload(
|
|
||||||
async_dispatcher_connect(
|
|
||||||
hass, SONOS_ALARM_UPDATE, entity.async_update
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
config_entry.async_on_unload(
|
config_entry.async_on_unload(
|
||||||
async_dispatcher_connect(hass, SONOS_CREATE_ALARM, _async_create_entity)
|
async_dispatcher_connect(hass, SONOS_CREATE_ALARM, _async_create_entity)
|
||||||
|
@ -64,9 +59,20 @@ class SonosAlarmEntity(SonosEntity, SwitchEntity):
|
||||||
self._alarm_id = alarm_id
|
self._alarm_id = alarm_id
|
||||||
self.entity_id = ENTITY_ID_FORMAT.format(f"sonos_alarm_{self.alarm_id}")
|
self.entity_id = ENTITY_ID_FORMAT.format(f"sonos_alarm_{self.alarm_id}")
|
||||||
|
|
||||||
|
async def async_added_to_hass(self) -> None:
|
||||||
|
"""Handle switch setup when added to hass."""
|
||||||
|
await super().async_added_to_hass()
|
||||||
|
self.async_on_remove(
|
||||||
|
async_dispatcher_connect(
|
||||||
|
self.hass,
|
||||||
|
SONOS_ALARM_UPDATE,
|
||||||
|
self.async_update,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def alarm(self):
|
def alarm(self):
|
||||||
"""Return the ID of the alarm."""
|
"""Return the alarm instance."""
|
||||||
return self.hass.data[DATA_SONOS].alarms[self.alarm_id]
|
return self.hass.data[DATA_SONOS].alarms[self.alarm_id]
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
|
|
@ -30,7 +30,7 @@ def config_entry_fixture():
|
||||||
|
|
||||||
@pytest.fixture(name="soco")
|
@pytest.fixture(name="soco")
|
||||||
def soco_fixture(
|
def soco_fixture(
|
||||||
music_library, speaker_info, battery_info, dummy_soco_service, alarmClock
|
music_library, speaker_info, battery_info, dummy_soco_service, alarm_clock
|
||||||
):
|
):
|
||||||
"""Create a mock pysonos SoCo fixture."""
|
"""Create a mock pysonos SoCo fixture."""
|
||||||
with patch("pysonos.SoCo", autospec=True) as mock, patch(
|
with patch("pysonos.SoCo", autospec=True) as mock, patch(
|
||||||
|
@ -46,7 +46,7 @@ def soco_fixture(
|
||||||
mock_soco.zoneGroupTopology = dummy_soco_service
|
mock_soco.zoneGroupTopology = dummy_soco_service
|
||||||
mock_soco.contentDirectory = dummy_soco_service
|
mock_soco.contentDirectory = dummy_soco_service
|
||||||
mock_soco.deviceProperties = dummy_soco_service
|
mock_soco.deviceProperties = dummy_soco_service
|
||||||
mock_soco.alarmClock = alarmClock
|
mock_soco.alarmClock = alarm_clock
|
||||||
mock_soco.mute = False
|
mock_soco.mute = False
|
||||||
mock_soco.night_mode = True
|
mock_soco.night_mode = True
|
||||||
mock_soco.dialog_mode = True
|
mock_soco.dialog_mode = True
|
||||||
|
@ -90,12 +90,28 @@ def music_library_fixture():
|
||||||
return music_library
|
return music_library
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(name="alarmClock")
|
@pytest.fixture(name="alarm_clock")
|
||||||
def alarmClock_fixture():
|
def alarm_clock_fixture():
|
||||||
"""Create alarmClock fixture."""
|
"""Create alarmClock fixture."""
|
||||||
alarmClock = Mock()
|
alarm_clock = Mock()
|
||||||
alarmClock.subscribe = AsyncMock()
|
alarm_clock.subscribe = AsyncMock()
|
||||||
alarmClock.ListAlarms.return_value = {
|
alarm_clock.ListAlarms.return_value = {
|
||||||
|
"CurrentAlarmList": "<Alarms>"
|
||||||
|
'<Alarm ID="14" StartTime="07:00:00" Duration="02:00:00" Recurrence="DAILY" '
|
||||||
|
'Enabled="1" RoomUUID="RINCON_test" ProgramURI="x-rincon-buzzer:0" '
|
||||||
|
'ProgramMetaData="" PlayMode="SHUFFLE_NOREPEAT" Volume="25" '
|
||||||
|
'IncludeLinkedZones="0"/>'
|
||||||
|
"</Alarms> "
|
||||||
|
}
|
||||||
|
return alarm_clock
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(name="alarm_clock_extended")
|
||||||
|
def alarm_clock_fixture_extended():
|
||||||
|
"""Create alarmClock fixture."""
|
||||||
|
alarm_clock = Mock()
|
||||||
|
alarm_clock.subscribe = AsyncMock()
|
||||||
|
alarm_clock.ListAlarms.return_value = {
|
||||||
"CurrentAlarmList": "<Alarms>"
|
"CurrentAlarmList": "<Alarms>"
|
||||||
'<Alarm ID="14" StartTime="07:00:00" Duration="02:00:00" Recurrence="DAILY" '
|
'<Alarm ID="14" StartTime="07:00:00" Duration="02:00:00" Recurrence="DAILY" '
|
||||||
'Enabled="1" RoomUUID="RINCON_test" ProgramURI="x-rincon-buzzer:0" '
|
'Enabled="1" RoomUUID="RINCON_test" ProgramURI="x-rincon-buzzer:0" '
|
||||||
|
@ -107,7 +123,7 @@ def alarmClock_fixture():
|
||||||
'Volume="25" IncludeLinkedZones="0"/>'
|
'Volume="25" IncludeLinkedZones="0"/>'
|
||||||
"</Alarms> "
|
"</Alarms> "
|
||||||
}
|
}
|
||||||
return alarmClock
|
return alarm_clock
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(name="speaker_info")
|
@pytest.fixture(name="speaker_info")
|
||||||
|
@ -141,3 +157,19 @@ def battery_event_fixture(soco):
|
||||||
"more_info": "BattChg:NOT_CHARGING,RawBattPct:100,BattPct:100,BattTmp:25",
|
"more_info": "BattChg:NOT_CHARGING,RawBattPct:100,BattPct:100,BattTmp:25",
|
||||||
}
|
}
|
||||||
return SonosMockEvent(soco, variables)
|
return SonosMockEvent(soco, variables)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(name="alarm_event")
|
||||||
|
def alarm_event_fixture(soco):
|
||||||
|
"""Create alarm_event fixture."""
|
||||||
|
variables = {
|
||||||
|
"time_zone": "ffc40a000503000003000502ffc4",
|
||||||
|
"time_server": "0.sonostime.pool.ntp.org,1.sonostime.pool.ntp.org,2.sonostime.pool.ntp.org,3.sonostime.pool.ntp.org",
|
||||||
|
"time_generation": "20000001",
|
||||||
|
"alarm_list_version": "RINCON_test",
|
||||||
|
"time_format": "INV",
|
||||||
|
"date_format": "INV",
|
||||||
|
"daily_index_refresh_time": None,
|
||||||
|
}
|
||||||
|
|
||||||
|
return SonosMockEvent(soco, variables)
|
||||||
|
|
|
@ -9,17 +9,18 @@ from homeassistant.components.sonos.switch import (
|
||||||
ATTR_VOLUME,
|
ATTR_VOLUME,
|
||||||
)
|
)
|
||||||
from homeassistant.const import ATTR_TIME, STATE_ON
|
from homeassistant.const import ATTR_TIME, STATE_ON
|
||||||
|
from homeassistant.helpers.entity_registry import async_get as async_get_entity_registry
|
||||||
from homeassistant.setup import async_setup_component
|
from homeassistant.setup import async_setup_component
|
||||||
|
|
||||||
|
|
||||||
async def setup_platform(hass, config_entry, config):
|
async def setup_platform(hass, config_entry, config):
|
||||||
"""Set up the media player platform for testing."""
|
"""Set up the switch platform for testing."""
|
||||||
config_entry.add_to_hass(hass)
|
config_entry.add_to_hass(hass)
|
||||||
assert await async_setup_component(hass, DOMAIN, config)
|
assert await async_setup_component(hass, DOMAIN, config)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
|
||||||
async def test_entity_registry(hass, config_entry, config, soco):
|
async def test_entity_registry(hass, config_entry, config):
|
||||||
"""Test sonos device with alarm registered in the device registry."""
|
"""Test sonos device with alarm registered in the device registry."""
|
||||||
await setup_platform(hass, config_entry, config)
|
await setup_platform(hass, config_entry, config)
|
||||||
|
|
||||||
|
@ -29,7 +30,7 @@ async def test_entity_registry(hass, config_entry, config, soco):
|
||||||
assert "switch.sonos_alarm_14" in entity_registry.entities
|
assert "switch.sonos_alarm_14" in entity_registry.entities
|
||||||
|
|
||||||
|
|
||||||
async def test_alarm_attributes(hass, config_entry, config, soco):
|
async def test_alarm_attributes(hass, config_entry, config):
|
||||||
"""Test for correct sonos alarm state."""
|
"""Test for correct sonos alarm state."""
|
||||||
await setup_platform(hass, config_entry, config)
|
await setup_platform(hass, config_entry, config)
|
||||||
|
|
||||||
|
@ -45,3 +46,31 @@ async def test_alarm_attributes(hass, config_entry, config, soco):
|
||||||
assert alarm_state.attributes.get(ATTR_VOLUME) == 0.25
|
assert alarm_state.attributes.get(ATTR_VOLUME) == 0.25
|
||||||
assert alarm_state.attributes.get(ATTR_PLAY_MODE) == "SHUFFLE_NOREPEAT"
|
assert alarm_state.attributes.get(ATTR_PLAY_MODE) == "SHUFFLE_NOREPEAT"
|
||||||
assert not alarm_state.attributes.get(ATTR_INCLUDE_LINKED_ZONES)
|
assert not alarm_state.attributes.get(ATTR_INCLUDE_LINKED_ZONES)
|
||||||
|
|
||||||
|
|
||||||
|
async def test_alarm_create_delete(
|
||||||
|
hass, config_entry, config, soco, alarm_clock, alarm_clock_extended, alarm_event
|
||||||
|
):
|
||||||
|
"""Test for correct creation and deletion of alarms during runtime."""
|
||||||
|
soco.alarmClock = alarm_clock_extended
|
||||||
|
|
||||||
|
await setup_platform(hass, config_entry, config)
|
||||||
|
|
||||||
|
subscription = alarm_clock_extended.subscribe.return_value
|
||||||
|
sub_callback = subscription.callback
|
||||||
|
|
||||||
|
sub_callback(event=alarm_event)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
entity_registry = async_get_entity_registry(hass)
|
||||||
|
|
||||||
|
assert "switch.sonos_alarm_14" in entity_registry.entities
|
||||||
|
assert "switch.sonos_alarm_15" in entity_registry.entities
|
||||||
|
|
||||||
|
alarm_clock_extended.ListAlarms.return_value = alarm_clock.ListAlarms.return_value
|
||||||
|
|
||||||
|
sub_callback(event=alarm_event)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
assert "switch.sonos_alarm_14" in entity_registry.entities
|
||||||
|
assert "switch.sonos_alarm_15" not in entity_registry.entities
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue