diff --git a/homeassistant/components/soundtouch/media_player.py b/homeassistant/components/soundtouch/media_player.py index 72677995a9d..71592e92c17 100644 --- a/homeassistant/components/soundtouch/media_player.py +++ b/homeassistant/components/soundtouch/media_player.py @@ -241,57 +241,46 @@ class SoundTouchDevice(MediaPlayerDevice): def turn_off(self): """Turn off media player.""" self._device.power_off() - self._status = self._device.status() def turn_on(self): """Turn on media player.""" self._device.power_on() - self._status = self._device.status() def volume_up(self): """Volume up the media player.""" self._device.volume_up() - self._volume = self._device.volume() def volume_down(self): """Volume down media player.""" self._device.volume_down() - self._volume = self._device.volume() def set_volume_level(self, volume): """Set volume level, range 0..1.""" self._device.set_volume(int(volume * 100)) - self._volume = self._device.volume() def mute_volume(self, mute): """Send mute command.""" self._device.mute() - self._volume = self._device.volume() def media_play_pause(self): """Simulate play pause media player.""" self._device.play_pause() - self._status = self._device.status() def media_play(self): """Send play command.""" self._device.play() - self._status = self._device.status() def media_pause(self): """Send media pause command to media player.""" self._device.pause() - self._status = self._device.status() def media_next_track(self): """Send next track command.""" self._device.next_track() - self._status = self._device.status() def media_previous_track(self): """Send the previous track command.""" self._device.previous_track() - self._status = self._device.status() @property def media_image_url(self): diff --git a/tests/components/soundtouch/test_media_player.py b/tests/components/soundtouch/test_media_player.py index 8789db1ca1f..b18f9efda97 100644 --- a/tests/components/soundtouch/test_media_player.py +++ b/tests/components/soundtouch/test_media_player.py @@ -1,34 +1,121 @@ """Test the Soundtouch component.""" -import logging -import unittest -from unittest import mock +from unittest.mock import call -from libsoundtouch.device import Config, Preset, SoundTouchDevice as STD, Status, Volume +from asynctest import patch +from libsoundtouch.device import ( + Config, + Preset, + SoundTouchDevice as STD, + Status, + Volume, + ZoneSlave, + ZoneStatus, +) +import pytest +from homeassistant.components.media_player.const import ( + ATTR_MEDIA_CONTENT_ID, + ATTR_MEDIA_CONTENT_TYPE, +) from homeassistant.components.soundtouch import media_player as soundtouch +from homeassistant.components.soundtouch.const import DOMAIN +from homeassistant.components.soundtouch.media_player import DATA_SOUNDTOUCH from homeassistant.const import STATE_OFF, STATE_PAUSED, STATE_PLAYING +from homeassistant.helpers.discovery import async_load_platform +from homeassistant.setup import async_setup_component -from tests.common import get_test_home_assistant +# pylint: disable=super-init-not-called -class MockService: - """Mock Soundtouch service.""" - - def __init__(self, master, slaves): - """Create a new service.""" - self.data = {"master": master, "slaves": slaves} +DEVICE_1_IP = "192.168.0.1" +DEVICE_2_IP = "192.168.0.2" -def _mock_soundtouch_device(*args, **kwargs): - return MockDevice() +def get_config(host=DEVICE_1_IP, port=8090, name="soundtouch"): + """Return a default component.""" + return {"platform": DOMAIN, "host": host, "port": port, "name": name} + + +DEVICE_1_CONFIG = {**get_config(), "name": "soundtouch_1"} +DEVICE_2_CONFIG = {**get_config(), "host": DEVICE_2_IP, "name": "soundtouch_2"} + + +@pytest.fixture(name="one_device") +def one_device_fixture(): + """Mock one master device.""" + device_1 = MockDevice() + device_patch = patch( + "homeassistant.components.soundtouch.media_player.soundtouch_device", + return_value=device_1, + ) + with device_patch as device: + yield device + + +@pytest.fixture(name="two_zones") +def two_zones_fixture(): + """Mock one master and one slave.""" + device_1 = MockDevice( + MockZoneStatus( + is_master=True, + master_id=1, + master_ip=DEVICE_1_IP, + slaves=[MockZoneSlave(DEVICE_2_IP)], + ) + ) + device_2 = MockDevice( + MockZoneStatus( + is_master=False, + master_id=1, + master_ip=DEVICE_1_IP, + slaves=[MockZoneSlave(DEVICE_2_IP)], + ) + ) + devices = {DEVICE_1_IP: device_1, DEVICE_2_IP: device_2} + device_patch = patch( + "homeassistant.components.soundtouch.media_player.soundtouch_device", + side_effect=lambda host, _: devices[host], + ) + with device_patch as device: + yield device + + +@pytest.fixture(name="mocked_status") +def status_fixture(): + """Mock the device status.""" + status_patch = patch( + "libsoundtouch.device.SoundTouchDevice.status", side_effect=MockStatusPlaying + ) + with status_patch as status: + yield status + + +@pytest.fixture(name="mocked_volume") +def volume_fixture(): + """Mock the device volume.""" + volume_patch = patch("libsoundtouch.device.SoundTouchDevice.volume") + with volume_patch as volume: + yield volume + + +async def setup_soundtouch(hass, config): + """Set up soundtouch integration.""" + assert await async_setup_component(hass, "media_player", {"media_player": config}) + await hass.async_block_till_done() + await hass.async_start() class MockDevice(STD): """Mock device.""" - def __init__(self): + def __init__(self, zone_status=None): """Init the class.""" - self._config = MockConfig + self._config = MockConfig() + self._zone_status = zone_status or MockZoneStatus() + + def zone_status(self, refresh=True): + """Zone status mock object.""" + return self._zone_status class MockConfig(Config): @@ -39,6 +126,26 @@ class MockConfig(Config): self._name = "name" +class MockZoneStatus(ZoneStatus): + """Mock zone status.""" + + def __init__(self, is_master=True, master_id=None, master_ip=None, slaves=None): + """Init the class.""" + self._is_master = is_master + self._master_id = master_id + self._master_ip = master_ip + self._slaves = slaves or [] + + +class MockZoneSlave(ZoneSlave): + """Mock zone slave.""" + + def __init__(self, device_ip=None, role=None): + """Init the class.""" + self._ip = device_ip + self._role = role + + def _mocked_presets(*args, **kwargs): """Return a list of mocked presets.""" return [MockPreset("1")] @@ -59,6 +166,7 @@ class MockVolume(Volume): def __init__(self): """Init class.""" self._actual = 12 + self._muted = False class MockVolumeMuted(Volume): @@ -130,697 +238,623 @@ class MockStatusPause(Status): """Init the class.""" self._source = "" self._play_status = "PAUSE_STATE" + self._image = "image.url" + self._artist = None + self._track = None + self._album = None + self._duration = None + self._station_name = None -def default_component(): - """Return a default component.""" - return {"host": "192.168.0.1", "port": 8090, "name": "soundtouch"} - - -class TestSoundtouchMediaPlayer(unittest.TestCase): - """Bose Soundtouch test class.""" - - def setUp(self): # pylint: disable=invalid-name - """Set up things to be run when tests are started.""" - self.hass = get_test_home_assistant() - logging.disable(logging.CRITICAL) - - def tearDown(self): # pylint: disable=invalid-name - """Stop everything that was started.""" - logging.disable(logging.NOTSET) - self.hass.stop() - - @mock.patch( - "homeassistant.components.soundtouch.media_player.soundtouch_device", - side_effect=None, +async def test_ensure_setup_config(mocked_status, mocked_volume, hass, one_device): + """Test setup OK with custom config.""" + await setup_soundtouch( + hass, get_config(host="192.168.1.44", port=8888, name="custom_sound") ) - def test_ensure_setup_config(self, mocked_soundtouch_device): - """Test setup OK with custom config.""" - soundtouch.setup_platform(self.hass, default_component(), mock.MagicMock()) - all_devices = self.hass.data[soundtouch.DATA_SOUNDTOUCH] - assert len(all_devices) == 1 - assert all_devices[0].name == "soundtouch" - assert all_devices[0].config["port"] == 8090 - assert mocked_soundtouch_device.call_count == 1 - @mock.patch( - "homeassistant.components.soundtouch.media_player.soundtouch_device", - side_effect=None, + assert one_device.call_count == 1 + assert one_device.call_args == call("192.168.1.44", 8888) + assert len(hass.states.async_all()) == 1 + state = hass.states.get("media_player.custom_sound") + assert state.name == "custom_sound" + + +async def test_ensure_setup_discovery(mocked_status, mocked_volume, hass, one_device): + """Test setup with discovery.""" + new_device = { + "port": "8090", + "host": "192.168.1.1", + "properties": {}, + "hostname": "hostname.local", + } + await async_load_platform( + hass, "media_player", DOMAIN, new_device, {"media_player": {}} ) - def test_ensure_setup_discovery(self, mocked_soundtouch_device): - """Test setup with discovery.""" - new_device = { - "port": "8090", - "host": "192.168.1.1", - "properties": {}, - "hostname": "hostname.local", - } - soundtouch.setup_platform(self.hass, None, mock.MagicMock(), new_device) - all_devices = self.hass.data[soundtouch.DATA_SOUNDTOUCH] - assert len(all_devices) == 1 - assert all_devices[0].config["port"] == 8090 - assert all_devices[0].config["host"] == "192.168.1.1" - assert mocked_soundtouch_device.call_count == 1 + await hass.async_block_till_done() - @mock.patch( - "homeassistant.components.soundtouch.media_player.soundtouch_device", - side_effect=None, + assert one_device.call_count == 1 + assert one_device.call_args == call("192.168.1.1", 8090) + assert len(hass.states.async_all()) == 1 + + +async def test_ensure_setup_discovery_no_duplicate( + mocked_status, mocked_volume, hass, one_device +): + """Test setup OK if device already exists.""" + await setup_soundtouch(hass, DEVICE_1_CONFIG) + + assert one_device.call_count == 1 + assert len(hass.states.async_all()) == 1 + + new_device = { + "port": "8090", + "host": "192.168.1.1", + "properties": {}, + "hostname": "hostname.local", + } + await async_load_platform( + hass, "media_player", DOMAIN, new_device, {"media_player": DEVICE_1_CONFIG} ) - def test_ensure_setup_discovery_no_duplicate(self, mocked_soundtouch_device): - """Test setup OK if device already exists.""" - soundtouch.setup_platform(self.hass, default_component(), mock.MagicMock()) - assert len(self.hass.data[soundtouch.DATA_SOUNDTOUCH]) == 1 - new_device = { - "port": "8090", - "host": "192.168.1.1", - "properties": {}, - "hostname": "hostname.local", - } - soundtouch.setup_platform( - self.hass, None, mock.MagicMock(), new_device # New device - ) - assert len(self.hass.data[soundtouch.DATA_SOUNDTOUCH]) == 2 - existing_device = { - "port": "8090", - "host": "192.168.0.1", - "properties": {}, - "hostname": "hostname.local", - } - soundtouch.setup_platform( - self.hass, None, mock.MagicMock(), existing_device # Existing device - ) - assert mocked_soundtouch_device.call_count == 2 - assert len(self.hass.data[soundtouch.DATA_SOUNDTOUCH]) == 2 + await hass.async_block_till_done() + assert one_device.call_count == 2 + assert len(hass.states.async_all()) == 2 - @mock.patch("libsoundtouch.device.SoundTouchDevice.volume") - @mock.patch("libsoundtouch.device.SoundTouchDevice.status") - @mock.patch( - "homeassistant.components.soundtouch.media_player.soundtouch_device", - side_effect=_mock_soundtouch_device, + existing_device = { + "port": "8090", + "host": "192.168.0.1", + "properties": {}, + "hostname": "hostname.local", + } + await async_load_platform( + hass, "media_player", DOMAIN, existing_device, {"media_player": DEVICE_1_CONFIG} ) - def test_update(self, mocked_soundtouch_device, mocked_status, mocked_volume): - """Test update device state.""" - soundtouch.setup_platform(self.hass, default_component(), mock.MagicMock()) - assert mocked_soundtouch_device.call_count == 1 - assert mocked_status.call_count == 1 - assert mocked_volume.call_count == 1 - self.hass.data[soundtouch.DATA_SOUNDTOUCH][0].update() - assert mocked_status.call_count == 2 - assert mocked_volume.call_count == 2 + await hass.async_block_till_done() + assert one_device.call_count == 2 + assert len(hass.states.async_all()) == 2 - @mock.patch("libsoundtouch.device.SoundTouchDevice.volume") - @mock.patch( - "libsoundtouch.device.SoundTouchDevice.status", side_effect=MockStatusPlaying + +async def test_playing_media(mocked_status, mocked_volume, hass, one_device): + """Test playing media info.""" + await setup_soundtouch(hass, DEVICE_1_CONFIG) + + assert one_device.call_count == 1 + assert mocked_status.call_count == 1 + assert mocked_volume.call_count == 1 + + entity_1_state = hass.states.get("media_player.soundtouch_1") + assert entity_1_state.state == STATE_PLAYING + assert entity_1_state.attributes["media_title"] == "artist - track" + assert entity_1_state.attributes["media_track"] == "track" + assert entity_1_state.attributes["media_artist"] == "artist" + assert entity_1_state.attributes["media_album_name"] == "album" + assert entity_1_state.attributes["media_duration"] == 1 + + +async def test_playing_unknown_media(mocked_status, mocked_volume, hass, one_device): + """Test playing media info.""" + mocked_status.side_effect = MockStatusUnknown + await setup_soundtouch(hass, DEVICE_1_CONFIG) + + assert one_device.call_count == 1 + assert mocked_status.call_count == 1 + assert mocked_volume.call_count == 1 + + entity_1_state = hass.states.get("media_player.soundtouch_1") + assert entity_1_state.state == STATE_PLAYING + + +async def test_playing_radio(mocked_status, mocked_volume, hass, one_device): + """Test playing radio info.""" + mocked_status.side_effect = MockStatusPlayingRadio + await setup_soundtouch(hass, DEVICE_1_CONFIG) + + assert one_device.call_count == 1 + assert mocked_status.call_count == 1 + assert mocked_volume.call_count == 1 + + entity_1_state = hass.states.get("media_player.soundtouch_1") + assert entity_1_state.state == STATE_PLAYING + assert entity_1_state.attributes["media_title"] == "station" + + +async def test_get_volume_level(mocked_status, mocked_volume, hass, one_device): + """Test volume level.""" + mocked_volume.side_effect = MockVolume + await setup_soundtouch(hass, DEVICE_1_CONFIG) + + assert one_device.call_count == 1 + assert mocked_status.call_count == 1 + assert mocked_volume.call_count == 1 + + entity_1_state = hass.states.get("media_player.soundtouch_1") + assert entity_1_state.attributes["volume_level"] == 0.12 + + +async def test_get_state_off(mocked_status, mocked_volume, hass, one_device): + """Test state device is off.""" + mocked_status.side_effect = MockStatusStandby + await setup_soundtouch(hass, DEVICE_1_CONFIG) + + assert one_device.call_count == 1 + assert mocked_status.call_count == 1 + assert mocked_volume.call_count == 1 + + entity_1_state = hass.states.get("media_player.soundtouch_1") + assert entity_1_state.state == STATE_OFF + + +async def test_get_state_pause(mocked_status, mocked_volume, hass, one_device): + """Test state device is paused.""" + mocked_status.side_effect = MockStatusPause + await setup_soundtouch(hass, DEVICE_1_CONFIG) + + assert one_device.call_count == 1 + assert mocked_status.call_count == 1 + assert mocked_volume.call_count == 1 + + entity_1_state = hass.states.get("media_player.soundtouch_1") + assert entity_1_state.state == STATE_PAUSED + + +async def test_is_muted(mocked_status, mocked_volume, hass, one_device): + """Test device volume is muted.""" + mocked_volume.side_effect = MockVolumeMuted + await setup_soundtouch(hass, DEVICE_1_CONFIG) + + assert one_device.call_count == 1 + assert mocked_status.call_count == 1 + assert mocked_volume.call_count == 1 + + entity_1_state = hass.states.get("media_player.soundtouch_1") + assert entity_1_state.attributes["is_volume_muted"] + + +async def test_media_commands(mocked_status, mocked_volume, hass, one_device): + """Test supported media commands.""" + await setup_soundtouch(hass, DEVICE_1_CONFIG) + + assert one_device.call_count == 1 + assert mocked_status.call_count == 1 + assert mocked_volume.call_count == 1 + + entity_1_state = hass.states.get("media_player.soundtouch_1") + assert entity_1_state.attributes["supported_features"] == 18365 + + +@patch("libsoundtouch.device.SoundTouchDevice.power_off") +async def test_should_turn_off( + mocked_power_off, mocked_status, mocked_volume, hass, one_device +): + """Test device is turned off.""" + await setup_soundtouch(hass, DEVICE_1_CONFIG) + + assert one_device.call_count == 1 + assert mocked_status.call_count == 1 + assert mocked_volume.call_count == 1 + + await hass.services.async_call( + "media_player", "turn_off", {"entity_id": "media_player.soundtouch_1"}, True, ) - @mock.patch( - "homeassistant.components.soundtouch.media_player.soundtouch_device", - side_effect=_mock_soundtouch_device, + assert mocked_status.call_count == 2 + assert mocked_power_off.call_count == 1 + + +@patch("libsoundtouch.device.SoundTouchDevice.power_on") +async def test_should_turn_on( + mocked_power_on, mocked_status, mocked_volume, hass, one_device +): + """Test device is turned on.""" + mocked_status.side_effect = MockStatusStandby + await setup_soundtouch(hass, DEVICE_1_CONFIG) + + assert one_device.call_count == 1 + assert mocked_status.call_count == 1 + assert mocked_volume.call_count == 1 + + await hass.services.async_call( + "media_player", "turn_on", {"entity_id": "media_player.soundtouch_1"}, True, ) - def test_playing_media( - self, mocked_soundtouch_device, mocked_status, mocked_volume - ): - """Test playing media info.""" - soundtouch.setup_platform(self.hass, default_component(), mock.MagicMock()) - assert mocked_soundtouch_device.call_count == 1 - assert mocked_status.call_count == 1 - assert mocked_volume.call_count == 1 - all_devices = self.hass.data[soundtouch.DATA_SOUNDTOUCH] - assert all_devices[0].state == STATE_PLAYING - assert all_devices[0].media_image_url == "image.url" - assert all_devices[0].media_title == "artist - track" - assert all_devices[0].media_track == "track" - assert all_devices[0].media_artist == "artist" - assert all_devices[0].media_album_name == "album" - assert all_devices[0].media_duration == 1 + assert mocked_status.call_count == 2 + assert mocked_power_on.call_count == 1 - @mock.patch("libsoundtouch.device.SoundTouchDevice.volume") - @mock.patch( - "libsoundtouch.device.SoundTouchDevice.status", side_effect=MockStatusUnknown + +@patch("libsoundtouch.device.SoundTouchDevice.volume_up") +async def test_volume_up( + mocked_volume_up, mocked_status, mocked_volume, hass, one_device +): + """Test volume up.""" + await setup_soundtouch(hass, DEVICE_1_CONFIG) + + assert one_device.call_count == 1 + assert mocked_status.call_count == 1 + assert mocked_volume.call_count == 1 + + await hass.services.async_call( + "media_player", "volume_up", {"entity_id": "media_player.soundtouch_1"}, True, ) - @mock.patch( - "homeassistant.components.soundtouch.media_player.soundtouch_device", - side_effect=_mock_soundtouch_device, + assert mocked_volume.call_count == 2 + assert mocked_volume_up.call_count == 1 + + +@patch("libsoundtouch.device.SoundTouchDevice.volume_down") +async def test_volume_down( + mocked_volume_down, mocked_status, mocked_volume, hass, one_device +): + """Test volume down.""" + await setup_soundtouch(hass, DEVICE_1_CONFIG) + + assert one_device.call_count == 1 + assert mocked_status.call_count == 1 + assert mocked_volume.call_count == 1 + + await hass.services.async_call( + "media_player", "volume_down", {"entity_id": "media_player.soundtouch_1"}, True, ) - def test_playing_unknown_media( - self, mocked_soundtouch_device, mocked_status, mocked_volume - ): - """Test playing media info.""" - soundtouch.setup_platform(self.hass, default_component(), mock.MagicMock()) - assert mocked_soundtouch_device.call_count == 1 - assert mocked_status.call_count == 1 - assert mocked_volume.call_count == 1 - all_devices = self.hass.data[soundtouch.DATA_SOUNDTOUCH] - assert all_devices[0].media_title is None + assert mocked_volume.call_count == 2 + assert mocked_volume_down.call_count == 1 - @mock.patch("libsoundtouch.device.SoundTouchDevice.volume") - @mock.patch( - "libsoundtouch.device.SoundTouchDevice.status", - side_effect=MockStatusPlayingRadio, + +@patch("libsoundtouch.device.SoundTouchDevice.set_volume") +async def test_set_volume_level( + mocked_set_volume, mocked_status, mocked_volume, hass, one_device +): + """Test set volume level.""" + await setup_soundtouch(hass, DEVICE_1_CONFIG) + + assert one_device.call_count == 1 + assert mocked_status.call_count == 1 + assert mocked_volume.call_count == 1 + + await hass.services.async_call( + "media_player", + "volume_set", + {"entity_id": "media_player.soundtouch_1", "volume_level": 0.17}, + True, ) - @mock.patch( - "homeassistant.components.soundtouch.media_player.soundtouch_device", - side_effect=_mock_soundtouch_device, + assert mocked_volume.call_count == 2 + mocked_set_volume.assert_called_with(17) + + +@patch("libsoundtouch.device.SoundTouchDevice.mute") +async def test_mute(mocked_mute, mocked_status, mocked_volume, hass, one_device): + """Test mute volume.""" + await setup_soundtouch(hass, DEVICE_1_CONFIG) + + assert one_device.call_count == 1 + assert mocked_status.call_count == 1 + assert mocked_volume.call_count == 1 + + await hass.services.async_call( + "media_player", + "volume_mute", + {"entity_id": "media_player.soundtouch_1", "is_volume_muted": True}, + True, ) - def test_playing_radio( - self, mocked_soundtouch_device, mocked_status, mocked_volume - ): - """Test playing radio info.""" - soundtouch.setup_platform(self.hass, default_component(), mock.MagicMock()) - assert mocked_soundtouch_device.call_count == 1 - assert mocked_status.call_count == 1 - assert mocked_volume.call_count == 1 - all_devices = self.hass.data[soundtouch.DATA_SOUNDTOUCH] - assert all_devices[0].state == STATE_PLAYING - assert all_devices[0].media_image_url == "image.url" - assert all_devices[0].media_title == "station" - assert all_devices[0].media_track is None - assert all_devices[0].media_artist is None - assert all_devices[0].media_album_name is None - assert all_devices[0].media_duration is None + assert mocked_volume.call_count == 2 + assert mocked_mute.call_count == 1 - @mock.patch("libsoundtouch.device.SoundTouchDevice.volume", side_effect=MockVolume) - @mock.patch("libsoundtouch.device.SoundTouchDevice.status") - @mock.patch( - "homeassistant.components.soundtouch.media_player.soundtouch_device", - side_effect=_mock_soundtouch_device, + +@patch("libsoundtouch.device.SoundTouchDevice.play") +async def test_play(mocked_play, mocked_status, mocked_volume, hass, one_device): + """Test play command.""" + await setup_soundtouch(hass, DEVICE_1_CONFIG) + + assert one_device.call_count == 1 + assert mocked_status.call_count == 1 + assert mocked_volume.call_count == 1 + + await hass.services.async_call( + "media_player", "media_play", {"entity_id": "media_player.soundtouch_1"}, True, ) - def test_get_volume_level( - self, mocked_soundtouch_device, mocked_status, mocked_volume - ): - """Test volume level.""" - soundtouch.setup_platform(self.hass, default_component(), mock.MagicMock()) - assert mocked_soundtouch_device.call_count == 1 - assert mocked_status.call_count == 1 - assert mocked_volume.call_count == 1 - all_devices = self.hass.data[soundtouch.DATA_SOUNDTOUCH] - assert all_devices[0].volume_level == 0.12 + assert mocked_status.call_count == 2 + assert mocked_play.call_count == 1 - @mock.patch("libsoundtouch.device.SoundTouchDevice.volume") - @mock.patch( - "libsoundtouch.device.SoundTouchDevice.status", side_effect=MockStatusStandby + +@patch("libsoundtouch.device.SoundTouchDevice.pause") +async def test_pause(mocked_pause, mocked_status, mocked_volume, hass, one_device): + """Test pause command.""" + await setup_soundtouch(hass, DEVICE_1_CONFIG) + + assert one_device.call_count == 1 + assert mocked_status.call_count == 1 + assert mocked_volume.call_count == 1 + + await hass.services.async_call( + "media_player", "media_pause", {"entity_id": "media_player.soundtouch_1"}, True, ) - @mock.patch( - "homeassistant.components.soundtouch.media_player.soundtouch_device", - side_effect=_mock_soundtouch_device, + assert mocked_status.call_count == 2 + assert mocked_pause.call_count == 1 + + +@patch("libsoundtouch.device.SoundTouchDevice.play_pause") +async def test_play_pause( + mocked_play_pause, mocked_status, mocked_volume, hass, one_device +): + """Test play/pause.""" + await setup_soundtouch(hass, DEVICE_1_CONFIG) + + assert one_device.call_count == 1 + assert mocked_status.call_count == 1 + assert mocked_volume.call_count == 1 + + await hass.services.async_call( + "media_player", + "media_play_pause", + {"entity_id": "media_player.soundtouch_1"}, + True, ) - def test_get_state_off( - self, mocked_soundtouch_device, mocked_status, mocked_volume - ): - """Test state device is off.""" - soundtouch.setup_platform(self.hass, default_component(), mock.MagicMock()) - assert mocked_soundtouch_device.call_count == 1 - assert mocked_status.call_count == 1 - assert mocked_volume.call_count == 1 - all_devices = self.hass.data[soundtouch.DATA_SOUNDTOUCH] - assert all_devices[0].state == STATE_OFF + assert mocked_status.call_count == 2 + assert mocked_play_pause.call_count == 1 - @mock.patch("libsoundtouch.device.SoundTouchDevice.volume") - @mock.patch( - "libsoundtouch.device.SoundTouchDevice.status", side_effect=MockStatusPause + +@patch("libsoundtouch.device.SoundTouchDevice.previous_track") +@patch("libsoundtouch.device.SoundTouchDevice.next_track") +async def test_next_previous_track( + mocked_next_track, + mocked_previous_track, + mocked_status, + mocked_volume, + hass, + one_device, +): + """Test next/previous track.""" + await setup_soundtouch(hass, DEVICE_1_CONFIG) + + assert one_device.call_count == 1 + assert mocked_status.call_count == 1 + assert mocked_volume.call_count == 1 + + await hass.services.async_call( + "media_player", + "media_next_track", + {"entity_id": "media_player.soundtouch_1"}, + True, ) - @mock.patch( - "homeassistant.components.soundtouch.media_player.soundtouch_device", - side_effect=_mock_soundtouch_device, + assert mocked_status.call_count == 2 + assert mocked_next_track.call_count == 1 + + await hass.services.async_call( + "media_player", + "media_previous_track", + {"entity_id": "media_player.soundtouch_1"}, + True, ) - def test_get_state_pause( - self, mocked_soundtouch_device, mocked_status, mocked_volume - ): - """Test state device is paused.""" - soundtouch.setup_platform(self.hass, default_component(), mock.MagicMock()) - assert mocked_soundtouch_device.call_count == 1 - assert mocked_status.call_count == 1 - assert mocked_volume.call_count == 1 - all_devices = self.hass.data[soundtouch.DATA_SOUNDTOUCH] - assert all_devices[0].state == STATE_PAUSED + assert mocked_status.call_count == 3 + assert mocked_previous_track.call_count == 1 - @mock.patch( - "libsoundtouch.device.SoundTouchDevice.volume", side_effect=MockVolumeMuted + +@patch("libsoundtouch.device.SoundTouchDevice.select_preset") +@patch("libsoundtouch.device.SoundTouchDevice.presets", side_effect=_mocked_presets) +async def test_play_media( + mocked_presets, mocked_select_preset, mocked_status, mocked_volume, hass, one_device +): + """Test play preset 1.""" + await setup_soundtouch(hass, DEVICE_1_CONFIG) + + assert one_device.call_count == 1 + assert mocked_status.call_count == 1 + assert mocked_volume.call_count == 1 + + await hass.services.async_call( + "media_player", + "play_media", + { + "entity_id": "media_player.soundtouch_1", + ATTR_MEDIA_CONTENT_TYPE: "PLAYLIST", + ATTR_MEDIA_CONTENT_ID: 1, + }, + True, ) - @mock.patch("libsoundtouch.device.SoundTouchDevice.status") - @mock.patch( - "homeassistant.components.soundtouch.media_player.soundtouch_device", - side_effect=_mock_soundtouch_device, + assert mocked_presets.call_count == 1 + assert mocked_select_preset.call_count == 1 + + await hass.services.async_call( + "media_player", + "play_media", + { + "entity_id": "media_player.soundtouch_1", + ATTR_MEDIA_CONTENT_TYPE: "PLAYLIST", + ATTR_MEDIA_CONTENT_ID: 2, + }, + True, ) - def test_is_muted(self, mocked_soundtouch_device, mocked_status, mocked_volume): - """Test device volume is muted.""" - soundtouch.setup_platform(self.hass, default_component(), mock.MagicMock()) - assert mocked_soundtouch_device.call_count == 1 - assert mocked_status.call_count == 1 - assert mocked_volume.call_count == 1 - all_devices = self.hass.data[soundtouch.DATA_SOUNDTOUCH] - assert all_devices[0].is_volume_muted is True + assert mocked_presets.call_count == 2 + assert mocked_select_preset.call_count == 1 - @mock.patch("homeassistant.components.soundtouch.media_player.soundtouch_device") - def test_media_commands(self, mocked_soundtouch_device): - """Test supported media commands.""" - soundtouch.setup_platform(self.hass, default_component(), mock.MagicMock()) - assert mocked_soundtouch_device.call_count == 1 - all_devices = self.hass.data[soundtouch.DATA_SOUNDTOUCH] - assert all_devices[0].supported_features == 18365 - @mock.patch("libsoundtouch.device.SoundTouchDevice.power_off") - @mock.patch("libsoundtouch.device.SoundTouchDevice.volume") - @mock.patch("libsoundtouch.device.SoundTouchDevice.status") - @mock.patch( - "homeassistant.components.soundtouch.media_player.soundtouch_device", - side_effect=_mock_soundtouch_device, +@patch("libsoundtouch.device.SoundTouchDevice.play_url") +async def test_play_media_url( + mocked_play_url, mocked_status, mocked_volume, hass, one_device +): + """Test play preset 1.""" + await setup_soundtouch(hass, DEVICE_1_CONFIG) + + assert one_device.call_count == 1 + assert mocked_status.call_count == 1 + assert mocked_volume.call_count == 1 + + await hass.services.async_call( + "media_player", + "play_media", + { + "entity_id": "media_player.soundtouch_1", + ATTR_MEDIA_CONTENT_TYPE: "MUSIC", + ATTR_MEDIA_CONTENT_ID: "http://fqdn/file.mp3", + }, + True, ) - def test_should_turn_off( - self, mocked_soundtouch_device, mocked_status, mocked_volume, mocked_power_off - ): - """Test device is turned off.""" - soundtouch.setup_platform(self.hass, default_component(), mock.MagicMock()) - all_devices = self.hass.data[soundtouch.DATA_SOUNDTOUCH] - all_devices[0].turn_off() - assert mocked_soundtouch_device.call_count == 1 - assert mocked_status.call_count == 2 - assert mocked_volume.call_count == 1 - assert mocked_power_off.call_count == 1 + mocked_play_url.assert_called_with("http://fqdn/file.mp3") - @mock.patch("libsoundtouch.device.SoundTouchDevice.power_on") - @mock.patch("libsoundtouch.device.SoundTouchDevice.volume") - @mock.patch("libsoundtouch.device.SoundTouchDevice.status") - @mock.patch( - "homeassistant.components.soundtouch.media_player.soundtouch_device", - side_effect=_mock_soundtouch_device, + +@patch("libsoundtouch.device.SoundTouchDevice.create_zone") +async def test_play_everywhere( + mocked_create_zone, mocked_status, mocked_volume, hass, two_zones +): + """Test play everywhere.""" + mocked_device = two_zones + await setup_soundtouch(hass, [DEVICE_1_CONFIG, DEVICE_2_CONFIG]) + + assert mocked_device.call_count == 2 + assert mocked_status.call_count == 2 + assert mocked_volume.call_count == 2 + + # one master, one slave => create zone + await hass.services.async_call( + soundtouch.DOMAIN, + soundtouch.SERVICE_PLAY_EVERYWHERE, + {"master": "media_player.soundtouch_1"}, + True, ) - def test_should_turn_on( - self, mocked_soundtouch_device, mocked_status, mocked_volume, mocked_power_on - ): - """Test device is turned on.""" - soundtouch.setup_platform(self.hass, default_component(), mock.MagicMock()) - all_devices = self.hass.data[soundtouch.DATA_SOUNDTOUCH] - all_devices[0].turn_on() - assert mocked_soundtouch_device.call_count == 1 - assert mocked_status.call_count == 2 - assert mocked_volume.call_count == 1 - assert mocked_power_on.call_count == 1 + assert mocked_create_zone.call_count == 1 - @mock.patch("libsoundtouch.device.SoundTouchDevice.volume_up") - @mock.patch("libsoundtouch.device.SoundTouchDevice.volume") - @mock.patch("libsoundtouch.device.SoundTouchDevice.status") - @mock.patch( - "homeassistant.components.soundtouch.media_player.soundtouch_device", - side_effect=_mock_soundtouch_device, + # unknown master, create zone must not be called + await hass.services.async_call( + soundtouch.DOMAIN, + soundtouch.SERVICE_PLAY_EVERYWHERE, + {"master": "media_player.entity_X"}, + True, ) - def test_volume_up( - self, mocked_soundtouch_device, mocked_status, mocked_volume, mocked_volume_up - ): - """Test volume up.""" - soundtouch.setup_platform(self.hass, default_component(), mock.MagicMock()) - all_devices = self.hass.data[soundtouch.DATA_SOUNDTOUCH] - all_devices[0].volume_up() - assert mocked_soundtouch_device.call_count == 1 - assert mocked_status.call_count == 1 - assert mocked_volume.call_count == 2 - assert mocked_volume_up.call_count == 1 + assert mocked_create_zone.call_count == 1 - @mock.patch("libsoundtouch.device.SoundTouchDevice.volume_down") - @mock.patch("libsoundtouch.device.SoundTouchDevice.volume") - @mock.patch("libsoundtouch.device.SoundTouchDevice.status") - @mock.patch( - "homeassistant.components.soundtouch.media_player.soundtouch_device", - side_effect=_mock_soundtouch_device, + # no slaves, create zone must not be called + for entity in list(hass.data[DATA_SOUNDTOUCH]): + if entity.entity_id == "media_player.soundtouch_1": + continue + hass.data[DATA_SOUNDTOUCH].remove(entity) + await entity.async_remove() + await hass.services.async_call( + soundtouch.DOMAIN, + soundtouch.SERVICE_PLAY_EVERYWHERE, + {"master": "media_player.soundtouch_1"}, + True, ) - def test_volume_down( - self, mocked_soundtouch_device, mocked_status, mocked_volume, mocked_volume_down - ): - """Test volume down.""" - soundtouch.setup_platform(self.hass, default_component(), mock.MagicMock()) - all_devices = self.hass.data[soundtouch.DATA_SOUNDTOUCH] - all_devices[0].volume_down() - assert mocked_soundtouch_device.call_count == 1 - assert mocked_status.call_count == 1 - assert mocked_volume.call_count == 2 - assert mocked_volume_down.call_count == 1 + assert mocked_create_zone.call_count == 1 - @mock.patch("libsoundtouch.device.SoundTouchDevice.set_volume") - @mock.patch("libsoundtouch.device.SoundTouchDevice.volume") - @mock.patch("libsoundtouch.device.SoundTouchDevice.status") - @mock.patch( - "homeassistant.components.soundtouch.media_player.soundtouch_device", - side_effect=_mock_soundtouch_device, + +@patch("libsoundtouch.device.SoundTouchDevice.create_zone") +async def test_create_zone( + mocked_create_zone, mocked_status, mocked_volume, hass, two_zones +): + """Test creating a zone.""" + mocked_device = two_zones + await setup_soundtouch(hass, [DEVICE_1_CONFIG, DEVICE_2_CONFIG]) + + assert mocked_device.call_count == 2 + assert mocked_status.call_count == 2 + assert mocked_volume.call_count == 2 + + # one master, one slave => create zone + await hass.services.async_call( + soundtouch.DOMAIN, + soundtouch.SERVICE_CREATE_ZONE, + { + "master": "media_player.soundtouch_1", + "slaves": ["media_player.soundtouch_2"], + }, + True, ) - def test_set_volume_level( - self, mocked_soundtouch_device, mocked_status, mocked_volume, mocked_set_volume - ): - """Test set volume level.""" - soundtouch.setup_platform(self.hass, default_component(), mock.MagicMock()) - all_devices = self.hass.data[soundtouch.DATA_SOUNDTOUCH] - all_devices[0].set_volume_level(0.17) - assert mocked_soundtouch_device.call_count == 1 - assert mocked_status.call_count == 1 - assert mocked_volume.call_count == 2 - mocked_set_volume.assert_called_with(17) + assert mocked_create_zone.call_count == 1 - @mock.patch("libsoundtouch.device.SoundTouchDevice.mute") - @mock.patch("libsoundtouch.device.SoundTouchDevice.volume") - @mock.patch("libsoundtouch.device.SoundTouchDevice.status") - @mock.patch( - "homeassistant.components.soundtouch.media_player.soundtouch_device", - side_effect=_mock_soundtouch_device, + # unknown master, create zone must not be called + await hass.services.async_call( + soundtouch.DOMAIN, + soundtouch.SERVICE_CREATE_ZONE, + {"master": "media_player.entity_X", "slaves": ["media_player.soundtouch_2"]}, + True, ) - def test_mute( - self, mocked_soundtouch_device, mocked_status, mocked_volume, mocked_mute - ): - """Test mute volume.""" - soundtouch.setup_platform(self.hass, default_component(), mock.MagicMock()) - all_devices = self.hass.data[soundtouch.DATA_SOUNDTOUCH] - all_devices[0].mute_volume(None) - assert mocked_soundtouch_device.call_count == 1 - assert mocked_status.call_count == 1 - assert mocked_volume.call_count == 2 - assert mocked_mute.call_count == 1 + assert mocked_create_zone.call_count == 1 - @mock.patch("libsoundtouch.device.SoundTouchDevice.play") - @mock.patch("libsoundtouch.device.SoundTouchDevice.volume") - @mock.patch("libsoundtouch.device.SoundTouchDevice.status") - @mock.patch( - "homeassistant.components.soundtouch.media_player.soundtouch_device", - side_effect=_mock_soundtouch_device, + # no slaves, create zone must not be called + await hass.services.async_call( + soundtouch.DOMAIN, + soundtouch.SERVICE_CREATE_ZONE, + {"master": "media_player.soundtouch_1", "slaves": []}, + True, ) - def test_play( - self, mocked_soundtouch_device, mocked_status, mocked_volume, mocked_play - ): - """Test play command.""" - soundtouch.setup_platform(self.hass, default_component(), mock.MagicMock()) - all_devices = self.hass.data[soundtouch.DATA_SOUNDTOUCH] - all_devices[0].media_play() - assert mocked_soundtouch_device.call_count == 1 - assert mocked_status.call_count == 2 - assert mocked_volume.call_count == 1 - assert mocked_play.call_count == 1 + assert mocked_create_zone.call_count == 1 - @mock.patch("libsoundtouch.device.SoundTouchDevice.pause") - @mock.patch("libsoundtouch.device.SoundTouchDevice.volume") - @mock.patch("libsoundtouch.device.SoundTouchDevice.status") - @mock.patch( - "homeassistant.components.soundtouch.media_player.soundtouch_device", - side_effect=_mock_soundtouch_device, + +@patch("libsoundtouch.device.SoundTouchDevice.remove_zone_slave") +async def test_remove_zone_slave( + mocked_remove_zone_slave, mocked_status, mocked_volume, hass, two_zones +): + """Test adding a slave to an existing zone.""" + mocked_device = two_zones + await setup_soundtouch(hass, [DEVICE_1_CONFIG, DEVICE_2_CONFIG]) + + assert mocked_device.call_count == 2 + assert mocked_status.call_count == 2 + assert mocked_volume.call_count == 2 + + # remove one slave + await hass.services.async_call( + soundtouch.DOMAIN, + soundtouch.SERVICE_REMOVE_ZONE_SLAVE, + { + "master": "media_player.soundtouch_1", + "slaves": ["media_player.soundtouch_2"], + }, + True, ) - def test_pause( - self, mocked_soundtouch_device, mocked_status, mocked_volume, mocked_pause - ): - """Test pause command.""" - soundtouch.setup_platform(self.hass, default_component(), mock.MagicMock()) - all_devices = self.hass.data[soundtouch.DATA_SOUNDTOUCH] - all_devices[0].media_pause() - assert mocked_soundtouch_device.call_count == 1 - assert mocked_status.call_count == 2 - assert mocked_volume.call_count == 1 - assert mocked_pause.call_count == 1 + assert mocked_remove_zone_slave.call_count == 1 - @mock.patch("libsoundtouch.device.SoundTouchDevice.play_pause") - @mock.patch("libsoundtouch.device.SoundTouchDevice.volume") - @mock.patch("libsoundtouch.device.SoundTouchDevice.status") - @mock.patch( - "homeassistant.components.soundtouch.media_player.soundtouch_device", - side_effect=_mock_soundtouch_device, + # unknown master. add zone slave is not called + await hass.services.async_call( + soundtouch.DOMAIN, + soundtouch.SERVICE_REMOVE_ZONE_SLAVE, + {"master": "media_player.entity_X", "slaves": ["media_player.soundtouch_2"]}, + True, ) - def test_play_pause_play( - self, mocked_soundtouch_device, mocked_status, mocked_volume, mocked_play_pause - ): - """Test play/pause.""" - soundtouch.setup_platform(self.hass, default_component(), mock.MagicMock()) - all_devices = self.hass.data[soundtouch.DATA_SOUNDTOUCH] - all_devices[0].media_play_pause() - assert mocked_soundtouch_device.call_count == 1 - assert mocked_status.call_count == 2 - assert mocked_volume.call_count == 1 - assert mocked_play_pause.call_count == 1 + assert mocked_remove_zone_slave.call_count == 1 - @mock.patch("libsoundtouch.device.SoundTouchDevice.previous_track") - @mock.patch("libsoundtouch.device.SoundTouchDevice.next_track") - @mock.patch("libsoundtouch.device.SoundTouchDevice.volume") - @mock.patch("libsoundtouch.device.SoundTouchDevice.status") - @mock.patch( - "homeassistant.components.soundtouch.media_player.soundtouch_device", - side_effect=_mock_soundtouch_device, + # no slave to add, add zone slave is not called + await hass.services.async_call( + soundtouch.DOMAIN, + soundtouch.SERVICE_REMOVE_ZONE_SLAVE, + {"master": "media_player.soundtouch_1", "slaves": []}, + True, ) - def test_next_previous_track( - self, - mocked_soundtouch_device, - mocked_status, - mocked_volume, - mocked_next_track, - mocked_previous_track, - ): - """Test next/previous track.""" - soundtouch.setup_platform(self.hass, default_component(), mock.MagicMock()) - all_devices = self.hass.data[soundtouch.DATA_SOUNDTOUCH] - assert mocked_soundtouch_device.call_count == 1 - assert mocked_status.call_count == 1 - assert mocked_volume.call_count == 1 - all_devices[0].media_next_track() - assert mocked_status.call_count == 2 - assert mocked_next_track.call_count == 1 - all_devices[0].media_previous_track() - assert mocked_status.call_count == 3 - assert mocked_previous_track.call_count == 1 + assert mocked_remove_zone_slave.call_count == 1 - @mock.patch("libsoundtouch.device.SoundTouchDevice.select_preset") - @mock.patch( - "libsoundtouch.device.SoundTouchDevice.presets", side_effect=_mocked_presets + +@patch("libsoundtouch.device.SoundTouchDevice.add_zone_slave") +async def test_add_zone_slave( + mocked_add_zone_slave, mocked_status, mocked_volume, hass, two_zones, +): + """Test removing a slave from a zone.""" + mocked_device = two_zones + await setup_soundtouch(hass, [DEVICE_1_CONFIG, DEVICE_2_CONFIG]) + + assert mocked_device.call_count == 2 + assert mocked_status.call_count == 2 + assert mocked_volume.call_count == 2 + + # add one slave + await hass.services.async_call( + soundtouch.DOMAIN, + soundtouch.SERVICE_ADD_ZONE_SLAVE, + { + "master": "media_player.soundtouch_1", + "slaves": ["media_player.soundtouch_2"], + }, + True, ) - @mock.patch("libsoundtouch.device.SoundTouchDevice.volume") - @mock.patch("libsoundtouch.device.SoundTouchDevice.status") - @mock.patch( - "homeassistant.components.soundtouch.media_player.soundtouch_device", - side_effect=_mock_soundtouch_device, + assert mocked_add_zone_slave.call_count == 1 + + # unknown master, add zone slave is not called + await hass.services.async_call( + soundtouch.DOMAIN, + soundtouch.SERVICE_ADD_ZONE_SLAVE, + {"master": "media_player.entity_X", "slaves": ["media_player.soundtouch_2"]}, + True, ) - def test_play_media( - self, - mocked_soundtouch_device, - mocked_status, - mocked_volume, - mocked_presets, - mocked_select_preset, - ): - """Test play preset 1.""" - soundtouch.setup_platform(self.hass, default_component(), mock.MagicMock()) - all_devices = self.hass.data[soundtouch.DATA_SOUNDTOUCH] - assert mocked_soundtouch_device.call_count == 1 - assert mocked_status.call_count == 1 - assert mocked_volume.call_count == 1 - all_devices[0].play_media("PLAYLIST", 1) - assert mocked_presets.call_count == 1 - assert mocked_select_preset.call_count == 1 - all_devices[0].play_media("PLAYLIST", 2) - assert mocked_presets.call_count == 2 - assert mocked_select_preset.call_count == 1 + assert mocked_add_zone_slave.call_count == 1 - @mock.patch("libsoundtouch.device.SoundTouchDevice.play_url") - @mock.patch("libsoundtouch.device.SoundTouchDevice.volume") - @mock.patch("libsoundtouch.device.SoundTouchDevice.status") - @mock.patch( - "homeassistant.components.soundtouch.media_player.soundtouch_device", - side_effect=_mock_soundtouch_device, + # no slave to add, add zone slave is not called + await hass.services.async_call( + soundtouch.DOMAIN, + soundtouch.SERVICE_ADD_ZONE_SLAVE, + {"master": "media_player.soundtouch_1", "slaves": ["media_player.entity_X"]}, + True, ) - def test_play_media_url( - self, mocked_soundtouch_device, mocked_status, mocked_volume, mocked_play_url - ): - """Test play preset 1.""" - soundtouch.setup_platform(self.hass, default_component(), mock.MagicMock()) - all_devices = self.hass.data[soundtouch.DATA_SOUNDTOUCH] - assert mocked_soundtouch_device.call_count == 1 - assert mocked_status.call_count == 1 - assert mocked_volume.call_count == 1 - all_devices[0].play_media("MUSIC", "http://fqdn/file.mp3") - mocked_play_url.assert_called_with("http://fqdn/file.mp3") - - @mock.patch("libsoundtouch.device.SoundTouchDevice.create_zone") - @mock.patch("libsoundtouch.device.SoundTouchDevice.volume") - @mock.patch("libsoundtouch.device.SoundTouchDevice.status") - @mock.patch( - "homeassistant.components.soundtouch.media_player.soundtouch_device", - side_effect=_mock_soundtouch_device, - ) - def test_play_everywhere( - self, mocked_soundtouch_device, mocked_status, mocked_volume, mocked_create_zone - ): - """Test play everywhere.""" - soundtouch.setup_platform(self.hass, default_component(), mock.MagicMock()) - soundtouch.setup_platform(self.hass, default_component(), mock.MagicMock()) - all_devices = self.hass.data[soundtouch.DATA_SOUNDTOUCH] - all_devices[0].entity_id = "media_player.entity_1" - all_devices[1].entity_id = "media_player.entity_2" - assert mocked_soundtouch_device.call_count == 2 - assert mocked_status.call_count == 2 - assert mocked_volume.call_count == 2 - - # one master, one slave => create zone - self.hass.services.call( - soundtouch.DOMAIN, - soundtouch.SERVICE_PLAY_EVERYWHERE, - {"master": "media_player.entity_1"}, - True, - ) - assert mocked_create_zone.call_count == 1 - - # unknown master. create zone is must not be called - self.hass.services.call( - soundtouch.DOMAIN, - soundtouch.SERVICE_PLAY_EVERYWHERE, - {"master": "media_player.entity_X"}, - True, - ) - assert mocked_create_zone.call_count == 1 - - # no slaves, create zone must not be called - all_devices.pop(1) - self.hass.services.call( - soundtouch.DOMAIN, - soundtouch.SERVICE_PLAY_EVERYWHERE, - {"master": "media_player.entity_1"}, - True, - ) - assert mocked_create_zone.call_count == 1 - - @mock.patch("libsoundtouch.device.SoundTouchDevice.create_zone") - @mock.patch("libsoundtouch.device.SoundTouchDevice.volume") - @mock.patch("libsoundtouch.device.SoundTouchDevice.status") - @mock.patch( - "homeassistant.components.soundtouch.media_player.soundtouch_device", - side_effect=_mock_soundtouch_device, - ) - def test_create_zone( - self, mocked_soundtouch_device, mocked_status, mocked_volume, mocked_create_zone - ): - """Test creating a zone.""" - soundtouch.setup_platform(self.hass, default_component(), mock.MagicMock()) - soundtouch.setup_platform(self.hass, default_component(), mock.MagicMock()) - all_devices = self.hass.data[soundtouch.DATA_SOUNDTOUCH] - all_devices[0].entity_id = "media_player.entity_1" - all_devices[1].entity_id = "media_player.entity_2" - assert mocked_soundtouch_device.call_count == 2 - assert mocked_status.call_count == 2 - assert mocked_volume.call_count == 2 - - # one master, one slave => create zone - self.hass.services.call( - soundtouch.DOMAIN, - soundtouch.SERVICE_CREATE_ZONE, - {"master": "media_player.entity_1", "slaves": ["media_player.entity_2"]}, - True, - ) - assert mocked_create_zone.call_count == 1 - - # unknown master. create zone is must not be called - self.hass.services.call( - soundtouch.DOMAIN, - soundtouch.SERVICE_CREATE_ZONE, - {"master": "media_player.entity_X", "slaves": ["media_player.entity_2"]}, - True, - ) - assert mocked_create_zone.call_count == 1 - - # no slaves, create zone must not be called - self.hass.services.call( - soundtouch.DOMAIN, - soundtouch.SERVICE_CREATE_ZONE, - {"master": "media_player.entity_X", "slaves": []}, - True, - ) - assert mocked_create_zone.call_count == 1 - - @mock.patch("libsoundtouch.device.SoundTouchDevice.remove_zone_slave") - @mock.patch("libsoundtouch.device.SoundTouchDevice.volume") - @mock.patch("libsoundtouch.device.SoundTouchDevice.status") - @mock.patch( - "homeassistant.components.soundtouch.media_player.soundtouch_device", - side_effect=_mock_soundtouch_device, - ) - def test_remove_zone_slave( - self, - mocked_soundtouch_device, - mocked_status, - mocked_volume, - mocked_remove_zone_slave, - ): - """Test adding a slave to an existing zone.""" - soundtouch.setup_platform(self.hass, default_component(), mock.MagicMock()) - soundtouch.setup_platform(self.hass, default_component(), mock.MagicMock()) - all_devices = self.hass.data[soundtouch.DATA_SOUNDTOUCH] - all_devices[0].entity_id = "media_player.entity_1" - all_devices[1].entity_id = "media_player.entity_2" - assert mocked_soundtouch_device.call_count == 2 - assert mocked_status.call_count == 2 - assert mocked_volume.call_count == 2 - - # remove one slave - self.hass.services.call( - soundtouch.DOMAIN, - soundtouch.SERVICE_REMOVE_ZONE_SLAVE, - {"master": "media_player.entity_1", "slaves": ["media_player.entity_2"]}, - True, - ) - assert mocked_remove_zone_slave.call_count == 1 - - # unknown master. add zone slave is not called - self.hass.services.call( - soundtouch.DOMAIN, - soundtouch.SERVICE_REMOVE_ZONE_SLAVE, - {"master": "media_player.entity_X", "slaves": ["media_player.entity_2"]}, - True, - ) - assert mocked_remove_zone_slave.call_count == 1 - - # no slave to add, add zone slave is not called - self.hass.services.call( - soundtouch.DOMAIN, - soundtouch.SERVICE_REMOVE_ZONE_SLAVE, - {"master": "media_player.entity_1", "slaves": []}, - True, - ) - assert mocked_remove_zone_slave.call_count == 1 - - @mock.patch("libsoundtouch.device.SoundTouchDevice.add_zone_slave") - @mock.patch("libsoundtouch.device.SoundTouchDevice.volume") - @mock.patch("libsoundtouch.device.SoundTouchDevice.status") - @mock.patch( - "homeassistant.components.soundtouch.media_player.soundtouch_device", - side_effect=_mock_soundtouch_device, - ) - def test_add_zone_slave( - self, - mocked_soundtouch_device, - mocked_status, - mocked_volume, - mocked_add_zone_slave, - ): - """Test removing a slave from a zone.""" - soundtouch.setup_platform(self.hass, default_component(), mock.MagicMock()) - soundtouch.setup_platform(self.hass, default_component(), mock.MagicMock()) - all_devices = self.hass.data[soundtouch.DATA_SOUNDTOUCH] - all_devices[0].entity_id = "media_player.entity_1" - all_devices[1].entity_id = "media_player.entity_2" - assert mocked_soundtouch_device.call_count == 2 - assert mocked_status.call_count == 2 - assert mocked_volume.call_count == 2 - - # add one slave - self.hass.services.call( - soundtouch.DOMAIN, - soundtouch.SERVICE_ADD_ZONE_SLAVE, - {"master": "media_player.entity_1", "slaves": ["media_player.entity_2"]}, - True, - ) - assert mocked_add_zone_slave.call_count == 1 - - # unknown master. add zone slave is not called - self.hass.services.call( - soundtouch.DOMAIN, - soundtouch.SERVICE_ADD_ZONE_SLAVE, - {"master": "media_player.entity_X", "slaves": ["media_player.entity_2"]}, - True, - ) - assert mocked_add_zone_slave.call_count == 1 - - # no slave to add, add zone slave is not called - self.hass.services.call( - soundtouch.DOMAIN, - soundtouch.SERVICE_ADD_ZONE_SLAVE, - {"master": "media_player.entity_1", "slaves": ["media_player.entity_X"]}, - True, - ) - assert mocked_add_zone_slave.call_count == 1 + assert mocked_add_zone_slave.call_count == 1