From 372ed2db910cd6c73c6681fcc34a69645819cf0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Gabriel?= Date: Thu, 25 Feb 2021 09:40:01 -0300 Subject: [PATCH] Add remote control platform to Panasonic Viera (#42450) * Adding remote platform * Update homeassistant/components/panasonic_viera/remote.py Simplify entity creation Co-authored-by: Martin Hjelmare * Use Pytest fixture * Use Pytest fixtures and assert service calls * Adding conftest.py and organizing tests * Reorganizing tests Co-authored-by: Martin Hjelmare --- .../components/panasonic_viera/__init__.py | 4 +- .../components/panasonic_viera/remote.py | 90 ++++++ tests/components/panasonic_viera/conftest.py | 104 +++++++ .../panasonic_viera/test_config_flow.py | 257 ++++-------------- tests/components/panasonic_viera/test_init.py | 196 ++++++------- .../components/panasonic_viera/test_remote.py | 58 ++++ 6 files changed, 386 insertions(+), 323 deletions(-) create mode 100644 homeassistant/components/panasonic_viera/remote.py create mode 100644 tests/components/panasonic_viera/conftest.py create mode 100644 tests/components/panasonic_viera/test_remote.py diff --git a/homeassistant/components/panasonic_viera/__init__.py b/homeassistant/components/panasonic_viera/__init__.py index 3305c935890..9902d39a56c 100644 --- a/homeassistant/components/panasonic_viera/__init__.py +++ b/homeassistant/components/panasonic_viera/__init__.py @@ -8,6 +8,7 @@ from panasonic_viera import EncryptionRequired, Keys, RemoteControl, SOAPError import voluptuous as vol from homeassistant.components.media_player.const import DOMAIN as MEDIA_PLAYER_DOMAIN +from homeassistant.components.remote import DOMAIN as REMOTE_DOMAIN from homeassistant.config_entries import SOURCE_IMPORT from homeassistant.const import CONF_HOST, CONF_NAME, CONF_PORT, STATE_OFF, STATE_ON import homeassistant.helpers.config_validation as cv @@ -46,7 +47,7 @@ CONFIG_SCHEMA = vol.Schema( extra=vol.ALLOW_EXTRA, ) -PLATFORMS = [MEDIA_PLAYER_DOMAIN] +PLATFORMS = [MEDIA_PLAYER_DOMAIN, REMOTE_DOMAIN] async def async_setup(hass, config): @@ -219,6 +220,7 @@ class Remote: """Turn off the TV.""" if self.state != STATE_OFF: await self.async_send_key(Keys.power) + self.state = STATE_OFF await self.async_update() async def async_set_mute(self, enable): diff --git a/homeassistant/components/panasonic_viera/remote.py b/homeassistant/components/panasonic_viera/remote.py new file mode 100644 index 00000000000..8f3fab80215 --- /dev/null +++ b/homeassistant/components/panasonic_viera/remote.py @@ -0,0 +1,90 @@ +"""Remote control support for Panasonic Viera TV.""" +import logging + +from homeassistant.components.remote import RemoteEntity +from homeassistant.const import CONF_NAME, STATE_ON + +from .const import ( + ATTR_DEVICE_INFO, + ATTR_MANUFACTURER, + ATTR_MODEL_NUMBER, + ATTR_REMOTE, + ATTR_UDN, + DEFAULT_MANUFACTURER, + DEFAULT_MODEL_NUMBER, + DOMAIN, +) + +_LOGGER = logging.getLogger(__name__) + + +async def async_setup_entry(hass, config_entry, async_add_entities): + """Set up Panasonic Viera TV Remote from a config entry.""" + + config = config_entry.data + + remote = hass.data[DOMAIN][config_entry.entry_id][ATTR_REMOTE] + name = config[CONF_NAME] + device_info = config[ATTR_DEVICE_INFO] + + async_add_entities([PanasonicVieraRemoteEntity(remote, name, device_info)]) + + +class PanasonicVieraRemoteEntity(RemoteEntity): + """Representation of a Panasonic Viera TV Remote.""" + + def __init__(self, remote, name, device_info): + """Initialize the entity.""" + # Save a reference to the imported class + self._remote = remote + self._name = name + self._device_info = device_info + + @property + def unique_id(self): + """Return the unique ID of the device.""" + if self._device_info is None: + return None + return self._device_info[ATTR_UDN] + + @property + def device_info(self): + """Return device specific attributes.""" + if self._device_info is None: + return None + return { + "name": self._name, + "identifiers": {(DOMAIN, self._device_info[ATTR_UDN])}, + "manufacturer": self._device_info.get( + ATTR_MANUFACTURER, DEFAULT_MANUFACTURER + ), + "model": self._device_info.get(ATTR_MODEL_NUMBER, DEFAULT_MODEL_NUMBER), + } + + @property + def name(self): + """Return the name of the device.""" + return self._name + + @property + def available(self): + """Return True if the device is available.""" + return self._remote.available + + @property + def is_on(self): + """Return true if device is on.""" + return self._remote.state == STATE_ON + + async def async_turn_on(self, **kwargs): + """Turn the device on.""" + await self._remote.async_turn_on(context=self._context) + + async def async_turn_off(self, **kwargs): + """Turn the device off.""" + await self._remote.async_turn_off() + + async def async_send_command(self, command, **kwargs): + """Send a command to one device.""" + for cmd in command: + await self._remote.async_send_key(cmd) diff --git a/tests/components/panasonic_viera/conftest.py b/tests/components/panasonic_viera/conftest.py new file mode 100644 index 00000000000..d1444f01477 --- /dev/null +++ b/tests/components/panasonic_viera/conftest.py @@ -0,0 +1,104 @@ +"""Test helpers for Panasonic Viera.""" + +from unittest.mock import Mock, patch + +from panasonic_viera import TV_TYPE_ENCRYPTED, TV_TYPE_NONENCRYPTED +import pytest + +from homeassistant.components.panasonic_viera.const import ( + ATTR_FRIENDLY_NAME, + ATTR_MANUFACTURER, + ATTR_MODEL_NUMBER, + ATTR_UDN, + CONF_APP_ID, + CONF_ENCRYPTION_KEY, + CONF_ON_ACTION, + DEFAULT_MANUFACTURER, + DEFAULT_MODEL_NUMBER, + DEFAULT_NAME, + DEFAULT_PORT, +) +from homeassistant.const import CONF_HOST, CONF_NAME, CONF_PORT + +MOCK_BASIC_DATA = { + CONF_HOST: "0.0.0.0", + CONF_NAME: DEFAULT_NAME, +} + +MOCK_CONFIG_DATA = { + **MOCK_BASIC_DATA, + CONF_PORT: DEFAULT_PORT, + CONF_ON_ACTION: None, +} + +MOCK_ENCRYPTION_DATA = { + CONF_APP_ID: "mock-app-id", + CONF_ENCRYPTION_KEY: "mock-encryption-key", +} + +MOCK_DEVICE_INFO = { + ATTR_FRIENDLY_NAME: DEFAULT_NAME, + ATTR_MANUFACTURER: DEFAULT_MANUFACTURER, + ATTR_MODEL_NUMBER: DEFAULT_MODEL_NUMBER, + ATTR_UDN: "mock-unique-id", +} + + +def get_mock_remote( + request_error=None, + authorize_error=None, + encrypted=False, + app_id=None, + encryption_key=None, + device_info=MOCK_DEVICE_INFO, +): + """Return a mock remote.""" + mock_remote = Mock() + + mock_remote.type = TV_TYPE_ENCRYPTED if encrypted else TV_TYPE_NONENCRYPTED + mock_remote.app_id = app_id + mock_remote.enc_key = encryption_key + + def request_pin_code(name=None): + if request_error is not None: + raise request_error + + mock_remote.request_pin_code = request_pin_code + + def authorize_pin_code(pincode): + if pincode == "1234": + return + + if authorize_error is not None: + raise authorize_error + + mock_remote.authorize_pin_code = authorize_pin_code + + def get_device_info(): + return device_info + + mock_remote.get_device_info = get_device_info + + def send_key(key): + return + + mock_remote.send_key = Mock(send_key) + + def get_volume(key): + return 100 + + mock_remote.get_volume = Mock(get_volume) + + return mock_remote + + +@pytest.fixture(name="mock_remote") +def mock_remote_fixture(): + """Patch the library remote.""" + mock_remote = get_mock_remote() + + with patch( + "homeassistant.components.panasonic_viera.RemoteControl", + return_value=mock_remote, + ): + yield mock_remote diff --git a/tests/components/panasonic_viera/test_config_flow.py b/tests/components/panasonic_viera/test_config_flow.py index e099862604a..dd7f629c29b 100644 --- a/tests/components/panasonic_viera/test_config_flow.py +++ b/tests/components/panasonic_viera/test_config_flow.py @@ -1,90 +1,28 @@ """Test the Panasonic Viera config flow.""" -from unittest.mock import Mock, patch +from unittest.mock import patch -from panasonic_viera import TV_TYPE_ENCRYPTED, TV_TYPE_NONENCRYPTED, SOAPError -import pytest +from panasonic_viera import SOAPError from homeassistant import config_entries from homeassistant.components.panasonic_viera.const import ( ATTR_DEVICE_INFO, - ATTR_FRIENDLY_NAME, - ATTR_MANUFACTURER, - ATTR_MODEL_NUMBER, - ATTR_UDN, - CONF_APP_ID, - CONF_ENCRYPTION_KEY, - CONF_ON_ACTION, - DEFAULT_MANUFACTURER, - DEFAULT_MODEL_NUMBER, DEFAULT_NAME, - DEFAULT_PORT, DOMAIN, ERROR_INVALID_PIN_CODE, ) -from homeassistant.const import CONF_HOST, CONF_NAME, CONF_PIN, CONF_PORT +from homeassistant.const import CONF_PIN + +from .conftest import ( + MOCK_BASIC_DATA, + MOCK_CONFIG_DATA, + MOCK_DEVICE_INFO, + MOCK_ENCRYPTION_DATA, + get_mock_remote, +) from tests.common import MockConfigEntry -@pytest.fixture(name="panasonic_viera_setup", autouse=True) -def panasonic_viera_setup_fixture(): - """Mock panasonic_viera setup.""" - with patch( - "homeassistant.components.panasonic_viera.async_setup", return_value=True - ), patch( - "homeassistant.components.panasonic_viera.async_setup_entry", - return_value=True, - ): - yield - - -def get_mock_remote( - host="1.2.3.4", - request_error=None, - authorize_error=None, - encrypted=False, - app_id=None, - encryption_key=None, - name=DEFAULT_NAME, - manufacturer=DEFAULT_MANUFACTURER, - model_number=DEFAULT_MODEL_NUMBER, - unique_id="mock-unique-id", -): - """Return a mock remote.""" - mock_remote = Mock() - - mock_remote.type = TV_TYPE_ENCRYPTED if encrypted else TV_TYPE_NONENCRYPTED - mock_remote.app_id = app_id - mock_remote.enc_key = encryption_key - - def request_pin_code(name=None): - if request_error is not None: - raise request_error - - mock_remote.request_pin_code = request_pin_code - - def authorize_pin_code(pincode): - if pincode == "1234": - return - - if authorize_error is not None: - raise authorize_error - - mock_remote.authorize_pin_code = authorize_pin_code - - def get_device_info(): - return { - ATTR_FRIENDLY_NAME: name, - ATTR_MANUFACTURER: manufacturer, - ATTR_MODEL_NUMBER: model_number, - ATTR_UDN: unique_id, - } - - mock_remote.get_device_info = get_device_info - - return mock_remote - - async def test_flow_non_encrypted(hass): """Test flow without encryption.""" @@ -103,23 +41,12 @@ async def test_flow_non_encrypted(hass): ): result = await hass.config_entries.flow.async_configure( result["flow_id"], - {CONF_HOST: "1.2.3.4", CONF_NAME: DEFAULT_NAME}, + MOCK_BASIC_DATA, ) assert result["type"] == "create_entry" assert result["title"] == DEFAULT_NAME - assert result["data"] == { - CONF_HOST: "1.2.3.4", - CONF_NAME: DEFAULT_NAME, - CONF_PORT: DEFAULT_PORT, - CONF_ON_ACTION: None, - ATTR_DEVICE_INFO: { - ATTR_FRIENDLY_NAME: DEFAULT_NAME, - ATTR_MANUFACTURER: DEFAULT_MANUFACTURER, - ATTR_MODEL_NUMBER: DEFAULT_MODEL_NUMBER, - ATTR_UDN: "mock-unique-id", - }, - } + assert result["data"] == {**MOCK_CONFIG_DATA, ATTR_DEVICE_INFO: MOCK_DEVICE_INFO} async def test_flow_not_connected_error(hass): @@ -138,7 +65,7 @@ async def test_flow_not_connected_error(hass): ): result = await hass.config_entries.flow.async_configure( result["flow_id"], - {CONF_HOST: "1.2.3.4", CONF_NAME: DEFAULT_NAME}, + MOCK_BASIC_DATA, ) assert result["type"] == "form" @@ -162,7 +89,7 @@ async def test_flow_unknown_abort(hass): ): result = await hass.config_entries.flow.async_configure( result["flow_id"], - {CONF_HOST: "1.2.3.4", CONF_NAME: DEFAULT_NAME}, + MOCK_BASIC_DATA, ) assert result["type"] == "abort" @@ -187,7 +114,7 @@ async def test_flow_encrypted_not_connected_pin_code_request(hass): ): result = await hass.config_entries.flow.async_configure( result["flow_id"], - {CONF_HOST: "1.2.3.4", CONF_NAME: DEFAULT_NAME}, + MOCK_BASIC_DATA, ) assert result["type"] == "abort" @@ -212,7 +139,7 @@ async def test_flow_encrypted_unknown_pin_code_request(hass): ): result = await hass.config_entries.flow.async_configure( result["flow_id"], - {CONF_HOST: "1.2.3.4", CONF_NAME: DEFAULT_NAME}, + MOCK_BASIC_DATA, ) assert result["type"] == "abort" @@ -231,8 +158,8 @@ async def test_flow_encrypted_valid_pin_code(hass): mock_remote = get_mock_remote( encrypted=True, - app_id="test-app-id", - encryption_key="test-encryption-key", + app_id="mock-app-id", + encryption_key="mock-encryption-key", ) with patch( @@ -241,7 +168,7 @@ async def test_flow_encrypted_valid_pin_code(hass): ): result = await hass.config_entries.flow.async_configure( result["flow_id"], - {CONF_HOST: "1.2.3.4", CONF_NAME: DEFAULT_NAME}, + MOCK_BASIC_DATA, ) assert result["type"] == "form" @@ -255,18 +182,9 @@ async def test_flow_encrypted_valid_pin_code(hass): assert result["type"] == "create_entry" assert result["title"] == DEFAULT_NAME assert result["data"] == { - CONF_HOST: "1.2.3.4", - CONF_NAME: DEFAULT_NAME, - CONF_PORT: DEFAULT_PORT, - CONF_ON_ACTION: None, - CONF_APP_ID: "test-app-id", - CONF_ENCRYPTION_KEY: "test-encryption-key", - ATTR_DEVICE_INFO: { - ATTR_FRIENDLY_NAME: DEFAULT_NAME, - ATTR_MANUFACTURER: DEFAULT_MANUFACTURER, - ATTR_MODEL_NUMBER: DEFAULT_MODEL_NUMBER, - ATTR_UDN: "mock-unique-id", - }, + **MOCK_CONFIG_DATA, + **MOCK_ENCRYPTION_DATA, + ATTR_DEVICE_INFO: MOCK_DEVICE_INFO, } @@ -288,7 +206,7 @@ async def test_flow_encrypted_invalid_pin_code_error(hass): ): result = await hass.config_entries.flow.async_configure( result["flow_id"], - {CONF_HOST: "1.2.3.4", CONF_NAME: DEFAULT_NAME}, + MOCK_BASIC_DATA, ) assert result["type"] == "form" @@ -326,7 +244,7 @@ async def test_flow_encrypted_not_connected_abort(hass): ): result = await hass.config_entries.flow.async_configure( result["flow_id"], - {CONF_HOST: "1.2.3.4", CONF_NAME: DEFAULT_NAME}, + MOCK_BASIC_DATA, ) assert result["type"] == "form" @@ -359,7 +277,7 @@ async def test_flow_encrypted_unknown_abort(hass): ): result = await hass.config_entries.flow.async_configure( result["flow_id"], - {CONF_HOST: "1.2.3.4", CONF_NAME: DEFAULT_NAME}, + MOCK_BASIC_DATA, ) assert result["type"] == "form" @@ -379,14 +297,14 @@ async def test_flow_non_encrypted_already_configured_abort(hass): MockConfigEntry( domain=DOMAIN, - unique_id="1.2.3.4", - data={CONF_HOST: "1.2.3.4", CONF_NAME: DEFAULT_NAME, CONF_PORT: DEFAULT_PORT}, + unique_id="0.0.0.0", + data=MOCK_CONFIG_DATA, ).add_to_hass(hass) result = await hass.config_entries.flow.async_init( DOMAIN, context={"source": config_entries.SOURCE_USER}, - data={CONF_HOST: "1.2.3.4", CONF_NAME: DEFAULT_NAME}, + data=MOCK_BASIC_DATA, ) assert result["type"] == "abort" @@ -398,20 +316,14 @@ async def test_flow_encrypted_already_configured_abort(hass): MockConfigEntry( domain=DOMAIN, - unique_id="1.2.3.4", - data={ - CONF_HOST: "1.2.3.4", - CONF_NAME: DEFAULT_NAME, - CONF_PORT: DEFAULT_PORT, - CONF_APP_ID: "test-app-id", - CONF_ENCRYPTION_KEY: "test-encryption-key", - }, + unique_id="0.0.0.0", + data={**MOCK_CONFIG_DATA, **MOCK_ENCRYPTION_DATA}, ).add_to_hass(hass) result = await hass.config_entries.flow.async_init( DOMAIN, context={"source": config_entries.SOURCE_USER}, - data={CONF_HOST: "1.2.3.4", CONF_NAME: DEFAULT_NAME}, + data=MOCK_BASIC_DATA, ) assert result["type"] == "abort" @@ -430,28 +342,12 @@ async def test_imported_flow_non_encrypted(hass): result = await hass.config_entries.flow.async_init( DOMAIN, context={"source": config_entries.SOURCE_IMPORT}, - data={ - CONF_HOST: "1.2.3.4", - CONF_NAME: DEFAULT_NAME, - CONF_PORT: DEFAULT_PORT, - CONF_ON_ACTION: "test-on-action", - }, + data=MOCK_CONFIG_DATA, ) assert result["type"] == "create_entry" assert result["title"] == DEFAULT_NAME - assert result["data"] == { - CONF_HOST: "1.2.3.4", - CONF_NAME: DEFAULT_NAME, - CONF_PORT: DEFAULT_PORT, - CONF_ON_ACTION: "test-on-action", - ATTR_DEVICE_INFO: { - ATTR_FRIENDLY_NAME: DEFAULT_NAME, - ATTR_MANUFACTURER: DEFAULT_MANUFACTURER, - ATTR_MODEL_NUMBER: DEFAULT_MODEL_NUMBER, - ATTR_UDN: "mock-unique-id", - }, - } + assert result["data"] == {**MOCK_CONFIG_DATA, ATTR_DEVICE_INFO: MOCK_DEVICE_INFO} async def test_imported_flow_encrypted_valid_pin_code(hass): @@ -459,8 +355,8 @@ async def test_imported_flow_encrypted_valid_pin_code(hass): mock_remote = get_mock_remote( encrypted=True, - app_id="test-app-id", - encryption_key="test-encryption-key", + app_id="mock-app-id", + encryption_key="mock-encryption-key", ) with patch( @@ -470,12 +366,7 @@ async def test_imported_flow_encrypted_valid_pin_code(hass): result = await hass.config_entries.flow.async_init( DOMAIN, context={"source": config_entries.SOURCE_IMPORT}, - data={ - CONF_HOST: "1.2.3.4", - CONF_NAME: DEFAULT_NAME, - CONF_PORT: DEFAULT_PORT, - CONF_ON_ACTION: "test-on-action", - }, + data=MOCK_CONFIG_DATA, ) assert result["type"] == "form" @@ -489,18 +380,9 @@ async def test_imported_flow_encrypted_valid_pin_code(hass): assert result["type"] == "create_entry" assert result["title"] == DEFAULT_NAME assert result["data"] == { - CONF_HOST: "1.2.3.4", - CONF_NAME: DEFAULT_NAME, - CONF_PORT: DEFAULT_PORT, - CONF_ON_ACTION: "test-on-action", - CONF_APP_ID: "test-app-id", - CONF_ENCRYPTION_KEY: "test-encryption-key", - ATTR_DEVICE_INFO: { - ATTR_FRIENDLY_NAME: DEFAULT_NAME, - ATTR_MANUFACTURER: DEFAULT_MANUFACTURER, - ATTR_MODEL_NUMBER: DEFAULT_MODEL_NUMBER, - ATTR_UDN: "mock-unique-id", - }, + **MOCK_CONFIG_DATA, + **MOCK_ENCRYPTION_DATA, + ATTR_DEVICE_INFO: MOCK_DEVICE_INFO, } @@ -516,12 +398,7 @@ async def test_imported_flow_encrypted_invalid_pin_code_error(hass): result = await hass.config_entries.flow.async_init( DOMAIN, context={"source": config_entries.SOURCE_IMPORT}, - data={ - CONF_HOST: "1.2.3.4", - CONF_NAME: DEFAULT_NAME, - CONF_PORT: DEFAULT_PORT, - CONF_ON_ACTION: "test-on-action", - }, + data=MOCK_CONFIG_DATA, ) assert result["type"] == "form" @@ -553,12 +430,7 @@ async def test_imported_flow_encrypted_not_connected_abort(hass): result = await hass.config_entries.flow.async_init( DOMAIN, context={"source": config_entries.SOURCE_IMPORT}, - data={ - CONF_HOST: "1.2.3.4", - CONF_NAME: DEFAULT_NAME, - CONF_PORT: DEFAULT_PORT, - CONF_ON_ACTION: "test-on-action", - }, + data=MOCK_CONFIG_DATA, ) assert result["type"] == "form" @@ -585,12 +457,7 @@ async def test_imported_flow_encrypted_unknown_abort(hass): result = await hass.config_entries.flow.async_init( DOMAIN, context={"source": config_entries.SOURCE_IMPORT}, - data={ - CONF_HOST: "1.2.3.4", - CONF_NAME: DEFAULT_NAME, - CONF_PORT: DEFAULT_PORT, - CONF_ON_ACTION: "test-on-action", - }, + data=MOCK_CONFIG_DATA, ) assert result["type"] == "form" @@ -615,12 +482,7 @@ async def test_imported_flow_not_connected_error(hass): result = await hass.config_entries.flow.async_init( DOMAIN, context={"source": config_entries.SOURCE_IMPORT}, - data={ - CONF_HOST: "1.2.3.4", - CONF_NAME: DEFAULT_NAME, - CONF_PORT: DEFAULT_PORT, - CONF_ON_ACTION: "test-on-action", - }, + data=MOCK_CONFIG_DATA, ) assert result["type"] == "form" @@ -638,12 +500,7 @@ async def test_imported_flow_unknown_abort(hass): result = await hass.config_entries.flow.async_init( DOMAIN, context={"source": config_entries.SOURCE_IMPORT}, - data={ - CONF_HOST: "1.2.3.4", - CONF_NAME: DEFAULT_NAME, - CONF_PORT: DEFAULT_PORT, - CONF_ON_ACTION: "test-on-action", - }, + data=MOCK_CONFIG_DATA, ) assert result["type"] == "abort" @@ -655,19 +512,14 @@ async def test_imported_flow_non_encrypted_already_configured_abort(hass): MockConfigEntry( domain=DOMAIN, - unique_id="1.2.3.4", - data={ - CONF_HOST: "1.2.3.4", - CONF_NAME: DEFAULT_NAME, - CONF_PORT: DEFAULT_PORT, - CONF_ON_ACTION: "test-on-action", - }, + unique_id="0.0.0.0", + data=MOCK_CONFIG_DATA, ).add_to_hass(hass) result = await hass.config_entries.flow.async_init( DOMAIN, context={"source": config_entries.SOURCE_IMPORT}, - data={CONF_HOST: "1.2.3.4", CONF_NAME: DEFAULT_NAME}, + data=MOCK_BASIC_DATA, ) assert result["type"] == "abort" @@ -679,21 +531,14 @@ async def test_imported_flow_encrypted_already_configured_abort(hass): MockConfigEntry( domain=DOMAIN, - unique_id="1.2.3.4", - data={ - CONF_HOST: "1.2.3.4", - CONF_NAME: DEFAULT_NAME, - CONF_PORT: DEFAULT_PORT, - CONF_ON_ACTION: "test-on-action", - CONF_APP_ID: "test-app-id", - CONF_ENCRYPTION_KEY: "test-encryption-key", - }, + unique_id="0.0.0.0", + data={**MOCK_CONFIG_DATA, **MOCK_ENCRYPTION_DATA}, ).add_to_hass(hass) result = await hass.config_entries.flow.async_init( DOMAIN, context={"source": config_entries.SOURCE_IMPORT}, - data={CONF_HOST: "1.2.3.4", CONF_NAME: DEFAULT_NAME}, + data=MOCK_BASIC_DATA, ) assert result["type"] == "abort" diff --git a/tests/components/panasonic_viera/test_init.py b/tests/components/panasonic_viera/test_init.py index 5c9bf183c6f..7351b4e5544 100644 --- a/tests/components/panasonic_viera/test_init.py +++ b/tests/components/panasonic_viera/test_init.py @@ -1,65 +1,27 @@ """Test the Panasonic Viera setup process.""" -from unittest.mock import Mock, patch +from unittest.mock import patch from homeassistant.components.panasonic_viera.const import ( ATTR_DEVICE_INFO, - ATTR_FRIENDLY_NAME, - ATTR_MANUFACTURER, - ATTR_MODEL_NUMBER, ATTR_UDN, - CONF_APP_ID, - CONF_ENCRYPTION_KEY, - CONF_ON_ACTION, - DEFAULT_MANUFACTURER, - DEFAULT_MODEL_NUMBER, DEFAULT_NAME, - DEFAULT_PORT, DOMAIN, ) from homeassistant.config_entries import ENTRY_STATE_NOT_LOADED -from homeassistant.const import CONF_HOST, CONF_NAME, CONF_PORT, STATE_UNAVAILABLE +from homeassistant.const import CONF_HOST, STATE_UNAVAILABLE from homeassistant.setup import async_setup_component +from .conftest import ( + MOCK_CONFIG_DATA, + MOCK_DEVICE_INFO, + MOCK_ENCRYPTION_DATA, + get_mock_remote, +) + from tests.common import MockConfigEntry -MOCK_CONFIG_DATA = { - CONF_HOST: "0.0.0.0", - CONF_NAME: DEFAULT_NAME, - CONF_PORT: DEFAULT_PORT, - CONF_ON_ACTION: None, -} -MOCK_ENCRYPTION_DATA = { - CONF_APP_ID: "mock-app-id", - CONF_ENCRYPTION_KEY: "mock-encryption-key", -} - -MOCK_DEVICE_INFO = { - ATTR_FRIENDLY_NAME: DEFAULT_NAME, - ATTR_MANUFACTURER: DEFAULT_MANUFACTURER, - ATTR_MODEL_NUMBER: DEFAULT_MODEL_NUMBER, - ATTR_UDN: "mock-unique-id", -} - - -def get_mock_remote(device_info=MOCK_DEVICE_INFO): - """Return a mock remote.""" - mock_remote = Mock() - - async def async_create_remote_control(during_setup=False): - return - - mock_remote.async_create_remote_control = async_create_remote_control - - async def async_get_device_info(): - return device_info - - mock_remote.async_get_device_info = async_get_device_info - - return mock_remote - - -async def test_setup_entry_encrypted(hass): +async def test_setup_entry_encrypted(hass, mock_remote): """Test setup with encrypted config entry.""" mock_entry = MockConfigEntry( domain=DOMAIN, @@ -69,22 +31,20 @@ async def test_setup_entry_encrypted(hass): mock_entry.add_to_hass(hass) - mock_remote = get_mock_remote() + await hass.config_entries.async_setup(mock_entry.entry_id) + await hass.async_block_till_done() - with patch( - "homeassistant.components.panasonic_viera.Remote", - return_value=mock_remote, - ): - await hass.config_entries.async_setup(mock_entry.entry_id) - await hass.async_block_till_done() + state_tv = hass.states.get("media_player.panasonic_viera_tv") + state_remote = hass.states.get("remote.panasonic_viera_tv") - state = hass.states.get("media_player.panasonic_viera_tv") + assert state_tv + assert state_tv.name == DEFAULT_NAME - assert state - assert state.name == DEFAULT_NAME + assert state_remote + assert state_remote.name == DEFAULT_NAME -async def test_setup_entry_encrypted_missing_device_info(hass): +async def test_setup_entry_encrypted_missing_device_info(hass, mock_remote): """Test setup with encrypted config entry and missing device info.""" mock_entry = MockConfigEntry( domain=DOMAIN, @@ -94,22 +54,20 @@ async def test_setup_entry_encrypted_missing_device_info(hass): mock_entry.add_to_hass(hass) - mock_remote = get_mock_remote() + await hass.config_entries.async_setup(mock_entry.entry_id) + await hass.async_block_till_done() - with patch( - "homeassistant.components.panasonic_viera.Remote", - return_value=mock_remote, - ): - await hass.config_entries.async_setup(mock_entry.entry_id) - await hass.async_block_till_done() + assert mock_entry.data[ATTR_DEVICE_INFO] == MOCK_DEVICE_INFO + assert mock_entry.unique_id == MOCK_DEVICE_INFO[ATTR_UDN] - assert mock_entry.data[ATTR_DEVICE_INFO] == MOCK_DEVICE_INFO - assert mock_entry.unique_id == MOCK_DEVICE_INFO[ATTR_UDN] + state_tv = hass.states.get("media_player.panasonic_viera_tv") + state_remote = hass.states.get("remote.panasonic_viera_tv") - state = hass.states.get("media_player.panasonic_viera_tv") + assert state_tv + assert state_tv.name == DEFAULT_NAME - assert state - assert state.name == DEFAULT_NAME + assert state_remote + assert state_remote.name == DEFAULT_NAME async def test_setup_entry_encrypted_missing_device_info_none(hass): @@ -125,7 +83,7 @@ async def test_setup_entry_encrypted_missing_device_info_none(hass): mock_remote = get_mock_remote(device_info=None) with patch( - "homeassistant.components.panasonic_viera.Remote", + "homeassistant.components.panasonic_viera.RemoteControl", return_value=mock_remote, ): await hass.config_entries.async_setup(mock_entry.entry_id) @@ -134,13 +92,17 @@ async def test_setup_entry_encrypted_missing_device_info_none(hass): assert mock_entry.data[ATTR_DEVICE_INFO] is None assert mock_entry.unique_id == MOCK_CONFIG_DATA[CONF_HOST] - state = hass.states.get("media_player.panasonic_viera_tv") + state_tv = hass.states.get("media_player.panasonic_viera_tv") + state_remote = hass.states.get("remote.panasonic_viera_tv") - assert state - assert state.name == DEFAULT_NAME + assert state_tv + assert state_tv.name == DEFAULT_NAME + + assert state_remote + assert state_remote.name == DEFAULT_NAME -async def test_setup_entry_unencrypted(hass): +async def test_setup_entry_unencrypted(hass, mock_remote): """Test setup with unencrypted config entry.""" mock_entry = MockConfigEntry( domain=DOMAIN, @@ -150,22 +112,20 @@ async def test_setup_entry_unencrypted(hass): mock_entry.add_to_hass(hass) - mock_remote = get_mock_remote() + await hass.config_entries.async_setup(mock_entry.entry_id) + await hass.async_block_till_done() - with patch( - "homeassistant.components.panasonic_viera.Remote", - return_value=mock_remote, - ): - await hass.config_entries.async_setup(mock_entry.entry_id) - await hass.async_block_till_done() + state_tv = hass.states.get("media_player.panasonic_viera_tv") + state_remote = hass.states.get("remote.panasonic_viera_tv") - state = hass.states.get("media_player.panasonic_viera_tv") + assert state_tv + assert state_tv.name == DEFAULT_NAME - assert state - assert state.name == DEFAULT_NAME + assert state_remote + assert state_remote.name == DEFAULT_NAME -async def test_setup_entry_unencrypted_missing_device_info(hass): +async def test_setup_entry_unencrypted_missing_device_info(hass, mock_remote): """Test setup with unencrypted config entry and missing device info.""" mock_entry = MockConfigEntry( domain=DOMAIN, @@ -175,22 +135,20 @@ async def test_setup_entry_unencrypted_missing_device_info(hass): mock_entry.add_to_hass(hass) - mock_remote = get_mock_remote() + await hass.config_entries.async_setup(mock_entry.entry_id) + await hass.async_block_till_done() - with patch( - "homeassistant.components.panasonic_viera.Remote", - return_value=mock_remote, - ): - await hass.config_entries.async_setup(mock_entry.entry_id) - await hass.async_block_till_done() + assert mock_entry.data[ATTR_DEVICE_INFO] == MOCK_DEVICE_INFO + assert mock_entry.unique_id == MOCK_DEVICE_INFO[ATTR_UDN] - assert mock_entry.data[ATTR_DEVICE_INFO] == MOCK_DEVICE_INFO - assert mock_entry.unique_id == MOCK_DEVICE_INFO[ATTR_UDN] + state_tv = hass.states.get("media_player.panasonic_viera_tv") + state_remote = hass.states.get("remote.panasonic_viera_tv") - state = hass.states.get("media_player.panasonic_viera_tv") + assert state_tv + assert state_tv.name == DEFAULT_NAME - assert state - assert state.name == DEFAULT_NAME + assert state_remote + assert state_remote.name == DEFAULT_NAME async def test_setup_entry_unencrypted_missing_device_info_none(hass): @@ -206,7 +164,7 @@ async def test_setup_entry_unencrypted_missing_device_info_none(hass): mock_remote = get_mock_remote(device_info=None) with patch( - "homeassistant.components.panasonic_viera.Remote", + "homeassistant.components.panasonic_viera.RemoteControl", return_value=mock_remote, ): await hass.config_entries.async_setup(mock_entry.entry_id) @@ -215,10 +173,14 @@ async def test_setup_entry_unencrypted_missing_device_info_none(hass): assert mock_entry.data[ATTR_DEVICE_INFO] is None assert mock_entry.unique_id == MOCK_CONFIG_DATA[CONF_HOST] - state = hass.states.get("media_player.panasonic_viera_tv") + state_tv = hass.states.get("media_player.panasonic_viera_tv") + state_remote = hass.states.get("remote.panasonic_viera_tv") - assert state - assert state.name == DEFAULT_NAME + assert state_tv + assert state_tv.name == DEFAULT_NAME + + assert state_remote + assert state_remote.name == DEFAULT_NAME async def test_setup_config_flow_initiated(hass): @@ -235,7 +197,7 @@ async def test_setup_config_flow_initiated(hass): assert len(hass.config_entries.flow.async_progress()) == 1 -async def test_setup_unload_entry(hass): +async def test_setup_unload_entry(hass, mock_remote): """Test if config entry is unloaded.""" mock_entry = MockConfigEntry( domain=DOMAIN, unique_id=MOCK_DEVICE_INFO[ATTR_UDN], data=MOCK_CONFIG_DATA @@ -243,21 +205,23 @@ async def test_setup_unload_entry(hass): mock_entry.add_to_hass(hass) - mock_remote = get_mock_remote() - - with patch( - "homeassistant.components.panasonic_viera.Remote", - return_value=mock_remote, - ): - await hass.config_entries.async_setup(mock_entry.entry_id) - await hass.async_block_till_done() + await hass.config_entries.async_setup(mock_entry.entry_id) + await hass.async_block_till_done() await hass.config_entries.async_unload(mock_entry.entry_id) assert mock_entry.state == ENTRY_STATE_NOT_LOADED - state = hass.states.get("media_player.panasonic_viera_tv") - assert state.state == STATE_UNAVAILABLE + + state_tv = hass.states.get("media_player.panasonic_viera_tv") + state_remote = hass.states.get("remote.panasonic_viera_tv") + + assert state_tv.state == STATE_UNAVAILABLE + assert state_remote.state == STATE_UNAVAILABLE await hass.config_entries.async_remove(mock_entry.entry_id) await hass.async_block_till_done() - state = hass.states.get("media_player.panasonic_viera_tv") - assert state is None + + state_tv = hass.states.get("media_player.panasonic_viera_tv") + state_remote = hass.states.get("remote.panasonic_viera_tv") + + assert state_tv is None + assert state_remote is None diff --git a/tests/components/panasonic_viera/test_remote.py b/tests/components/panasonic_viera/test_remote.py new file mode 100644 index 00000000000..6bfd7dee8eb --- /dev/null +++ b/tests/components/panasonic_viera/test_remote.py @@ -0,0 +1,58 @@ +"""Test the Panasonic Viera remote entity.""" + +from unittest.mock import call + +from panasonic_viera import Keys + +from homeassistant.components.panasonic_viera.const import ATTR_UDN, DOMAIN +from homeassistant.components.remote import ( + ATTR_COMMAND, + DOMAIN as REMOTE_DOMAIN, + SERVICE_SEND_COMMAND, +) +from homeassistant.const import ATTR_ENTITY_ID, SERVICE_TURN_OFF, SERVICE_TURN_ON + +from .conftest import MOCK_CONFIG_DATA, MOCK_DEVICE_INFO, MOCK_ENCRYPTION_DATA + +from tests.common import MockConfigEntry + + +async def setup_panasonic_viera(hass): + """Initialize integration for tests.""" + mock_entry = MockConfigEntry( + domain=DOMAIN, + unique_id=MOCK_DEVICE_INFO[ATTR_UDN], + data={**MOCK_CONFIG_DATA, **MOCK_ENCRYPTION_DATA, **MOCK_DEVICE_INFO}, + ) + + mock_entry.add_to_hass(hass) + + await hass.config_entries.async_setup(mock_entry.entry_id) + await hass.async_block_till_done() + + +async def test_onoff(hass, mock_remote): + """Test the on/off service calls.""" + + await setup_panasonic_viera(hass) + + data = {ATTR_ENTITY_ID: "remote.panasonic_viera_tv"} + + await hass.services.async_call(REMOTE_DOMAIN, SERVICE_TURN_OFF, data) + await hass.services.async_call(REMOTE_DOMAIN, SERVICE_TURN_ON, data) + await hass.async_block_till_done() + + power = getattr(Keys.power, "value", Keys.power) + assert mock_remote.send_key.call_args_list == [call(power), call(power)] + + +async def test_send_command(hass, mock_remote): + """Test the send_command service call.""" + + await setup_panasonic_viera(hass) + + data = {ATTR_ENTITY_ID: "remote.panasonic_viera_tv", ATTR_COMMAND: "command"} + await hass.services.async_call(REMOTE_DOMAIN, SERVICE_SEND_COMMAND, data) + await hass.async_block_till_done() + + assert mock_remote.send_key.call_args == call("command")