Add tests for Roku (#34380)

This commit is contained in:
Chris Talkington 2020-04-18 17:23:55 -05:00 committed by GitHub
parent 3b12fd22a4
commit b3eba49a2f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 520 additions and 105 deletions

View file

@ -596,8 +596,6 @@ omit =
homeassistant/components/ring/camera.py homeassistant/components/ring/camera.py
homeassistant/components/ripple/sensor.py homeassistant/components/ripple/sensor.py
homeassistant/components/rocketchat/notify.py homeassistant/components/rocketchat/notify.py
homeassistant/components/roku/__init__.py
homeassistant/components/roku/media_player.py
homeassistant/components/roku/remote.py homeassistant/components/roku/remote.py
homeassistant/components/roomba/vacuum.py homeassistant/components/roomba/vacuum.py
homeassistant/components/route53/* homeassistant/components/route53/*

View file

@ -1,49 +1,59 @@
"""Tests for the Roku component.""" """Tests for the Roku component."""
from requests_mock import Mocker
from homeassistant.components.roku.const import DOMAIN from homeassistant.components.roku.const import DOMAIN
from homeassistant.const import CONF_HOST from homeassistant.const import CONF_HOST
from homeassistant.helpers.typing import HomeAssistantType from homeassistant.helpers.typing import HomeAssistantType
from tests.common import MockConfigEntry from tests.common import MockConfigEntry, load_fixture
HOST = "1.2.3.4" HOST = "192.168.1.160"
NAME = "Roku 3" NAME = "Roku 3"
SSDP_LOCATION = "http://1.2.3.4/" SSDP_LOCATION = "http://192.168.1.160/"
UPNP_FRIENDLY_NAME = "My Roku 3" UPNP_FRIENDLY_NAME = "My Roku 3"
UPNP_SERIAL = "1GU48T017973" UPNP_SERIAL = "1GU48T017973"
class MockDeviceInfo: def mock_connection(
"""Mock DeviceInfo for Roku.""" requests_mocker: Mocker, device: str = "roku3", app: str = "roku", host: str = HOST,
) -> None:
"""Mock the Roku connection."""
roku_url = f"http://{host}:8060"
model_name = NAME requests_mocker.get(
model_num = "4200X" f"{roku_url}/query/device-info",
software_version = "7.5.0.09021" text=load_fixture(f"roku/{device}-device-info.xml"),
serial_num = UPNP_SERIAL )
user_device_name = UPNP_FRIENDLY_NAME
roku_type = "Box"
def __repr__(self): apps_fixture = "roku/apps.xml"
"""Return the object representation of DeviceInfo.""" if device == "rokutv":
return "<DeviceInfo: {}-{}, SW v{}, Ser# {} ({})>".format( apps_fixture = "roku/apps-tv.xml"
self.model_name,
self.model_num, requests_mocker.get(
self.software_version, f"{roku_url}/query/apps", text=load_fixture(apps_fixture),
self.serial_num, )
self.roku_type,
requests_mocker.get(
f"{roku_url}/query/active-app", text=load_fixture(f"roku/active-app-{app}.xml"),
) )
async def setup_integration( async def setup_integration(
hass: HomeAssistantType, skip_entry_setup: bool = False hass: HomeAssistantType,
requests_mocker: Mocker,
device: str = "roku3",
app: str = "roku",
host: str = HOST,
unique_id: str = UPNP_SERIAL,
skip_entry_setup: bool = False,
) -> MockConfigEntry: ) -> MockConfigEntry:
"""Set up the Roku integration in Home Assistant.""" """Set up the Roku integration in Home Assistant."""
entry = MockConfigEntry( entry = MockConfigEntry(domain=DOMAIN, unique_id=unique_id, data={CONF_HOST: host})
domain=DOMAIN, unique_id=UPNP_SERIAL, data={CONF_HOST: HOST}
)
entry.add_to_hass(hass) entry.add_to_hass(hass)
if not skip_entry_setup: if not skip_entry_setup:
mock_connection(requests_mocker, device, app=app, host=host)
await hass.config_entries.async_setup(entry.entry_id) await hass.config_entries.async_setup(entry.entry_id)
await hass.async_block_till_done() await hass.async_block_till_done()

View file

@ -1,9 +1,9 @@
"""Test the Roku config flow.""" """Test the Roku config flow."""
from socket import gaierror as SocketGIAError from socket import gaierror as SocketGIAError
from typing import Any, Dict, Optional
from asynctest import patch from asynctest import patch
from requests.exceptions import RequestException from requests.exceptions import RequestException
from requests_mock import Mocker
from roku import RokuException from roku import RokuException
from homeassistant.components.roku.const import DOMAIN from homeassistant.components.roku.const import DOMAIN
@ -27,91 +27,74 @@ from tests.components.roku import (
SSDP_LOCATION, SSDP_LOCATION,
UPNP_FRIENDLY_NAME, UPNP_FRIENDLY_NAME,
UPNP_SERIAL, UPNP_SERIAL,
MockDeviceInfo, mock_connection,
setup_integration, setup_integration,
) )
async def async_configure_flow( async def test_duplicate_error(hass: HomeAssistantType, requests_mock: Mocker) -> None:
hass: HomeAssistantType, flow_id: str, user_input: Optional[Dict] = None
) -> Any:
"""Set up mock Roku integration flow."""
with patch(
"homeassistant.components.roku.config_flow.Roku.device_info",
new=MockDeviceInfo,
):
return await hass.config_entries.flow.async_configure(
flow_id=flow_id, user_input=user_input
)
async def async_init_flow(
hass: HomeAssistantType,
handler: str = DOMAIN,
context: Optional[Dict] = None,
data: Any = None,
) -> Any:
"""Set up mock Roku integration flow."""
with patch(
"homeassistant.components.roku.config_flow.Roku.device_info",
new=MockDeviceInfo,
):
return await hass.config_entries.flow.async_init(
handler=handler, context=context, data=data
)
async def test_duplicate_error(hass: HomeAssistantType) -> None:
"""Test that errors are shown when duplicates are added.""" """Test that errors are shown when duplicates are added."""
await setup_integration(hass, skip_entry_setup=True) await setup_integration(hass, requests_mock, skip_entry_setup=True)
result = await async_init_flow( mock_connection(requests_mock)
hass, context={CONF_SOURCE: SOURCE_IMPORT}, data={CONF_HOST: HOST}
user_input = {CONF_HOST: HOST}
result = await hass.config_entries.flow.async_init(
DOMAIN, context={CONF_SOURCE: SOURCE_IMPORT}, data=user_input
) )
assert result["type"] == RESULT_TYPE_ABORT assert result["type"] == RESULT_TYPE_ABORT
assert result["reason"] == "already_configured" assert result["reason"] == "already_configured"
result = await async_init_flow( user_input = {CONF_HOST: HOST}
hass, context={CONF_SOURCE: SOURCE_USER}, data={CONF_HOST: HOST} result = await hass.config_entries.flow.async_init(
DOMAIN, context={CONF_SOURCE: SOURCE_USER}, data=user_input
) )
assert result["type"] == RESULT_TYPE_ABORT assert result["type"] == RESULT_TYPE_ABORT
assert result["reason"] == "already_configured" assert result["reason"] == "already_configured"
result = await async_init_flow( discovery_info = {
hass,
context={CONF_SOURCE: SOURCE_SSDP},
data={
ATTR_UPNP_FRIENDLY_NAME: UPNP_FRIENDLY_NAME, ATTR_UPNP_FRIENDLY_NAME: UPNP_FRIENDLY_NAME,
ATTR_SSDP_LOCATION: SSDP_LOCATION, ATTR_SSDP_LOCATION: SSDP_LOCATION,
ATTR_UPNP_SERIAL: UPNP_SERIAL, ATTR_UPNP_SERIAL: UPNP_SERIAL,
}, }
result = await hass.config_entries.flow.async_init(
DOMAIN, context={CONF_SOURCE: SOURCE_SSDP}, data=discovery_info
) )
assert result["type"] == RESULT_TYPE_ABORT assert result["type"] == RESULT_TYPE_ABORT
assert result["reason"] == "already_configured" assert result["reason"] == "already_configured"
async def test_form(hass: HomeAssistantType) -> None: async def test_form(hass: HomeAssistantType, requests_mock: Mocker) -> None:
"""Test the user step.""" """Test the user step."""
await async_setup_component(hass, "persistent_notification", {}) await async_setup_component(hass, "persistent_notification", {})
mock_connection(requests_mock)
result = await hass.config_entries.flow.async_init( result = await hass.config_entries.flow.async_init(
DOMAIN, context={CONF_SOURCE: SOURCE_USER} DOMAIN, context={CONF_SOURCE: SOURCE_USER}
) )
assert result["type"] == RESULT_TYPE_FORM assert result["type"] == RESULT_TYPE_FORM
assert result["errors"] == {} assert result["errors"] == {}
user_input = {CONF_HOST: HOST}
with patch( with patch(
"homeassistant.components.roku.async_setup", return_value=True "homeassistant.components.roku.async_setup", return_value=True
) as mock_setup, patch( ) as mock_setup, patch(
"homeassistant.components.roku.async_setup_entry", return_value=True, "homeassistant.components.roku.async_setup_entry", return_value=True,
) as mock_setup_entry: ) as mock_setup_entry:
result = await async_configure_flow(hass, result["flow_id"], {CONF_HOST: HOST}) result = await hass.config_entries.flow.async_configure(
flow_id=result["flow_id"], user_input=user_input
)
assert result["type"] == RESULT_TYPE_CREATE_ENTRY assert result["type"] == RESULT_TYPE_CREATE_ENTRY
assert result["title"] == HOST assert result["title"] == HOST
assert result["data"] == {CONF_HOST: HOST}
assert result["data"]
assert result["data"][CONF_HOST] == HOST
await hass.async_block_till_done() await hass.async_block_till_done()
assert len(mock_setup.mock_calls) == 1 assert len(mock_setup.mock_calls) == 1
assert len(mock_setup_entry.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1
@ -144,12 +127,13 @@ async def test_form_cannot_connect_request(hass: HomeAssistantType) -> None:
DOMAIN, context={CONF_SOURCE: SOURCE_USER} DOMAIN, context={CONF_SOURCE: SOURCE_USER}
) )
user_input = {CONF_HOST: HOST}
with patch( with patch(
"homeassistant.components.roku.config_flow.Roku._call", "homeassistant.components.roku.config_flow.Roku._call",
side_effect=RequestException, side_effect=RequestException,
) as mock_validate_input: ) as mock_validate_input:
result = await hass.config_entries.flow.async_configure( result = await hass.config_entries.flow.async_configure(
flow_id=result["flow_id"], user_input={CONF_HOST: HOST} flow_id=result["flow_id"], user_input=user_input
) )
assert result["type"] == RESULT_TYPE_FORM assert result["type"] == RESULT_TYPE_FORM
@ -165,12 +149,13 @@ async def test_form_cannot_connect_socket(hass: HomeAssistantType) -> None:
DOMAIN, context={CONF_SOURCE: SOURCE_USER} DOMAIN, context={CONF_SOURCE: SOURCE_USER}
) )
user_input = {CONF_HOST: HOST}
with patch( with patch(
"homeassistant.components.roku.config_flow.Roku._call", "homeassistant.components.roku.config_flow.Roku._call",
side_effect=SocketGIAError, side_effect=SocketGIAError,
) as mock_validate_input: ) as mock_validate_input:
result = await hass.config_entries.flow.async_configure( result = await hass.config_entries.flow.async_configure(
flow_id=result["flow_id"], user_input={CONF_HOST: HOST} flow_id=result["flow_id"], user_input=user_input
) )
assert result["type"] == RESULT_TYPE_FORM assert result["type"] == RESULT_TYPE_FORM
@ -186,11 +171,12 @@ async def test_form_unknown_error(hass: HomeAssistantType) -> None:
DOMAIN, context={CONF_SOURCE: SOURCE_USER} DOMAIN, context={CONF_SOURCE: SOURCE_USER}
) )
user_input = {CONF_HOST: HOST}
with patch( with patch(
"homeassistant.components.roku.config_flow.Roku._call", side_effect=Exception, "homeassistant.components.roku.config_flow.Roku._call", side_effect=Exception,
) as mock_validate_input: ) as mock_validate_input:
result = await hass.config_entries.flow.async_configure( result = await hass.config_entries.flow.async_configure(
flow_id=result["flow_id"], user_input={CONF_HOST: HOST} flow_id=result["flow_id"], user_input=user_input
) )
assert result["type"] == RESULT_TYPE_ABORT assert result["type"] == RESULT_TYPE_ABORT
@ -200,36 +186,42 @@ async def test_form_unknown_error(hass: HomeAssistantType) -> None:
assert len(mock_validate_input.mock_calls) == 1 assert len(mock_validate_input.mock_calls) == 1
async def test_import(hass: HomeAssistantType) -> None: async def test_import(hass: HomeAssistantType, requests_mock: Mocker) -> None:
"""Test the import step.""" """Test the import step."""
mock_connection(requests_mock)
user_input = {CONF_HOST: HOST}
with patch( with patch(
"homeassistant.components.roku.async_setup", return_value=True "homeassistant.components.roku.async_setup", return_value=True
) as mock_setup, patch( ) as mock_setup, patch(
"homeassistant.components.roku.async_setup_entry", return_value=True, "homeassistant.components.roku.async_setup_entry", return_value=True,
) as mock_setup_entry: ) as mock_setup_entry:
result = await async_init_flow( result = await hass.config_entries.flow.async_init(
hass, context={CONF_SOURCE: SOURCE_IMPORT}, data={CONF_HOST: HOST} DOMAIN, context={CONF_SOURCE: SOURCE_IMPORT}, data=user_input
) )
assert result["type"] == RESULT_TYPE_CREATE_ENTRY assert result["type"] == RESULT_TYPE_CREATE_ENTRY
assert result["title"] == HOST assert result["title"] == HOST
assert result["data"] == {CONF_HOST: HOST}
assert result["data"]
assert result["data"][CONF_HOST] == HOST
await hass.async_block_till_done() await hass.async_block_till_done()
assert len(mock_setup.mock_calls) == 1 assert len(mock_setup.mock_calls) == 1
assert len(mock_setup_entry.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1
async def test_ssdp_discovery(hass: HomeAssistantType) -> None: async def test_ssdp_discovery(hass: HomeAssistantType, requests_mock: Mocker) -> None:
"""Test the ssdp discovery step.""" """Test the ssdp discovery step."""
result = await hass.config_entries.flow.async_init( mock_connection(requests_mock)
DOMAIN,
context={CONF_SOURCE: SOURCE_SSDP}, discovery_info = {
data={
ATTR_SSDP_LOCATION: SSDP_LOCATION, ATTR_SSDP_LOCATION: SSDP_LOCATION,
ATTR_UPNP_FRIENDLY_NAME: UPNP_FRIENDLY_NAME, ATTR_UPNP_FRIENDLY_NAME: UPNP_FRIENDLY_NAME,
ATTR_UPNP_SERIAL: UPNP_SERIAL, ATTR_UPNP_SERIAL: UPNP_SERIAL,
}, }
result = await hass.config_entries.flow.async_init(
DOMAIN, context={CONF_SOURCE: SOURCE_SSDP}, data=discovery_info
) )
assert result["type"] == RESULT_TYPE_FORM assert result["type"] == RESULT_TYPE_FORM
@ -241,14 +233,17 @@ async def test_ssdp_discovery(hass: HomeAssistantType) -> None:
) as mock_setup, patch( ) as mock_setup, patch(
"homeassistant.components.roku.async_setup_entry", return_value=True, "homeassistant.components.roku.async_setup_entry", return_value=True,
) as mock_setup_entry: ) as mock_setup_entry:
result = await async_configure_flow(hass, result["flow_id"], {}) result = await hass.config_entries.flow.async_configure(
flow_id=result["flow_id"], user_input={}
)
assert result["type"] == RESULT_TYPE_CREATE_ENTRY assert result["type"] == RESULT_TYPE_CREATE_ENTRY
assert result["title"] == UPNP_FRIENDLY_NAME assert result["title"] == UPNP_FRIENDLY_NAME
assert result["data"] == {
CONF_HOST: HOST, assert result["data"]
CONF_NAME: UPNP_FRIENDLY_NAME, assert result["data"][CONF_HOST] == HOST
} assert result["data"][CONF_NAME] == UPNP_FRIENDLY_NAME
await hass.async_block_till_done() await hass.async_block_till_done()
assert len(mock_setup.mock_calls) == 1 assert len(mock_setup.mock_calls) == 1
assert len(mock_setup_entry.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1

View file

@ -3,6 +3,7 @@ from socket import gaierror as SocketGIAError
from asynctest import patch from asynctest import patch
from requests.exceptions import RequestException from requests.exceptions import RequestException
from requests_mock import Mocker
from roku import RokuException from roku import RokuException
from homeassistant.components.roku.const import DOMAIN from homeassistant.components.roku.const import DOMAIN
@ -13,50 +14,56 @@ from homeassistant.config_entries import (
) )
from homeassistant.helpers.typing import HomeAssistantType from homeassistant.helpers.typing import HomeAssistantType
from tests.components.roku import MockDeviceInfo, setup_integration from tests.components.roku import setup_integration
async def test_config_entry_not_ready(hass: HomeAssistantType) -> None: async def test_config_entry_not_ready(
hass: HomeAssistantType, requests_mock: Mocker
) -> None:
"""Test the Roku configuration entry not ready.""" """Test the Roku configuration entry not ready."""
with patch( with patch(
"homeassistant.components.roku.Roku._call", side_effect=RokuException, "homeassistant.components.roku.Roku._call", side_effect=RokuException,
): ):
entry = await setup_integration(hass) entry = await setup_integration(hass, requests_mock)
assert entry.state == ENTRY_STATE_SETUP_RETRY assert entry.state == ENTRY_STATE_SETUP_RETRY
async def test_config_entry_not_ready_request(hass: HomeAssistantType) -> None: async def test_config_entry_not_ready_request(
hass: HomeAssistantType, requests_mock: Mocker
) -> None:
"""Test the Roku configuration entry not ready.""" """Test the Roku configuration entry not ready."""
with patch( with patch(
"homeassistant.components.roku.Roku._call", side_effect=RequestException, "homeassistant.components.roku.Roku._call", side_effect=RequestException,
): ):
entry = await setup_integration(hass) entry = await setup_integration(hass, requests_mock)
assert entry.state == ENTRY_STATE_SETUP_RETRY assert entry.state == ENTRY_STATE_SETUP_RETRY
async def test_config_entry_not_ready_socket(hass: HomeAssistantType) -> None: async def test_config_entry_not_ready_socket(
hass: HomeAssistantType, requests_mock: Mocker
) -> None:
"""Test the Roku configuration entry not ready.""" """Test the Roku configuration entry not ready."""
with patch( with patch(
"homeassistant.components.roku.Roku._call", side_effect=SocketGIAError, "homeassistant.components.roku.Roku._call", side_effect=SocketGIAError,
): ):
entry = await setup_integration(hass) entry = await setup_integration(hass, requests_mock)
assert entry.state == ENTRY_STATE_SETUP_RETRY assert entry.state == ENTRY_STATE_SETUP_RETRY
async def test_unload_config_entry(hass: HomeAssistantType) -> None: async def test_unload_config_entry(
hass: HomeAssistantType, requests_mock: Mocker
) -> None:
"""Test the Roku configuration entry unloading.""" """Test the Roku configuration entry unloading."""
with patch( with patch(
"homeassistant.components.roku.Roku.device_info", return_value=MockDeviceInfo,
), patch(
"homeassistant.components.roku.media_player.async_setup_entry", "homeassistant.components.roku.media_player.async_setup_entry",
return_value=True, return_value=True,
), patch( ), patch(
"homeassistant.components.roku.remote.async_setup_entry", return_value=True, "homeassistant.components.roku.remote.async_setup_entry", return_value=True,
): ):
entry = await setup_integration(hass) entry = await setup_integration(hass, requests_mock)
assert hass.data[DOMAIN][entry.entry_id] assert hass.data[DOMAIN][entry.entry_id]
assert entry.state == ENTRY_STATE_LOADED assert entry.state == ENTRY_STATE_LOADED

View file

@ -0,0 +1,258 @@
"""Tests for the Roku Media Player platform."""
from asynctest import patch
from requests_mock import Mocker
from homeassistant.components.media_player.const import (
ATTR_INPUT_SOURCE,
ATTR_MEDIA_CONTENT_ID,
ATTR_MEDIA_CONTENT_TYPE,
ATTR_MEDIA_VOLUME_MUTED,
DOMAIN as MP_DOMAIN,
MEDIA_TYPE_CHANNEL,
MEDIA_TYPE_MOVIE,
SERVICE_PLAY_MEDIA,
SERVICE_SELECT_SOURCE,
SUPPORT_NEXT_TRACK,
SUPPORT_PLAY,
SUPPORT_PLAY_MEDIA,
SUPPORT_PREVIOUS_TRACK,
SUPPORT_SELECT_SOURCE,
SUPPORT_TURN_OFF,
SUPPORT_TURN_ON,
SUPPORT_VOLUME_MUTE,
SUPPORT_VOLUME_SET,
)
from homeassistant.const import (
ATTR_ENTITY_ID,
SERVICE_MEDIA_NEXT_TRACK,
SERVICE_MEDIA_PREVIOUS_TRACK,
SERVICE_TURN_OFF,
SERVICE_TURN_ON,
SERVICE_VOLUME_DOWN,
SERVICE_VOLUME_MUTE,
SERVICE_VOLUME_UP,
STATE_PLAYING,
)
from homeassistant.helpers.typing import HomeAssistantType
from tests.components.roku import UPNP_SERIAL, setup_integration
MAIN_ENTITY_ID = f"{MP_DOMAIN}.my_roku_3"
TV_ENTITY_ID = f"{MP_DOMAIN}.58_onn_roku_tv"
TV_HOST = "192.168.1.161"
TV_SERIAL = "YN00H5555555"
async def test_setup(hass: HomeAssistantType, requests_mock: Mocker) -> None:
"""Test setup with basic config."""
await setup_integration(hass, requests_mock)
await setup_integration(
hass,
requests_mock,
device="rokutv",
app="tvinput-dtv",
host=TV_HOST,
unique_id=TV_SERIAL,
)
entity_registry = await hass.helpers.entity_registry.async_get_registry()
main = entity_registry.async_get(MAIN_ENTITY_ID)
assert hass.states.get(MAIN_ENTITY_ID)
assert main.unique_id == UPNP_SERIAL
tv = entity_registry.async_get(TV_ENTITY_ID)
assert hass.states.get(TV_ENTITY_ID)
assert tv.unique_id == TV_SERIAL
async def test_supported_features(
hass: HomeAssistantType, requests_mock: Mocker
) -> None:
"""Test supported features."""
await setup_integration(hass, requests_mock)
# Features supported for Rokus
state = hass.states.get(MAIN_ENTITY_ID)
assert (
SUPPORT_PREVIOUS_TRACK
| SUPPORT_NEXT_TRACK
| SUPPORT_VOLUME_SET
| SUPPORT_VOLUME_MUTE
| SUPPORT_SELECT_SOURCE
| SUPPORT_PLAY
| SUPPORT_PLAY_MEDIA
| SUPPORT_TURN_ON
| SUPPORT_TURN_OFF
== state.attributes.get("supported_features")
)
async def test_tv_supported_features(
hass: HomeAssistantType, requests_mock: Mocker
) -> None:
"""Test supported features for Roku TV."""
await setup_integration(
hass,
requests_mock,
device="rokutv",
app="tvinput-dtv",
host=TV_HOST,
unique_id=TV_SERIAL,
)
state = hass.states.get(TV_ENTITY_ID)
assert (
SUPPORT_PREVIOUS_TRACK
| SUPPORT_NEXT_TRACK
| SUPPORT_VOLUME_SET
| SUPPORT_VOLUME_MUTE
| SUPPORT_SELECT_SOURCE
| SUPPORT_PLAY
| SUPPORT_PLAY_MEDIA
| SUPPORT_TURN_ON
| SUPPORT_TURN_OFF
== state.attributes.get("supported_features")
)
async def test_attributes(hass: HomeAssistantType, requests_mock: Mocker) -> None:
"""Test attributes."""
await setup_integration(hass, requests_mock)
state = hass.states.get(MAIN_ENTITY_ID)
assert state.state == "home"
assert state.attributes.get(ATTR_MEDIA_CONTENT_TYPE) is None
assert state.attributes.get(ATTR_INPUT_SOURCE) == "Roku"
async def test_tv_attributes(hass: HomeAssistantType, requests_mock: Mocker) -> None:
"""Test attributes for Roku TV."""
await setup_integration(
hass,
requests_mock,
device="rokutv",
app="tvinput-dtv",
host=TV_HOST,
unique_id=TV_SERIAL,
)
state = hass.states.get(TV_ENTITY_ID)
assert state.state == STATE_PLAYING
assert state.attributes.get(ATTR_MEDIA_CONTENT_TYPE) == MEDIA_TYPE_MOVIE
assert state.attributes.get(ATTR_INPUT_SOURCE) == "Antenna TV"
async def test_services(hass: HomeAssistantType, requests_mock: Mocker) -> None:
"""Test the different media player services."""
await setup_integration(hass, requests_mock)
with patch("roku.Roku._post") as remote_mock:
await hass.services.async_call(
MP_DOMAIN, SERVICE_TURN_OFF, {ATTR_ENTITY_ID: MAIN_ENTITY_ID}, blocking=True
)
remote_mock.assert_called_once_with("/keypress/PowerOff")
with patch("roku.Roku._post") as remote_mock:
await hass.services.async_call(
MP_DOMAIN, SERVICE_TURN_ON, {ATTR_ENTITY_ID: MAIN_ENTITY_ID}, blocking=True
)
remote_mock.assert_called_once_with("/keypress/PowerOn")
with patch("roku.Roku._post") as remote_mock:
await hass.services.async_call(
MP_DOMAIN,
SERVICE_MEDIA_NEXT_TRACK,
{ATTR_ENTITY_ID: MAIN_ENTITY_ID},
blocking=True,
)
remote_mock.assert_called_once_with("/keypress/Fwd")
with patch("roku.Roku._post") as remote_mock:
await hass.services.async_call(
MP_DOMAIN,
SERVICE_MEDIA_PREVIOUS_TRACK,
{ATTR_ENTITY_ID: MAIN_ENTITY_ID},
blocking=True,
)
remote_mock.assert_called_once_with("/keypress/Rev")
with patch("roku.Roku._post") as remote_mock:
await hass.services.async_call(
MP_DOMAIN,
SERVICE_SELECT_SOURCE,
{ATTR_ENTITY_ID: MAIN_ENTITY_ID, ATTR_INPUT_SOURCE: "Home"},
blocking=True,
)
remote_mock.assert_called_once_with("/keypress/Home")
with patch("roku.Roku._post") as remote_mock:
await hass.services.async_call(
MP_DOMAIN,
SERVICE_SELECT_SOURCE,
{ATTR_ENTITY_ID: MAIN_ENTITY_ID, ATTR_INPUT_SOURCE: "Netflix"},
blocking=True,
)
remote_mock.assert_called_once_with("/launch/12", params={"contentID": "12"})
async def test_tv_services(hass: HomeAssistantType, requests_mock: Mocker) -> None:
"""Test the media player services related to Roku TV."""
await setup_integration(
hass,
requests_mock,
device="rokutv",
app="tvinput-dtv",
host=TV_HOST,
unique_id=TV_SERIAL,
)
with patch("roku.Roku._post") as remote_mock:
await hass.services.async_call(
MP_DOMAIN, SERVICE_VOLUME_UP, {ATTR_ENTITY_ID: TV_ENTITY_ID}, blocking=True
)
remote_mock.assert_called_once_with("/keypress/VolumeUp")
with patch("roku.Roku._post") as remote_mock:
await hass.services.async_call(
MP_DOMAIN,
SERVICE_VOLUME_DOWN,
{ATTR_ENTITY_ID: TV_ENTITY_ID},
blocking=True,
)
remote_mock.assert_called_once_with("/keypress/VolumeDown")
with patch("roku.Roku._post") as remote_mock:
await hass.services.async_call(
MP_DOMAIN,
SERVICE_VOLUME_MUTE,
{ATTR_ENTITY_ID: TV_ENTITY_ID, ATTR_MEDIA_VOLUME_MUTED: True},
blocking=True,
)
remote_mock.assert_called_once_with("/keypress/VolumeMute")
with patch("roku.Roku.launch") as tune_mock:
await hass.services.async_call(
MP_DOMAIN,
SERVICE_PLAY_MEDIA,
{
ATTR_ENTITY_ID: TV_ENTITY_ID,
ATTR_MEDIA_CONTENT_TYPE: MEDIA_TYPE_CHANNEL,
ATTR_MEDIA_CONTENT_ID: "55",
},
blocking=True,
)
tune_mock.assert_called_once()

View file

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8" ?>
<active-app>
<app id="12" type="appl" version="4.1.218">Netflix</app>
</active-app>

View file

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8" ?>
<active-app>
<app>Roku</app>
</active-app>

View file

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
<active-app>
<app>Roku</app>
<screensaver id="55545" type="ssvr" version="2.0.1">Default screensaver</screensaver>
</active-app>

View file

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8" ?>
<active-app>
<app id="tvinput.dtv" type="tvin" version="1.0.0">Antenna TV</app>
</active-app>

13
tests/fixtures/roku/apps-tv.xml vendored Normal file
View file

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8" ?>
<apps>
<app id="tvinput.hdmi2" type="tvin" version="1.0.0">Satellite TV</app>
<app id="tvinput.hdmi1" type="tvin" version="1.0.0">Blu-ray player</app>
<app id="tvinput.dtv" type="tvin" version="1.0.0">Antenna TV</app>
<app id="11">Roku Channel Store</app>
<app id="12">Netflix</app>
<app id="13">Amazon Video on Demand</app>
<app id="14">MLB.TV®</app>
<app id="26">Free FrameChannel Service</app>
<app id="27">Mediafly</app>
<app id="28">Pandora</app>
</apps>

10
tests/fixtures/roku/apps.xml vendored Normal file
View file

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8" ?>
<apps>
<app id="11">Roku Channel Store</app>
<app id="12">Netflix</app>
<app id="13">Amazon Video on Demand</app>
<app id="14">MLB.TV®</app>
<app id="26">Free FrameChannel Service</app>
<app id="27">Mediafly</app>
<app id="28">Pandora</app>
</apps>

View file

@ -0,0 +1,35 @@
<?xml version="1.0" encoding="UTF-8" ?>
<device-info>
<udn>015e5108-9000-1046-8035-b0a737964dfb</udn>
<serial-number>1GU48T017973</serial-number>
<device-id>1GU48T017973</device-id>
<vendor-name>Roku</vendor-name>
<model-number>4200X</model-number>
<model-name>Roku 3</model-name>
<model-region>US</model-region>
<supports-ethernet>true</supports-ethernet>
<wifi-mac>b0:a7:37:96:4d:fb</wifi-mac>
<ethernet-mac>b0:a7:37:96:4d:fa</ethernet-mac>
<network-type>ethernet</network-type>
<user-device-name>My Roku 3</user-device-name>
<software-version>7.5.0</software-version>
<software-build>09021</software-build>
<secure-device>true</secure-device>
<language>en</language>
<country>US</country>
<locale>en_US</locale>
<time-zone>US/Pacific</time-zone>
<time-zone-offset>-480</time-zone-offset>
<power-mode>PowerOn</power-mode>
<supports-suspend>false</supports-suspend>
<supports-find-remote>false</supports-find-remote>
<supports-audio-guide>false</supports-audio-guide>
<developer-enabled>true</developer-enabled>
<keyed-developer-id>70f6ed9c90cf60718a26f3a7c3e5af1c3ec29558</keyed-developer-id>
<search-enabled>true</search-enabled>
<voice-search-enabled>true</voice-search-enabled>
<notifications-enabled>true</notifications-enabled>
<notifications-first-use>false</notifications-first-use>
<supports-private-listening>false</supports-private-listening>
<headphones-connected>false</headphones-connected>
</device-info>

View file

@ -0,0 +1,72 @@
<?xml version="1.0" encoding="UTF-8" ?>
<device-info>
<udn>015e5555-9000-5555-5555-b0a555555dfb</udn>
<serial-number>YN00H5555555</serial-number>
<device-id>0S596H055555</device-id>
<advertising-id>055555a9-d82b-5c75-b8fe-5555550cb7ee</advertising-id>
<vendor-name>Onn</vendor-name>
<model-name>100005844</model-name>
<model-number>7820X</model-number>
<model-region>US</model-region>
<is-tv>true</is-tv>
<is-stick>false</is-stick>
<screen-size>58</screen-size>
<panel-id>2</panel-id>
<tuner-type>ATSC</tuner-type>
<supports-ethernet>true</supports-ethernet>
<wifi-mac>d8:13:99:f8:b0:c6</wifi-mac>
<wifi-driver>realtek</wifi-driver>
<ethernet-mac>d4:3a:2e:07:fd:cb</ethernet-mac>
<network-type>wifi</network-type>
<network-name>NetworkSSID</network-name>
<friendly-device-name>58" Onn Roku TV</friendly-device-name>
<friendly-model-name>Onn Roku TV</friendly-model-name>
<default-device-name>Onn Roku TV - YN00H5555555</default-device-name>
<user-device-name>58" Onn Roku TV</user-device-name>
<user-device-location>Living room</user-device-location>
<build-number>AT9.20E04502A</build-number>
<software-version>9.2.0</software-version>
<software-build>4502</software-build>
<secure-device>true</secure-device>
<language>en</language>
<country>US</country>
<locale>en_US</locale>
<time-zone-auto>true</time-zone-auto>
<time-zone>US/Central</time-zone>
<time-zone-name>United States/Central</time-zone-name>
<time-zone-tz>America/Chicago</time-zone-tz>
<time-zone-offset>-300</time-zone-offset>
<clock-format>12-hour</clock-format>
<uptime>264789</uptime>
<power-mode>PowerOn</power-mode>
<supports-suspend>true</supports-suspend>
<supports-find-remote>true</supports-find-remote>
<find-remote-is-possible>false</find-remote-is-possible>
<supports-audio-guide>true</supports-audio-guide>
<supports-rva>true</supports-rva>
<developer-enabled>false</developer-enabled>
<keyed-developer-id/>
<search-enabled>true</search-enabled>
<search-channels-enabled>true</search-channels-enabled>
<voice-search-enabled>true</voice-search-enabled>
<notifications-enabled>true</notifications-enabled>
<notifications-first-use>false</notifications-first-use>
<supports-private-listening>true</supports-private-listening>
<supports-private-listening-dtv>true</supports-private-listening-dtv>
<supports-warm-standby>true</supports-warm-standby>
<headphones-connected>false</headphones-connected>
<expert-pq-enabled>0.9</expert-pq-enabled>
<supports-ecs-textedit>true</supports-ecs-textedit>
<supports-ecs-microphone>true</supports-ecs-microphone>
<supports-wake-on-wlan>true</supports-wake-on-wlan>
<has-play-on-roku>true</has-play-on-roku>
<has-mobile-screensaver>true</has-mobile-screensaver>
<support-url>https://www.onntvsupport.com/</support-url>
<grandcentral-version>2.9.57</grandcentral-version>
<trc-version>3.0</trc-version>
<trc-channel-version>2.9.42</trc-channel-version>
<davinci-version>2.8.20</davinci-version>
<has-wifi-extender>false</has-wifi-extender>
<has-wifi-5G-support>true</has-wifi-5G-support>
<can-use-wifi-extender>true</can-use-wifi-extender>
</device-info>