2019-08-29 03:03:03 -07:00
""" The tests for the androidtv platform. """
import logging
2022-05-03 00:18:38 +02:00
from unittest . mock import Mock , patch
2020-01-06 14:10:13 -08:00
2021-12-20 20:08:35 +01:00
from androidtv . constants import APPS as ANDROIDTV_APPS , KEYS
2020-01-06 14:10:13 -08:00
from androidtv . exceptions import LockNotAcquiredException
2020-08-29 19:56:25 -07:00
import pytest
2019-08-29 03:03:03 -07:00
2021-12-20 20:08:35 +01:00
from homeassistant . components . androidtv . const import (
2019-09-02 13:08:01 -07:00
CONF_ADB_SERVER_IP ,
2021-12-20 20:08:35 +01:00
CONF_ADB_SERVER_PORT ,
2019-10-17 06:33:20 -07:00
CONF_ADBKEY ,
2019-11-07 14:04:59 -08:00
CONF_APPS ,
2020-01-29 12:13:09 -08:00
CONF_EXCLUDE_UNNAMED_APPS ,
2022-05-03 00:18:38 +02:00
CONF_SCREENCAP ,
CONF_STATE_DETECTION_RULES ,
2020-07-05 12:13:08 -07:00
CONF_TURN_OFF_COMMAND ,
CONF_TURN_ON_COMMAND ,
2021-12-20 20:08:35 +01:00
DEFAULT_ADB_SERVER_PORT ,
DEFAULT_PORT ,
2022-04-27 08:26:22 +02:00
DEVICE_ANDROIDTV ,
DEVICE_FIRETV ,
2021-12-20 20:08:35 +01:00
DOMAIN ,
)
from homeassistant . components . androidtv . media_player import (
ATTR_DEVICE_PATH ,
ATTR_LOCAL_PATH ,
2022-04-27 08:26:22 +02:00
PREFIX_ANDROIDTV ,
PREFIX_FIRETV ,
2020-01-06 14:10:13 -08:00
SERVICE_ADB_COMMAND ,
SERVICE_DOWNLOAD ,
2020-06-29 18:17:04 -07:00
SERVICE_LEARN_SENDEVENT ,
2020-01-06 14:10:13 -08:00
SERVICE_UPLOAD ,
2019-11-07 14:04:59 -08:00
)
2020-07-05 12:13:08 -07:00
from homeassistant . components . media_player import (
2019-11-07 14:04:59 -08:00
ATTR_INPUT_SOURCE ,
2020-07-05 12:13:08 -07:00
ATTR_MEDIA_VOLUME_LEVEL ,
ATTR_MEDIA_VOLUME_MUTED ,
2021-12-20 20:08:35 +01:00
DOMAIN as MP_DOMAIN ,
2020-07-05 12:13:08 -07:00
SERVICE_MEDIA_NEXT_TRACK ,
SERVICE_MEDIA_PAUSE ,
SERVICE_MEDIA_PLAY ,
SERVICE_MEDIA_PLAY_PAUSE ,
SERVICE_MEDIA_PREVIOUS_TRACK ,
SERVICE_MEDIA_STOP ,
2019-11-07 14:04:59 -08:00
SERVICE_SELECT_SOURCE ,
2020-07-05 12:13:08 -07:00
SERVICE_TURN_OFF ,
SERVICE_TURN_ON ,
SERVICE_VOLUME_DOWN ,
SERVICE_VOLUME_MUTE ,
SERVICE_VOLUME_SET ,
SERVICE_VOLUME_UP ,
2019-09-02 13:08:01 -07:00
)
2022-05-03 00:18:38 +02:00
from homeassistant . config_entries import ConfigEntryState
2019-09-02 13:08:01 -07:00
from homeassistant . const import (
2021-12-20 20:08:35 +01:00
ATTR_COMMAND ,
2019-11-07 14:04:59 -08:00
ATTR_ENTITY_ID ,
2019-09-02 13:08:01 -07:00
CONF_DEVICE_CLASS ,
CONF_HOST ,
2022-03-28 02:57:15 +02:00
CONF_NAME ,
2021-12-20 20:08:35 +01:00
CONF_PORT ,
2020-07-19 17:48:08 -07:00
EVENT_HOMEASSISTANT_STOP ,
2019-09-02 13:08:01 -07:00
STATE_OFF ,
2019-11-07 14:04:59 -08:00
STATE_PLAYING ,
2020-06-07 08:10:20 -07:00
STATE_STANDBY ,
2019-09-02 13:08:01 -07:00
STATE_UNAVAILABLE ,
2019-08-29 03:03:03 -07:00
)
2022-03-25 23:22:58 +01:00
from homeassistant . helpers . entity_component import async_update_entity
2021-12-20 20:08:35 +01:00
from homeassistant . util import slugify
2019-08-29 03:03:03 -07:00
2022-04-27 08:26:22 +02:00
from . import patchers
2021-12-20 20:08:35 +01:00
from tests . common import MockConfigEntry
2020-07-05 12:13:08 -07:00
2022-04-27 08:26:22 +02:00
HOST = " 127.0.0.1 "
2022-04-28 00:17:56 +02:00
ADB_PATCH_KEY = " patch_key "
2022-04-27 08:26:22 +02:00
TEST_ENTITY_NAME = " entity_name "
2021-12-20 20:08:35 +01:00
2022-05-03 00:18:38 +02:00
MSG_RECONNECT = {
patchers . KEY_PYTHON : f " ADB connection to { HOST } : { DEFAULT_PORT } successfully established " ,
patchers . KEY_SERVER : f " ADB connection to { HOST } : { DEFAULT_PORT } via ADB server { patchers . ADB_SERVER_HOST } : { DEFAULT_ADB_SERVER_PORT } successfully established " ,
}
2021-12-20 20:08:35 +01:00
2020-07-05 12:13:08 -07:00
SHELL_RESPONSE_OFF = " "
SHELL_RESPONSE_STANDBY = " 1 "
2020-05-03 11:27:19 -07:00
2019-09-02 13:08:01 -07:00
# Android TV device with Python ADB implementation
CONFIG_ANDROIDTV_PYTHON_ADB = {
2022-04-28 00:17:56 +02:00
ADB_PATCH_KEY : patchers . KEY_PYTHON ,
2022-04-27 08:26:22 +02:00
TEST_ENTITY_NAME : f " { PREFIX_ANDROIDTV } { HOST } " ,
2019-09-02 13:08:01 -07:00
DOMAIN : {
2022-04-27 08:26:22 +02:00
CONF_HOST : HOST ,
2021-12-20 20:08:35 +01:00
CONF_PORT : DEFAULT_PORT ,
2022-04-27 08:26:22 +02:00
CONF_DEVICE_CLASS : DEVICE_ANDROIDTV ,
} ,
2019-09-02 13:08:01 -07:00
}
2022-03-28 02:57:15 +02:00
# Android TV device with Python ADB implementation imported from YAML
CONFIG_ANDROIDTV_PYTHON_ADB_YAML = {
2022-04-28 00:17:56 +02:00
ADB_PATCH_KEY : patchers . KEY_PYTHON ,
2022-04-27 08:26:22 +02:00
TEST_ENTITY_NAME : " ADB yaml import " ,
2022-03-28 02:57:15 +02:00
DOMAIN : {
CONF_NAME : " ADB yaml import " ,
* * CONFIG_ANDROIDTV_PYTHON_ADB [ DOMAIN ] ,
2022-04-27 08:26:22 +02:00
} ,
2022-03-28 02:57:15 +02:00
}
2022-05-03 00:18:38 +02:00
# Android TV device with Python ADB implementation with custom adbkey
CONFIG_ANDROIDTV_PYTHON_ADB_KEY = {
ADB_PATCH_KEY : patchers . KEY_PYTHON ,
TEST_ENTITY_NAME : CONFIG_ANDROIDTV_PYTHON_ADB [ TEST_ENTITY_NAME ] ,
DOMAIN : {
* * CONFIG_ANDROIDTV_PYTHON_ADB [ DOMAIN ] ,
CONF_ADBKEY : " user_provided_adbkey " ,
} ,
}
2019-09-02 13:08:01 -07:00
# Android TV device with ADB server
CONFIG_ANDROIDTV_ADB_SERVER = {
2022-04-28 00:17:56 +02:00
ADB_PATCH_KEY : patchers . KEY_SERVER ,
2022-04-27 08:26:22 +02:00
TEST_ENTITY_NAME : f " { PREFIX_ANDROIDTV } { HOST } " ,
2019-09-02 13:08:01 -07:00
DOMAIN : {
2022-04-27 08:26:22 +02:00
CONF_HOST : HOST ,
2021-12-20 20:08:35 +01:00
CONF_PORT : DEFAULT_PORT ,
2022-04-27 08:26:22 +02:00
CONF_DEVICE_CLASS : DEVICE_ANDROIDTV ,
2022-05-03 00:18:38 +02:00
CONF_ADB_SERVER_IP : patchers . ADB_SERVER_HOST ,
2021-12-20 20:08:35 +01:00
CONF_ADB_SERVER_PORT : DEFAULT_ADB_SERVER_PORT ,
2022-04-27 08:26:22 +02:00
} ,
2019-09-02 13:08:01 -07:00
}
# Fire TV device with Python ADB implementation
CONFIG_FIRETV_PYTHON_ADB = {
2022-04-28 00:17:56 +02:00
ADB_PATCH_KEY : patchers . KEY_PYTHON ,
2022-04-27 08:26:22 +02:00
TEST_ENTITY_NAME : f " { PREFIX_FIRETV } { HOST } " ,
2019-09-02 13:08:01 -07:00
DOMAIN : {
2022-04-27 08:26:22 +02:00
CONF_HOST : HOST ,
2021-12-20 20:08:35 +01:00
CONF_PORT : DEFAULT_PORT ,
2022-04-27 08:26:22 +02:00
CONF_DEVICE_CLASS : DEVICE_FIRETV ,
} ,
2019-09-02 13:08:01 -07:00
}
# Fire TV device with ADB server
CONFIG_FIRETV_ADB_SERVER = {
2022-04-28 00:17:56 +02:00
ADB_PATCH_KEY : patchers . KEY_SERVER ,
2022-04-27 08:26:22 +02:00
TEST_ENTITY_NAME : f " { PREFIX_FIRETV } { HOST } " ,
2019-09-02 13:08:01 -07:00
DOMAIN : {
2022-04-27 08:26:22 +02:00
CONF_HOST : HOST ,
2021-12-20 20:08:35 +01:00
CONF_PORT : DEFAULT_PORT ,
2022-04-27 08:26:22 +02:00
CONF_DEVICE_CLASS : DEVICE_FIRETV ,
2022-05-03 00:18:38 +02:00
CONF_ADB_SERVER_IP : patchers . ADB_SERVER_HOST ,
2021-12-20 20:08:35 +01:00
CONF_ADB_SERVER_PORT : DEFAULT_ADB_SERVER_PORT ,
2022-04-27 08:26:22 +02:00
} ,
2019-09-02 13:08:01 -07:00
}
2022-05-03 00:18:38 +02:00
CONFIG_ANDROIDTV_DEFAULT = CONFIG_ANDROIDTV_PYTHON_ADB
CONFIG_FIRETV_DEFAULT = CONFIG_FIRETV_PYTHON_ADB
@pytest.fixture ( autouse = True )
def adb_device_tcp_fixture ( ) - > None :
""" Patch ADB Device TCP. """
with patch (
" androidtv.adb_manager.adb_manager_async.AdbDeviceTcpAsync " ,
patchers . AdbDeviceTcpAsyncFake ,
) :
yield
@pytest.fixture ( autouse = True )
def load_adbkey_fixture ( ) - > None :
""" Patch load_adbkey. """
with patch (
" homeassistant.components.androidtv.ADBPythonSync.load_adbkey " ,
return_value = " signer for testing " ,
) :
yield
@pytest.fixture ( autouse = True )
def keygen_fixture ( ) - > None :
""" Patch keygen. """
with patch (
" homeassistant.components.androidtv.keygen " ,
return_value = Mock ( ) ,
) :
yield
2019-09-02 13:08:01 -07:00
2020-01-06 14:10:13 -08:00
def _setup ( config ) :
2019-10-17 06:33:20 -07:00
""" Perform common setup tasks for the tests. """
2022-04-28 00:17:56 +02:00
patch_key = config [ ADB_PATCH_KEY ]
2022-04-27 08:26:22 +02:00
entity_id = f " { MP_DOMAIN } . { slugify ( config [ TEST_ENTITY_NAME ] ) } "
2021-12-20 20:08:35 +01:00
config_entry = MockConfigEntry (
domain = DOMAIN ,
data = config [ DOMAIN ] ,
unique_id = " a1:b1:c1:d1:e1:f1 " ,
)
return patch_key , entity_id , config_entry
2022-01-14 02:05:35 +01:00
@pytest.mark.parametrize (
" config " ,
[
CONFIG_ANDROIDTV_PYTHON_ADB ,
2022-03-28 02:57:15 +02:00
CONFIG_ANDROIDTV_PYTHON_ADB_YAML ,
2022-01-14 02:05:35 +01:00
CONFIG_FIRETV_PYTHON_ADB ,
CONFIG_ANDROIDTV_ADB_SERVER ,
CONFIG_FIRETV_ADB_SERVER ,
] ,
)
async def test_reconnect ( hass , caplog , config ) :
2019-10-17 06:33:20 -07:00
""" Test that the error and reconnection attempts are logged correctly.
" Handles device/service unavailable. Log a warning once when
unavailable , log once when reconnected . "
https : / / developers . home - assistant . io / docs / en / integration_quality_scale_index . html
"""
2021-12-20 20:08:35 +01:00
patch_key , entity_id , config_entry = _setup ( config )
config_entry . add_to_hass ( hass )
2019-10-17 06:33:20 -07:00
2022-05-03 00:18:38 +02:00
with patchers . patch_connect ( True ) [ patch_key ] , patchers . patch_shell (
SHELL_RESPONSE_OFF
) [ patch_key ] :
2022-02-06 23:15:50 +01:00
assert await hass . config_entries . async_setup ( config_entry . entry_id )
await hass . async_block_till_done ( )
2019-10-17 06:33:20 -07:00
2022-03-25 23:22:58 +01:00
await async_update_entity ( hass , entity_id )
2019-09-02 13:08:01 -07:00
state = hass . states . get ( entity_id )
assert state is not None
assert state . state == STATE_OFF
caplog . clear ( )
caplog . set_level ( logging . WARNING )
with patchers . patch_connect ( False ) [ patch_key ] , patchers . patch_shell ( error = True ) [
patch_key
2022-05-03 00:18:38 +02:00
] :
2019-09-02 13:08:01 -07:00
for _ in range ( 5 ) :
2022-03-25 23:22:58 +01:00
await async_update_entity ( hass , entity_id )
2019-09-02 13:08:01 -07:00
state = hass . states . get ( entity_id )
assert state is not None
assert state . state == STATE_UNAVAILABLE
assert len ( caplog . record_tuples ) == 2
assert caplog . record_tuples [ 0 ] [ 1 ] == logging . ERROR
assert caplog . record_tuples [ 1 ] [ 1 ] == logging . WARNING
caplog . set_level ( logging . DEBUG )
2020-07-05 12:13:08 -07:00
with patchers . patch_connect ( True ) [ patch_key ] , patchers . patch_shell (
SHELL_RESPONSE_STANDBY
2022-05-03 00:18:38 +02:00
) [ patch_key ] :
2022-03-25 23:22:58 +01:00
await async_update_entity ( hass , entity_id )
2019-09-02 13:08:01 -07:00
state = hass . states . get ( entity_id )
assert state is not None
2020-06-07 08:10:20 -07:00
assert state . state == STATE_STANDBY
2022-05-03 00:18:38 +02:00
assert MSG_RECONNECT [ patch_key ] in caplog . record_tuples [ 2 ]
2019-08-29 03:03:03 -07:00
2022-01-14 02:05:35 +01:00
@pytest.mark.parametrize (
" config " ,
[
CONFIG_ANDROIDTV_PYTHON_ADB ,
CONFIG_FIRETV_PYTHON_ADB ,
CONFIG_ANDROIDTV_ADB_SERVER ,
CONFIG_FIRETV_ADB_SERVER ,
] ,
)
async def test_adb_shell_returns_none ( hass , config ) :
2019-09-02 13:08:01 -07:00
""" Test the case that the ADB shell command returns `None`.
2019-08-29 03:03:03 -07:00
2019-09-02 13:08:01 -07:00
The state should be ` None ` and the device should be unavailable .
"""
2021-12-20 20:08:35 +01:00
patch_key , entity_id , config_entry = _setup ( config )
config_entry . add_to_hass ( hass )
2019-08-29 03:03:03 -07:00
2022-05-03 00:18:38 +02:00
with patchers . patch_connect ( True ) [ patch_key ] , patchers . patch_shell (
SHELL_RESPONSE_OFF
) [ patch_key ] :
2022-02-06 23:15:50 +01:00
assert await hass . config_entries . async_setup ( config_entry . entry_id )
await hass . async_block_till_done ( )
2022-02-04 11:13:08 -08:00
2022-03-25 23:22:58 +01:00
await async_update_entity ( hass , entity_id )
2019-09-02 13:08:01 -07:00
state = hass . states . get ( entity_id )
assert state is not None
assert state . state != STATE_UNAVAILABLE
2019-08-29 03:03:03 -07:00
2019-09-02 13:08:01 -07:00
with patchers . patch_shell ( None ) [ patch_key ] , patchers . patch_shell ( error = True ) [
patch_key
2022-05-03 00:18:38 +02:00
] :
2022-03-25 23:22:58 +01:00
await async_update_entity ( hass , entity_id )
2019-09-02 13:08:01 -07:00
state = hass . states . get ( entity_id )
assert state is not None
assert state . state == STATE_UNAVAILABLE
2019-08-29 03:03:03 -07:00
2019-10-17 06:33:20 -07:00
async def test_setup_with_adbkey ( hass ) :
""" Test that setup succeeds when using an ADB key. """
2022-05-03 00:18:38 +02:00
patch_key , entity_id , config_entry = _setup ( CONFIG_ANDROIDTV_PYTHON_ADB_KEY )
2021-12-20 20:08:35 +01:00
config_entry . add_to_hass ( hass )
2019-10-17 06:33:20 -07:00
2022-05-03 00:18:38 +02:00
with patchers . patch_connect ( True ) [ patch_key ] , patchers . patch_shell (
SHELL_RESPONSE_OFF
) [ patch_key ] , patchers . PATCH_ISFILE :
2022-02-06 23:15:50 +01:00
assert await hass . config_entries . async_setup ( config_entry . entry_id )
await hass . async_block_till_done ( )
2022-02-04 11:13:08 -08:00
2022-03-25 23:22:58 +01:00
await async_update_entity ( hass , entity_id )
2019-10-17 06:33:20 -07:00
state = hass . states . get ( entity_id )
assert state is not None
assert state . state == STATE_OFF
2019-11-07 14:04:59 -08:00
2022-01-14 02:05:35 +01:00
@pytest.mark.parametrize (
2022-05-03 00:18:38 +02:00
" config " ,
2022-01-14 02:05:35 +01:00
[
2022-05-03 00:18:38 +02:00
CONFIG_ANDROIDTV_DEFAULT ,
CONFIG_FIRETV_DEFAULT ,
2022-01-14 02:05:35 +01:00
] ,
)
2022-05-03 00:18:38 +02:00
async def test_sources ( hass , config ) :
2019-12-14 10:54:41 -05:00
""" Test that sources (i.e., apps) are handled correctly for Android TV and Fire TV devices. """
2022-05-03 00:18:38 +02:00
conf_apps = {
" com.app.test1 " : " TEST 1 " ,
" com.app.test3 " : None ,
" com.app.test4 " : SHELL_RESPONSE_OFF ,
}
2021-12-20 20:08:35 +01:00
patch_key , entity_id , config_entry = _setup ( config )
config_entry . add_to_hass ( hass )
2022-05-03 00:18:38 +02:00
hass . config_entries . async_update_entry ( config_entry , options = { CONF_APPS : conf_apps } )
2019-11-07 14:04:59 -08:00
2022-05-03 00:18:38 +02:00
with patchers . patch_connect ( True ) [ patch_key ] , patchers . patch_shell (
SHELL_RESPONSE_OFF
) [ patch_key ] :
2022-02-06 23:15:50 +01:00
assert await hass . config_entries . async_setup ( config_entry . entry_id )
await hass . async_block_till_done ( )
2022-02-04 11:13:08 -08:00
2022-03-25 23:22:58 +01:00
await async_update_entity ( hass , entity_id )
2019-11-07 14:04:59 -08:00
state = hass . states . get ( entity_id )
assert state is not None
assert state . state == STATE_OFF
2022-05-03 00:18:38 +02:00
patch_update = patchers . patch_androidtv_update (
" playing " ,
" com.app.test1 " ,
[ " com.app.test1 " , " com.app.test2 " , " com.app.test3 " , " com.app.test4 " ] ,
" hdmi " ,
False ,
1 ,
" HW5 " ,
)
2019-12-14 10:54:41 -05:00
2022-05-03 00:18:38 +02:00
with patch_update [ config [ DOMAIN ] [ CONF_DEVICE_CLASS ] ] :
2022-03-25 23:22:58 +01:00
await async_update_entity ( hass , entity_id )
2019-11-07 14:04:59 -08:00
state = hass . states . get ( entity_id )
assert state is not None
assert state . state == STATE_PLAYING
assert state . attributes [ " source " ] == " TEST 1 "
2020-01-29 12:13:09 -08:00
assert sorted ( state . attributes [ " source_list " ] ) == [ " TEST 1 " , " com.app.test2 " ]
2019-11-07 14:04:59 -08:00
2022-05-03 00:18:38 +02:00
patch_update = patchers . patch_androidtv_update (
" playing " ,
" com.app.test2 " ,
[ " com.app.test2 " , " com.app.test1 " , " com.app.test3 " , " com.app.test4 " ] ,
" hdmi " ,
True ,
0 ,
" HW5 " ,
)
2019-12-14 10:54:41 -05:00
2022-05-03 00:18:38 +02:00
with patch_update [ config [ DOMAIN ] [ CONF_DEVICE_CLASS ] ] :
2022-03-25 23:22:58 +01:00
await async_update_entity ( hass , entity_id )
2019-11-07 14:04:59 -08:00
state = hass . states . get ( entity_id )
assert state is not None
assert state . state == STATE_PLAYING
assert state . attributes [ " source " ] == " com.app.test2 "
2020-01-29 12:13:09 -08:00
assert sorted ( state . attributes [ " source_list " ] ) == [ " TEST 1 " , " com.app.test2 " ]
2019-11-07 14:04:59 -08:00
2019-12-14 10:54:41 -05:00
2022-05-03 00:18:38 +02:00
@pytest.mark.parametrize (
[ " config " , " expected_sources " ] ,
[
( CONFIG_ANDROIDTV_DEFAULT , [ " TEST 1 " ] ) ,
( CONFIG_FIRETV_DEFAULT , [ " TEST 1 " ] ) ,
] ,
)
async def test_exclude_sources ( hass , config , expected_sources ) :
2020-01-29 12:13:09 -08:00
""" Test that sources (i.e., apps) are handled correctly when the `exclude_unnamed_apps` config parameter is provided. """
2022-05-03 00:18:38 +02:00
conf_apps = {
" com.app.test1 " : " TEST 1 " ,
" com.app.test3 " : None ,
" com.app.test4 " : SHELL_RESPONSE_OFF ,
}
2021-12-20 20:08:35 +01:00
patch_key , entity_id , config_entry = _setup ( config )
config_entry . add_to_hass ( hass )
2022-05-03 00:18:38 +02:00
hass . config_entries . async_update_entry (
config_entry , options = { CONF_EXCLUDE_UNNAMED_APPS : True , CONF_APPS : conf_apps }
)
2020-01-29 12:13:09 -08:00
2022-05-03 00:18:38 +02:00
with patchers . patch_connect ( True ) [ patch_key ] , patchers . patch_shell (
SHELL_RESPONSE_OFF
) [ patch_key ] :
2022-02-06 23:15:50 +01:00
assert await hass . config_entries . async_setup ( config_entry . entry_id )
await hass . async_block_till_done ( )
2022-02-04 11:13:08 -08:00
2022-03-25 23:22:58 +01:00
await async_update_entity ( hass , entity_id )
2020-01-29 12:13:09 -08:00
state = hass . states . get ( entity_id )
assert state is not None
assert state . state == STATE_OFF
2022-05-03 00:18:38 +02:00
patch_update = patchers . patch_androidtv_update (
" playing " ,
" com.app.test1 " ,
[
2020-01-29 12:13:09 -08:00
" com.app.test1 " ,
2022-05-03 00:18:38 +02:00
" com.app.test2 " ,
" com.app.test3 " ,
" com.app.test4 " ,
" com.app.test5 " ,
] ,
" hdmi " ,
False ,
1 ,
" HW5 " ,
)
2020-01-29 12:13:09 -08:00
2022-05-03 00:18:38 +02:00
with patch_update [ config [ DOMAIN ] [ CONF_DEVICE_CLASS ] ] :
2022-03-25 23:22:58 +01:00
await async_update_entity ( hass , entity_id )
2020-01-29 12:13:09 -08:00
state = hass . states . get ( entity_id )
assert state is not None
assert state . state == STATE_PLAYING
assert state . attributes [ " source " ] == " TEST 1 "
assert sorted ( state . attributes [ " source_list " ] ) == expected_sources
2022-05-03 00:18:38 +02:00
async def _test_select_source (
hass , config , conf_apps , source , expected_arg , method_patch
) :
2019-12-14 10:54:41 -05:00
""" Test that the methods for launching and stopping apps are called correctly when selecting a source. """
2021-12-20 20:08:35 +01:00
patch_key , entity_id , config_entry = _setup ( config )
config_entry . add_to_hass ( hass )
2022-05-03 00:18:38 +02:00
hass . config_entries . async_update_entry ( config_entry , options = { CONF_APPS : conf_apps } )
2019-11-07 14:04:59 -08:00
2022-05-03 00:18:38 +02:00
with patchers . patch_connect ( True ) [ patch_key ] , patchers . patch_shell (
SHELL_RESPONSE_OFF
) [ patch_key ] :
2022-02-06 23:15:50 +01:00
assert await hass . config_entries . async_setup ( config_entry . entry_id )
await hass . async_block_till_done ( )
2022-02-04 11:13:08 -08:00
2022-03-25 23:22:58 +01:00
await async_update_entity ( hass , entity_id )
2019-11-07 14:04:59 -08:00
state = hass . states . get ( entity_id )
assert state is not None
assert state . state == STATE_OFF
2022-05-03 00:18:38 +02:00
with method_patch as method_patch_used :
2019-11-07 14:04:59 -08:00
await hass . services . async_call (
2021-12-20 20:08:35 +01:00
MP_DOMAIN ,
2019-11-07 14:04:59 -08:00
SERVICE_SELECT_SOURCE ,
{ ATTR_ENTITY_ID : entity_id , ATTR_INPUT_SOURCE : source } ,
blocking = True ,
)
2022-05-03 00:18:38 +02:00
method_patch_used . assert_called_with ( expected_arg )
2019-12-14 10:54:41 -05:00
2022-05-03 00:18:38 +02:00
@pytest.mark.parametrize (
[ " source " , " expected_arg " , " method_patch " ] ,
[
( " com.app.test1 " , " com.app.test1 " , patchers . PATCH_LAUNCH_APP ) ,
( " TEST 1 " , " com.app.test1 " , patchers . PATCH_LAUNCH_APP ) ,
( " com.app.test2 " , " com.app.test2 " , patchers . PATCH_LAUNCH_APP ) ,
( " com.app.test3 " , " com.app.test3 " , patchers . PATCH_LAUNCH_APP ) ,
( " !com.app.test1 " , " com.app.test1 " , patchers . PATCH_STOP_APP ) ,
( " !TEST 1 " , " com.app.test1 " , patchers . PATCH_STOP_APP ) ,
( " !com.app.test2 " , " com.app.test2 " , patchers . PATCH_STOP_APP ) ,
( " !com.app.test3 " , " com.app.test3 " , patchers . PATCH_STOP_APP ) ,
] ,
)
async def test_select_source_androidtv ( hass , source , expected_arg , method_patch ) :
""" Test that an app can be launched for AndroidTV. """
conf_apps = {
" com.app.test1 " : " TEST 1 " ,
" com.app.test3 " : None ,
}
await _test_select_source (
hass , CONFIG_ANDROIDTV_DEFAULT , conf_apps , source , expected_arg , method_patch
2020-01-29 12:13:09 -08:00
)
2020-11-05 07:41:22 -08:00
async def test_androidtv_select_source_overridden_app_name ( hass ) :
""" Test that when an app name is overridden via the `apps` configuration parameter, the app is launched correctly. """
# Evidence that the default YouTube app ID will be overridden
2022-05-03 00:18:38 +02:00
conf_apps = {
" com.youtube.test " : " YouTube " ,
}
2020-11-05 07:41:22 -08:00
assert " YouTube " in ANDROIDTV_APPS . values ( )
assert " com.youtube.test " not in ANDROIDTV_APPS
2022-05-03 00:18:38 +02:00
await _test_select_source (
2020-11-05 07:41:22 -08:00
hass ,
2022-05-03 00:18:38 +02:00
CONFIG_ANDROIDTV_PYTHON_ADB ,
conf_apps ,
2020-11-05 07:41:22 -08:00
" YouTube " ,
" com.youtube.test " ,
patchers . PATCH_LAUNCH_APP ,
)
2022-05-03 00:18:38 +02:00
@pytest.mark.parametrize (
[ " source " , " expected_arg " , " method_patch " ] ,
[
( " com.app.test1 " , " com.app.test1 " , patchers . PATCH_LAUNCH_APP ) ,
( " TEST 1 " , " com.app.test1 " , patchers . PATCH_LAUNCH_APP ) ,
( " com.app.test2 " , " com.app.test2 " , patchers . PATCH_LAUNCH_APP ) ,
( " com.app.test3 " , " com.app.test3 " , patchers . PATCH_LAUNCH_APP ) ,
( " !com.app.test1 " , " com.app.test1 " , patchers . PATCH_STOP_APP ) ,
( " !TEST 1 " , " com.app.test1 " , patchers . PATCH_STOP_APP ) ,
( " !com.app.test2 " , " com.app.test2 " , patchers . PATCH_STOP_APP ) ,
( " !com.app.test3 " , " com.app.test3 " , patchers . PATCH_STOP_APP ) ,
] ,
)
async def test_select_source_firetv ( hass , source , expected_arg , method_patch ) :
""" Test that an app can be launched for FireTV. """
conf_apps = {
" com.app.test1 " : " TEST 1 " ,
" com.app.test3 " : None ,
}
await _test_select_source (
hass , CONFIG_FIRETV_DEFAULT , conf_apps , source , expected_arg , method_patch
2020-01-29 12:13:09 -08:00
)
2022-01-14 02:05:35 +01:00
@pytest.mark.parametrize (
" config " ,
[
2022-05-03 00:18:38 +02:00
CONFIG_ANDROIDTV_DEFAULT ,
CONFIG_FIRETV_DEFAULT ,
2022-01-14 02:05:35 +01:00
] ,
)
async def test_setup_fail ( hass , config ) :
2019-12-15 02:31:59 -08:00
""" Test that the entity is not created when the ADB connection is not established. """
2021-12-20 20:08:35 +01:00
patch_key , entity_id , config_entry = _setup ( config )
config_entry . add_to_hass ( hass )
2019-12-15 02:31:59 -08:00
2022-05-03 00:18:38 +02:00
with patchers . patch_connect ( False ) [ patch_key ] , patchers . patch_shell (
SHELL_RESPONSE_OFF
) [ patch_key ] :
2022-02-06 23:15:50 +01:00
assert await hass . config_entries . async_setup ( config_entry . entry_id ) is False
await hass . async_block_till_done ( )
2022-02-04 11:13:08 -08:00
2022-03-25 23:22:58 +01:00
await async_update_entity ( hass , entity_id )
2019-12-15 02:31:59 -08:00
state = hass . states . get ( entity_id )
assert state is None
2020-01-06 14:10:13 -08:00
async def test_adb_command ( hass ) :
""" Test sending a command via the `androidtv.adb_command` service. """
2022-05-03 00:18:38 +02:00
patch_key , entity_id , config_entry = _setup ( CONFIG_ANDROIDTV_DEFAULT )
2021-12-20 20:08:35 +01:00
config_entry . add_to_hass ( hass )
2020-01-06 14:10:13 -08:00
command = " test command "
response = " test response "
2022-05-03 00:18:38 +02:00
with patchers . patch_connect ( True ) [ patch_key ] , patchers . patch_shell (
SHELL_RESPONSE_OFF
) [ patch_key ] :
2022-02-06 23:15:50 +01:00
assert await hass . config_entries . async_setup ( config_entry . entry_id )
await hass . async_block_till_done ( )
2020-01-06 14:10:13 -08:00
2021-12-20 20:08:35 +01:00
with patch (
" androidtv.basetv.basetv_async.BaseTVAsync.adb_shell " , return_value = response
) as patch_shell :
await hass . services . async_call (
DOMAIN ,
SERVICE_ADB_COMMAND ,
{ ATTR_ENTITY_ID : entity_id , ATTR_COMMAND : command } ,
blocking = True ,
)
2020-01-06 14:10:13 -08:00
2021-12-20 20:08:35 +01:00
patch_shell . assert_called_with ( command )
state = hass . states . get ( entity_id )
assert state is not None
assert state . attributes [ " adb_response " ] == response
2020-01-06 14:10:13 -08:00
2020-01-07 04:30:34 -08:00
async def test_adb_command_unicode_decode_error ( hass ) :
""" Test sending a command via the `androidtv.adb_command` service that raises a UnicodeDecodeError exception. """
2022-05-03 00:18:38 +02:00
patch_key , entity_id , config_entry = _setup ( CONFIG_ANDROIDTV_DEFAULT )
2021-12-20 20:08:35 +01:00
config_entry . add_to_hass ( hass )
2020-01-07 04:30:34 -08:00
command = " test command "
response = b " test response "
2022-05-03 00:18:38 +02:00
with patchers . patch_connect ( True ) [ patch_key ] , patchers . patch_shell (
SHELL_RESPONSE_OFF
) [ patch_key ] :
2022-02-06 23:15:50 +01:00
assert await hass . config_entries . async_setup ( config_entry . entry_id )
await hass . async_block_till_done ( )
2020-01-07 04:30:34 -08:00
2021-12-20 20:08:35 +01:00
with patch (
" androidtv.basetv.basetv_async.BaseTVAsync.adb_shell " ,
side_effect = UnicodeDecodeError ( " utf-8 " , response , 0 , len ( response ) , " TEST " ) ,
) :
await hass . services . async_call (
DOMAIN ,
SERVICE_ADB_COMMAND ,
{ ATTR_ENTITY_ID : entity_id , ATTR_COMMAND : command } ,
blocking = True ,
)
2020-01-07 04:30:34 -08:00
2021-12-20 20:08:35 +01:00
state = hass . states . get ( entity_id )
assert state is not None
assert state . attributes [ " adb_response " ] is None
2020-01-07 04:30:34 -08:00
2020-01-06 14:10:13 -08:00
async def test_adb_command_key ( hass ) :
""" Test sending a key command via the `androidtv.adb_command` service. """
2022-05-03 00:18:38 +02:00
patch_key , entity_id , config_entry = _setup ( CONFIG_ANDROIDTV_DEFAULT )
2021-12-20 20:08:35 +01:00
config_entry . add_to_hass ( hass )
2020-01-06 14:10:13 -08:00
command = " HOME "
response = None
2019-12-15 02:31:59 -08:00
2022-05-03 00:18:38 +02:00
with patchers . patch_connect ( True ) [ patch_key ] , patchers . patch_shell (
SHELL_RESPONSE_OFF
) [ patch_key ] :
2022-02-06 23:15:50 +01:00
assert await hass . config_entries . async_setup ( config_entry . entry_id )
await hass . async_block_till_done ( )
2019-12-15 02:31:59 -08:00
2021-12-20 20:08:35 +01:00
with patch (
" androidtv.basetv.basetv_async.BaseTVAsync.adb_shell " , return_value = response
) as patch_shell :
await hass . services . async_call (
DOMAIN ,
SERVICE_ADB_COMMAND ,
{ ATTR_ENTITY_ID : entity_id , ATTR_COMMAND : command } ,
blocking = True ,
)
2020-01-06 14:10:13 -08:00
2021-12-20 20:08:35 +01:00
patch_shell . assert_called_with ( f " input keyevent { KEYS [ command ] } " )
state = hass . states . get ( entity_id )
assert state is not None
assert state . attributes [ " adb_response " ] is None
2020-01-06 14:10:13 -08:00
async def test_adb_command_get_properties ( hass ) :
""" Test sending the " GET_PROPERTIES " command via the `androidtv.adb_command` service. """
2022-05-03 00:18:38 +02:00
patch_key , entity_id , config_entry = _setup ( CONFIG_ANDROIDTV_DEFAULT )
2021-12-20 20:08:35 +01:00
config_entry . add_to_hass ( hass )
2020-01-06 14:10:13 -08:00
command = " GET_PROPERTIES "
response = { " test key " : " test value " }
2022-05-03 00:18:38 +02:00
with patchers . patch_connect ( True ) [ patch_key ] , patchers . patch_shell (
SHELL_RESPONSE_OFF
) [ patch_key ] :
2022-02-06 23:15:50 +01:00
assert await hass . config_entries . async_setup ( config_entry . entry_id )
await hass . async_block_till_done ( )
2020-01-06 14:10:13 -08:00
2021-12-20 20:08:35 +01:00
with patch (
" androidtv.androidtv.androidtv_async.AndroidTVAsync.get_properties_dict " ,
return_value = response ,
) as patch_get_props :
await hass . services . async_call (
DOMAIN ,
SERVICE_ADB_COMMAND ,
{ ATTR_ENTITY_ID : entity_id , ATTR_COMMAND : command } ,
blocking = True ,
)
2020-01-06 14:10:13 -08:00
2021-12-20 20:08:35 +01:00
patch_get_props . assert_called ( )
state = hass . states . get ( entity_id )
assert state is not None
assert state . attributes [ " adb_response " ] == str ( response )
2020-01-06 14:10:13 -08:00
2020-06-29 18:17:04 -07:00
async def test_learn_sendevent ( hass ) :
""" Test the `androidtv.learn_sendevent` service. """
2022-05-03 00:18:38 +02:00
patch_key , entity_id , config_entry = _setup ( CONFIG_ANDROIDTV_DEFAULT )
2021-12-20 20:08:35 +01:00
config_entry . add_to_hass ( hass )
2020-06-29 18:17:04 -07:00
response = " sendevent 1 2 3 4 "
2022-05-03 00:18:38 +02:00
with patchers . patch_connect ( True ) [ patch_key ] , patchers . patch_shell (
SHELL_RESPONSE_OFF
) [ patch_key ] :
2022-02-06 23:15:50 +01:00
assert await hass . config_entries . async_setup ( config_entry . entry_id )
await hass . async_block_till_done ( )
2020-06-29 18:17:04 -07:00
with patch (
2020-07-05 12:13:08 -07:00
" androidtv.basetv.basetv_async.BaseTVAsync.learn_sendevent " ,
return_value = response ,
2020-06-29 18:17:04 -07:00
) as patch_learn_sendevent :
await hass . services . async_call (
2021-12-20 20:08:35 +01:00
DOMAIN ,
2020-06-29 18:17:04 -07:00
SERVICE_LEARN_SENDEVENT ,
{ ATTR_ENTITY_ID : entity_id } ,
blocking = True ,
)
patch_learn_sendevent . assert_called ( )
state = hass . states . get ( entity_id )
assert state is not None
assert state . attributes [ " adb_response " ] == response
2020-01-06 14:10:13 -08:00
async def test_update_lock_not_acquired ( hass ) :
""" Test that the state does not get updated when a `LockNotAcquiredException` is raised. """
2022-05-03 00:18:38 +02:00
patch_key , entity_id , config_entry = _setup ( CONFIG_ANDROIDTV_DEFAULT )
2021-12-20 20:08:35 +01:00
config_entry . add_to_hass ( hass )
2020-01-06 14:10:13 -08:00
2022-05-03 00:18:38 +02:00
with patchers . patch_connect ( True ) [ patch_key ] , patchers . patch_shell (
SHELL_RESPONSE_OFF
) [ patch_key ] :
2022-02-06 23:15:50 +01:00
assert await hass . config_entries . async_setup ( config_entry . entry_id )
await hass . async_block_till_done ( )
2020-01-06 14:10:13 -08:00
2020-07-05 12:13:08 -07:00
with patchers . patch_shell ( SHELL_RESPONSE_OFF ) [ patch_key ] :
2022-03-25 23:22:58 +01:00
await async_update_entity ( hass , entity_id )
2020-01-06 14:10:13 -08:00
state = hass . states . get ( entity_id )
assert state is not None
assert state . state == STATE_OFF
with patch (
2020-07-05 12:13:08 -07:00
" androidtv.androidtv.androidtv_async.AndroidTVAsync.update " ,
side_effect = LockNotAcquiredException ,
2021-03-27 09:17:15 +01:00
) , patchers . patch_shell ( SHELL_RESPONSE_STANDBY ) [ patch_key ] :
2022-03-25 23:22:58 +01:00
await async_update_entity ( hass , entity_id )
2021-03-27 09:17:15 +01:00
state = hass . states . get ( entity_id )
assert state is not None
assert state . state == STATE_OFF
2020-01-06 14:10:13 -08:00
2020-07-05 12:13:08 -07:00
with patchers . patch_shell ( SHELL_RESPONSE_STANDBY ) [ patch_key ] :
2022-03-25 23:22:58 +01:00
await async_update_entity ( hass , entity_id )
2020-01-06 14:10:13 -08:00
state = hass . states . get ( entity_id )
assert state is not None
2020-06-07 08:10:20 -07:00
assert state . state == STATE_STANDBY
2020-01-06 14:10:13 -08:00
async def test_download ( hass ) :
""" Test the `androidtv.download` service. """
2022-05-03 00:18:38 +02:00
patch_key , entity_id , config_entry = _setup ( CONFIG_ANDROIDTV_DEFAULT )
2021-12-20 20:08:35 +01:00
config_entry . add_to_hass ( hass )
2020-01-06 14:10:13 -08:00
device_path = " device/path "
local_path = " local/path "
2022-05-03 00:18:38 +02:00
with patchers . patch_connect ( True ) [ patch_key ] , patchers . patch_shell (
SHELL_RESPONSE_OFF
) [ patch_key ] :
2022-02-06 23:15:50 +01:00
assert await hass . config_entries . async_setup ( config_entry . entry_id )
await hass . async_block_till_done ( )
2020-01-06 14:10:13 -08:00
2021-12-20 20:08:35 +01:00
# Failed download because path is not whitelisted
with patch ( " androidtv.basetv.basetv_async.BaseTVAsync.adb_pull " ) as patch_pull :
await hass . services . async_call (
DOMAIN ,
SERVICE_DOWNLOAD ,
{
ATTR_ENTITY_ID : entity_id ,
ATTR_DEVICE_PATH : device_path ,
ATTR_LOCAL_PATH : local_path ,
} ,
blocking = True ,
)
patch_pull . assert_not_called ( )
2020-01-06 14:10:13 -08:00
2021-12-20 20:08:35 +01:00
# Successful download
with patch (
" androidtv.basetv.basetv_async.BaseTVAsync.adb_pull "
) as patch_pull , patch . object (
hass . config , " is_allowed_path " , return_value = True
) :
await hass . services . async_call (
DOMAIN ,
SERVICE_DOWNLOAD ,
{
ATTR_ENTITY_ID : entity_id ,
ATTR_DEVICE_PATH : device_path ,
ATTR_LOCAL_PATH : local_path ,
} ,
blocking = True ,
)
patch_pull . assert_called_with ( local_path , device_path )
2020-01-06 14:10:13 -08:00
async def test_upload ( hass ) :
""" Test the `androidtv.upload` service. """
2022-05-03 00:18:38 +02:00
patch_key , entity_id , config_entry = _setup ( CONFIG_ANDROIDTV_DEFAULT )
2021-12-20 20:08:35 +01:00
config_entry . add_to_hass ( hass )
2020-01-06 14:10:13 -08:00
device_path = " device/path "
local_path = " local/path "
2022-05-03 00:18:38 +02:00
with patchers . patch_connect ( True ) [ patch_key ] , patchers . patch_shell (
SHELL_RESPONSE_OFF
) [ patch_key ] :
2022-02-06 23:15:50 +01:00
assert await hass . config_entries . async_setup ( config_entry . entry_id )
await hass . async_block_till_done ( )
2020-01-06 14:10:13 -08:00
2021-12-20 20:08:35 +01:00
# Failed upload because path is not whitelisted
with patch ( " androidtv.basetv.basetv_async.BaseTVAsync.adb_push " ) as patch_push :
await hass . services . async_call (
DOMAIN ,
SERVICE_UPLOAD ,
{
ATTR_ENTITY_ID : entity_id ,
ATTR_DEVICE_PATH : device_path ,
ATTR_LOCAL_PATH : local_path ,
} ,
blocking = True ,
)
patch_push . assert_not_called ( )
2020-01-06 14:10:13 -08:00
2021-12-20 20:08:35 +01:00
# Successful upload
with patch (
" androidtv.basetv.basetv_async.BaseTVAsync.adb_push "
) as patch_push , patch . object (
hass . config , " is_allowed_path " , return_value = True
) :
await hass . services . async_call (
DOMAIN ,
SERVICE_UPLOAD ,
{
ATTR_ENTITY_ID : entity_id ,
ATTR_DEVICE_PATH : device_path ,
ATTR_LOCAL_PATH : local_path ,
} ,
blocking = True ,
)
patch_push . assert_called_with ( local_path , device_path )
2020-01-26 01:39:19 -08:00
async def test_androidtv_volume_set ( hass ) :
""" Test setting the volume for an Android TV device. """
2022-05-03 00:18:38 +02:00
patch_key , entity_id , config_entry = _setup ( CONFIG_ANDROIDTV_DEFAULT )
2021-12-20 20:08:35 +01:00
config_entry . add_to_hass ( hass )
2020-01-26 01:39:19 -08:00
2022-05-03 00:18:38 +02:00
with patchers . patch_connect ( True ) [ patch_key ] , patchers . patch_shell (
SHELL_RESPONSE_OFF
) [ patch_key ] :
2022-02-06 23:15:50 +01:00
assert await hass . config_entries . async_setup ( config_entry . entry_id )
await hass . async_block_till_done ( )
2020-01-26 01:39:19 -08:00
with patch (
2020-07-05 12:13:08 -07:00
" androidtv.basetv.basetv_async.BaseTVAsync.set_volume_level " , return_value = 0.5
2020-01-26 01:39:19 -08:00
) as patch_set_volume_level :
await hass . services . async_call (
2021-12-20 20:08:35 +01:00
MP_DOMAIN ,
2020-01-26 01:39:19 -08:00
SERVICE_VOLUME_SET ,
2020-07-05 12:13:08 -07:00
{ ATTR_ENTITY_ID : entity_id , ATTR_MEDIA_VOLUME_LEVEL : 0.5 } ,
2020-01-26 01:39:19 -08:00
blocking = True ,
)
patch_set_volume_level . assert_called_with ( 0.5 )
2020-04-15 02:41:19 +10:00
2022-07-20 12:08:11 +08:00
async def test_get_image_http ( hass , hass_client_no_auth ) :
2020-04-15 02:41:19 +10:00
""" Test taking a screen capture.
2022-07-20 12:08:11 +08:00
This is based on ` test_get_image_http ` in tests / components / media_player / test_init . py .
2020-04-15 02:41:19 +10:00
"""
2022-05-03 00:18:38 +02:00
patch_key , entity_id , config_entry = _setup ( CONFIG_ANDROIDTV_DEFAULT )
2021-12-20 20:08:35 +01:00
config_entry . add_to_hass ( hass )
2020-04-15 02:41:19 +10:00
2022-05-03 00:18:38 +02:00
with patchers . patch_connect ( True ) [ patch_key ] , patchers . patch_shell (
SHELL_RESPONSE_OFF
) [ patch_key ] :
2022-02-06 23:15:50 +01:00
assert await hass . config_entries . async_setup ( config_entry . entry_id )
await hass . async_block_till_done ( )
2020-04-15 02:41:19 +10:00
with patchers . patch_shell ( " 11 " ) [ patch_key ] :
2022-03-25 23:22:58 +01:00
await async_update_entity ( hass , entity_id )
2020-04-15 02:41:19 +10:00
2022-07-20 12:08:11 +08:00
media_player_name = " media_player. " + slugify (
CONFIG_ANDROIDTV_DEFAULT [ TEST_ENTITY_NAME ]
)
state = hass . states . get ( media_player_name )
assert " entity_picture_local " not in state . attributes
client = await hass_client_no_auth ( )
2020-04-15 02:41:19 +10:00
2020-07-05 12:13:08 -07:00
with patch (
" androidtv.basetv.basetv_async.BaseTVAsync.adb_screencap " , return_value = b " image "
) :
2022-07-20 12:08:11 +08:00
resp = await client . get ( state . attributes [ " entity_picture " ] )
content = await resp . read ( )
2020-04-15 02:41:19 +10:00
2022-07-20 12:08:11 +08:00
assert content == b " image "
2020-07-05 12:13:08 -07:00
2020-09-28 07:04:08 -07:00
with patch (
" androidtv.basetv.basetv_async.BaseTVAsync.adb_screencap " ,
2022-05-03 00:18:38 +02:00
side_effect = ConnectionResetError ,
2020-09-28 07:04:08 -07:00
) :
2022-07-20 12:08:11 +08:00
resp = await client . get ( state . attributes [ " entity_picture " ] )
2020-09-28 07:04:08 -07:00
2022-07-20 12:08:11 +08:00
# The device is unavailable, but getting the media image did not cause an exception
state = hass . states . get ( media_player_name )
assert state is not None
assert state . state == STATE_UNAVAILABLE
2020-09-28 07:04:08 -07:00
2020-07-05 12:13:08 -07:00
2022-07-20 12:08:11 +08:00
async def test_get_image_disabled ( hass ) :
""" Test that the screencap option can disable entity_picture. """
2022-05-03 00:18:38 +02:00
patch_key , entity_id , config_entry = _setup ( CONFIG_ANDROIDTV_DEFAULT )
config_entry . add_to_hass ( hass )
hass . config_entries . async_update_entry (
config_entry , options = { CONF_SCREENCAP : False }
)
with patchers . patch_connect ( True ) [ patch_key ] , patchers . patch_shell (
SHELL_RESPONSE_OFF
) [ patch_key ] :
assert await hass . config_entries . async_setup ( config_entry . entry_id )
await hass . async_block_till_done ( )
with patchers . patch_shell ( " 11 " ) [ patch_key ] :
await async_update_entity ( hass , entity_id )
2022-07-20 12:08:11 +08:00
media_player_name = " media_player. " + slugify (
CONFIG_ANDROIDTV_DEFAULT [ TEST_ENTITY_NAME ]
)
state = hass . states . get ( media_player_name )
assert " entity_picture_local " not in state . attributes
assert " entity_picture " not in state . attributes
2022-05-03 00:18:38 +02:00
2020-07-05 12:13:08 -07:00
async def _test_service (
hass ,
entity_id ,
ha_service_name ,
androidtv_method ,
additional_service_data = None ,
return_value = None ,
) :
""" Test generic Android TV media player entity service. """
service_data = { ATTR_ENTITY_ID : entity_id }
if additional_service_data :
service_data . update ( additional_service_data )
androidtv_patch = (
" androidtv.androidtv_async.AndroidTVAsync "
if " android " in entity_id
else " firetv.firetv_async.FireTVAsync "
)
with patch (
f " androidtv. { androidtv_patch } . { androidtv_method } " , return_value = return_value
) as service_call :
await hass . services . async_call (
2021-12-20 20:08:35 +01:00
MP_DOMAIN ,
2020-08-27 13:56:20 +02:00
ha_service_name ,
service_data = service_data ,
blocking = True ,
2020-07-05 12:13:08 -07:00
)
assert service_call . called
async def test_services_androidtv ( hass ) :
""" Test media player services for an Android TV device. """
2022-05-03 00:18:38 +02:00
patch_key , entity_id , config_entry = _setup ( CONFIG_ANDROIDTV_DEFAULT )
2021-12-20 20:08:35 +01:00
config_entry . add_to_hass ( hass )
2020-07-05 12:13:08 -07:00
2022-05-03 00:18:38 +02:00
with patchers . patch_connect ( True ) [ patch_key ] :
2020-07-05 12:13:08 -07:00
with patchers . patch_shell ( SHELL_RESPONSE_OFF ) [ patch_key ] :
2022-02-06 23:15:50 +01:00
assert await hass . config_entries . async_setup ( config_entry . entry_id )
await hass . async_block_till_done ( )
2020-07-05 12:13:08 -07:00
with patchers . patch_shell ( SHELL_RESPONSE_STANDBY ) [ patch_key ] :
await _test_service (
hass , entity_id , SERVICE_MEDIA_NEXT_TRACK , " media_next_track "
)
await _test_service ( hass , entity_id , SERVICE_MEDIA_PAUSE , " media_pause " )
await _test_service ( hass , entity_id , SERVICE_MEDIA_PLAY , " media_play " )
await _test_service (
hass , entity_id , SERVICE_MEDIA_PLAY_PAUSE , " media_play_pause "
)
await _test_service (
hass , entity_id , SERVICE_MEDIA_PREVIOUS_TRACK , " media_previous_track "
)
await _test_service ( hass , entity_id , SERVICE_MEDIA_STOP , " media_stop " )
await _test_service ( hass , entity_id , SERVICE_TURN_OFF , " turn_off " )
await _test_service ( hass , entity_id , SERVICE_TURN_ON , " turn_on " )
await _test_service (
hass , entity_id , SERVICE_VOLUME_DOWN , " volume_down " , return_value = 0.1
)
await _test_service (
hass ,
entity_id ,
SERVICE_VOLUME_SET ,
" set_volume_level " ,
{ ATTR_MEDIA_VOLUME_LEVEL : 0.5 } ,
0.5 ,
)
await _test_service (
hass , entity_id , SERVICE_VOLUME_UP , " volume_up " , return_value = 0.2
)
async def test_services_firetv ( hass ) :
""" Test media player services for a Fire TV device. """
2022-05-03 00:18:38 +02:00
patch_key , entity_id , config_entry = _setup ( CONFIG_FIRETV_DEFAULT )
2021-12-20 20:08:35 +01:00
config_entry . add_to_hass ( hass )
2022-05-03 00:18:38 +02:00
hass . config_entries . async_update_entry (
config_entry ,
options = {
CONF_TURN_OFF_COMMAND : " test off " ,
CONF_TURN_ON_COMMAND : " test on " ,
} ,
)
2020-07-05 12:13:08 -07:00
2022-05-03 00:18:38 +02:00
with patchers . patch_connect ( True ) [ patch_key ] :
2020-07-05 12:13:08 -07:00
with patchers . patch_shell ( SHELL_RESPONSE_OFF ) [ patch_key ] :
2022-02-06 23:15:50 +01:00
assert await hass . config_entries . async_setup ( config_entry . entry_id )
await hass . async_block_till_done ( )
2020-07-05 12:13:08 -07:00
with patchers . patch_shell ( SHELL_RESPONSE_STANDBY ) [ patch_key ] :
await _test_service ( hass , entity_id , SERVICE_MEDIA_STOP , " back " )
await _test_service ( hass , entity_id , SERVICE_TURN_OFF , " adb_shell " )
await _test_service ( hass , entity_id , SERVICE_TURN_ON , " adb_shell " )
2020-07-19 17:48:08 -07:00
2022-01-19 08:55:46 -08:00
async def test_volume_mute ( hass ) :
""" Test the volume mute service. """
2022-05-03 00:18:38 +02:00
patch_key , entity_id , config_entry = _setup ( CONFIG_ANDROIDTV_DEFAULT )
2022-01-19 08:55:46 -08:00
config_entry . add_to_hass ( hass )
2022-05-03 00:18:38 +02:00
with patchers . patch_connect ( True ) [ patch_key ] :
2022-01-19 08:55:46 -08:00
with patchers . patch_shell ( SHELL_RESPONSE_OFF ) [ patch_key ] :
2022-02-06 23:15:50 +01:00
assert await hass . config_entries . async_setup ( config_entry . entry_id )
await hass . async_block_till_done ( )
2022-01-19 08:55:46 -08:00
with patchers . patch_shell ( SHELL_RESPONSE_STANDBY ) [ patch_key ] :
service_data = { ATTR_ENTITY_ID : entity_id , ATTR_MEDIA_VOLUME_MUTED : True }
with patch (
" androidtv.androidtv.androidtv_async.AndroidTVAsync.mute_volume " ,
return_value = None ,
) as mute_volume :
# Don't send the mute key if the volume is already muted
with patch (
" androidtv.androidtv.androidtv_async.AndroidTVAsync.is_volume_muted " ,
return_value = True ,
) :
await hass . services . async_call (
MP_DOMAIN ,
SERVICE_VOLUME_MUTE ,
service_data = service_data ,
blocking = True ,
)
assert not mute_volume . called
# Send the mute key because the volume is not already muted
with patch (
" androidtv.androidtv.androidtv_async.AndroidTVAsync.is_volume_muted " ,
return_value = False ,
) :
await hass . services . async_call (
MP_DOMAIN ,
SERVICE_VOLUME_MUTE ,
service_data = service_data ,
blocking = True ,
)
assert mute_volume . called
2020-07-19 17:48:08 -07:00
async def test_connection_closed_on_ha_stop ( hass ) :
""" Test that the ADB socket connection is closed when HA stops. """
2022-05-03 00:18:38 +02:00
patch_key , _ , config_entry = _setup ( CONFIG_ANDROIDTV_DEFAULT )
2021-12-20 20:08:35 +01:00
config_entry . add_to_hass ( hass )
2020-07-19 17:48:08 -07:00
2022-05-03 00:18:38 +02:00
with patchers . patch_connect ( True ) [ patch_key ] , patchers . patch_shell (
SHELL_RESPONSE_OFF
) [ patch_key ] :
2022-02-06 23:15:50 +01:00
assert await hass . config_entries . async_setup ( config_entry . entry_id )
await hass . async_block_till_done ( )
2020-07-19 17:48:08 -07:00
2022-05-03 00:18:38 +02:00
with patch ( " androidtv.basetv.basetv_async.BaseTVAsync.adb_close " ) as adb_close :
2021-03-27 09:17:15 +01:00
hass . bus . async_fire ( EVENT_HOMEASSISTANT_STOP )
await hass . async_block_till_done ( )
assert adb_close . called
2020-08-29 19:56:25 -07:00
async def test_exception ( hass ) :
""" Test that the ADB connection gets closed when there is an unforeseen exception.
HA will attempt to reconnect on the next update .
"""
2022-05-03 00:18:38 +02:00
patch_key , entity_id , config_entry = _setup ( CONFIG_ANDROIDTV_DEFAULT )
2021-12-20 20:08:35 +01:00
config_entry . add_to_hass ( hass )
2020-08-29 19:56:25 -07:00
2022-05-03 00:18:38 +02:00
with patchers . patch_connect ( True ) [ patch_key ] , patchers . patch_shell (
SHELL_RESPONSE_OFF
) [ patch_key ] :
2022-02-06 23:15:50 +01:00
assert await hass . config_entries . async_setup ( config_entry . entry_id )
await hass . async_block_till_done ( )
2020-08-29 19:56:25 -07:00
2022-03-25 23:22:58 +01:00
await async_update_entity ( hass , entity_id )
2020-08-29 19:56:25 -07:00
state = hass . states . get ( entity_id )
assert state is not None
assert state . state == STATE_OFF
2022-01-17 09:28:28 -05:00
# When an unforeseen exception occurs, we close the ADB connection and raise the exception
2020-08-29 19:56:25 -07:00
with patchers . PATCH_ANDROIDTV_UPDATE_EXCEPTION , pytest . raises ( Exception ) :
2022-03-25 23:22:58 +01:00
await async_update_entity ( hass , entity_id )
2020-08-29 19:56:25 -07:00
state = hass . states . get ( entity_id )
assert state is not None
assert state . state == STATE_UNAVAILABLE
# On the next update, HA will reconnect to the device
2022-03-25 23:22:58 +01:00
await async_update_entity ( hass , entity_id )
2020-08-29 19:56:25 -07:00
state = hass . states . get ( entity_id )
assert state is not None
assert state . state == STATE_OFF
2022-05-03 00:18:38 +02:00
async def test_options_reload ( hass ) :
""" Test changing an option that will cause integration reload. """
patch_key , entity_id , config_entry = _setup ( CONFIG_ANDROIDTV_DEFAULT )
config_entry . add_to_hass ( hass )
with patchers . patch_connect ( True ) [ patch_key ] , patchers . patch_shell (
SHELL_RESPONSE_OFF
) [ patch_key ] :
assert await hass . config_entries . async_setup ( config_entry . entry_id )
await hass . async_block_till_done ( )
await async_update_entity ( hass , entity_id )
state = hass . states . get ( entity_id )
assert state is not None
assert state . state == STATE_OFF
with patchers . PATCH_SETUP_ENTRY as setup_entry_call :
# change an option that not require integration reload
hass . config_entries . async_update_entry (
config_entry , options = { CONF_SCREENCAP : False }
)
await hass . async_block_till_done ( )
assert not setup_entry_call . called
# change an option that require integration reload
hass . config_entries . async_update_entry (
config_entry , options = { CONF_STATE_DETECTION_RULES : { } }
)
await hass . async_block_till_done ( )
assert setup_entry_call . called
assert config_entry . state is ConfigEntryState . LOADED