Add tests for Roku (#34380)

pull/34408/head
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/ripple/sensor.py
homeassistant/components/rocketchat/notify.py
homeassistant/components/roku/__init__.py
homeassistant/components/roku/media_player.py
homeassistant/components/roku/remote.py
homeassistant/components/roomba/vacuum.py
homeassistant/components/route53/*

View File

@ -1,49 +1,59 @@
"""Tests for the Roku component."""
from requests_mock import Mocker
from homeassistant.components.roku.const import DOMAIN
from homeassistant.const import CONF_HOST
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"
SSDP_LOCATION = "http://1.2.3.4/"
SSDP_LOCATION = "http://192.168.1.160/"
UPNP_FRIENDLY_NAME = "My Roku 3"
UPNP_SERIAL = "1GU48T017973"
class MockDeviceInfo:
"""Mock DeviceInfo for Roku."""
def mock_connection(
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
model_num = "4200X"
software_version = "7.5.0.09021"
serial_num = UPNP_SERIAL
user_device_name = UPNP_FRIENDLY_NAME
roku_type = "Box"
requests_mocker.get(
f"{roku_url}/query/device-info",
text=load_fixture(f"roku/{device}-device-info.xml"),
)
def __repr__(self):
"""Return the object representation of DeviceInfo."""
return "<DeviceInfo: {}-{}, SW v{}, Ser# {} ({})>".format(
self.model_name,
self.model_num,
self.software_version,
self.serial_num,
self.roku_type,
apps_fixture = "roku/apps.xml"
if device == "rokutv":
apps_fixture = "roku/apps-tv.xml"
requests_mocker.get(
f"{roku_url}/query/apps", text=load_fixture(apps_fixture),
)
requests_mocker.get(
f"{roku_url}/query/active-app", text=load_fixture(f"roku/active-app-{app}.xml"),
)
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:
"""Set up the Roku integration in Home Assistant."""
entry = MockConfigEntry(
domain=DOMAIN, unique_id=UPNP_SERIAL, data={CONF_HOST: HOST}
)
entry = MockConfigEntry(domain=DOMAIN, unique_id=unique_id, data={CONF_HOST: host})
entry.add_to_hass(hass)
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.async_block_till_done()

View File

@ -1,9 +1,9 @@
"""Test the Roku config flow."""
from socket import gaierror as SocketGIAError
from typing import Any, Dict, Optional
from asynctest import patch
from requests.exceptions import RequestException
from requests_mock import Mocker
from roku import RokuException
from homeassistant.components.roku.const import DOMAIN
@ -27,91 +27,74 @@ from tests.components.roku import (
SSDP_LOCATION,
UPNP_FRIENDLY_NAME,
UPNP_SERIAL,
MockDeviceInfo,
mock_connection,
setup_integration,
)
async def async_configure_flow(
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:
async def test_duplicate_error(hass: HomeAssistantType, requests_mock: Mocker) -> None:
"""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(
hass, context={CONF_SOURCE: SOURCE_IMPORT}, data={CONF_HOST: HOST}
mock_connection(requests_mock)
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["reason"] == "already_configured"
result = await async_init_flow(
hass, context={CONF_SOURCE: SOURCE_USER}, data={CONF_HOST: HOST}
user_input = {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["reason"] == "already_configured"
result = await async_init_flow(
hass,
context={CONF_SOURCE: SOURCE_SSDP},
data={
discovery_info = {
ATTR_UPNP_FRIENDLY_NAME: UPNP_FRIENDLY_NAME,
ATTR_SSDP_LOCATION: SSDP_LOCATION,
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["reason"] == "already_configured"
async def test_form(hass: HomeAssistantType) -> None:
async def test_form(hass: HomeAssistantType, requests_mock: Mocker) -> None:
"""Test the user step."""
await async_setup_component(hass, "persistent_notification", {})
mock_connection(requests_mock)
result = await hass.config_entries.flow.async_init(
DOMAIN, context={CONF_SOURCE: SOURCE_USER}
)
assert result["type"] == RESULT_TYPE_FORM
assert result["errors"] == {}
user_input = {CONF_HOST: HOST}
with patch(
"homeassistant.components.roku.async_setup", return_value=True
) as mock_setup, patch(
"homeassistant.components.roku.async_setup_entry", return_value=True,
) 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["title"] == HOST
assert result["data"] == {CONF_HOST: HOST}
assert result["data"]
assert result["data"][CONF_HOST] == HOST
await hass.async_block_till_done()
assert len(mock_setup.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}
)
user_input = {CONF_HOST: HOST}
with patch(
"homeassistant.components.roku.config_flow.Roku._call",
side_effect=RequestException,
) as mock_validate_input:
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
@ -165,12 +149,13 @@ async def test_form_cannot_connect_socket(hass: HomeAssistantType) -> None:
DOMAIN, context={CONF_SOURCE: SOURCE_USER}
)
user_input = {CONF_HOST: HOST}
with patch(
"homeassistant.components.roku.config_flow.Roku._call",
side_effect=SocketGIAError,
) as mock_validate_input:
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
@ -186,11 +171,12 @@ async def test_form_unknown_error(hass: HomeAssistantType) -> None:
DOMAIN, context={CONF_SOURCE: SOURCE_USER}
)
user_input = {CONF_HOST: HOST}
with patch(
"homeassistant.components.roku.config_flow.Roku._call", side_effect=Exception,
) as mock_validate_input:
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
@ -200,36 +186,42 @@ async def test_form_unknown_error(hass: HomeAssistantType) -> None:
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."""
mock_connection(requests_mock)
user_input = {CONF_HOST: HOST}
with patch(
"homeassistant.components.roku.async_setup", return_value=True
) as mock_setup, patch(
"homeassistant.components.roku.async_setup_entry", return_value=True,
) as mock_setup_entry:
result = await async_init_flow(
hass, context={CONF_SOURCE: SOURCE_IMPORT}, data={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_CREATE_ENTRY
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()
assert len(mock_setup.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."""
result = await hass.config_entries.flow.async_init(
DOMAIN,
context={CONF_SOURCE: SOURCE_SSDP},
data={
mock_connection(requests_mock)
discovery_info = {
ATTR_SSDP_LOCATION: SSDP_LOCATION,
ATTR_UPNP_FRIENDLY_NAME: UPNP_FRIENDLY_NAME,
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
@ -241,14 +233,17 @@ async def test_ssdp_discovery(hass: HomeAssistantType) -> None:
) as mock_setup, patch(
"homeassistant.components.roku.async_setup_entry", return_value=True,
) 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["title"] == UPNP_FRIENDLY_NAME
assert result["data"] == {
CONF_HOST: HOST,
CONF_NAME: UPNP_FRIENDLY_NAME,
}
assert result["data"]
assert result["data"][CONF_HOST] == HOST
assert result["data"][CONF_NAME] == UPNP_FRIENDLY_NAME
await hass.async_block_till_done()
assert len(mock_setup.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 requests.exceptions import RequestException
from requests_mock import Mocker
from roku import RokuException
from homeassistant.components.roku.const import DOMAIN
@ -13,50 +14,56 @@ from homeassistant.config_entries import (
)
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."""
with patch(
"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
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."""
with patch(
"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
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."""
with patch(
"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
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."""
with patch(
"homeassistant.components.roku.Roku.device_info", return_value=MockDeviceInfo,
), patch(
"homeassistant.components.roku.media_player.async_setup_entry",
return_value=True,
), patch(
"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 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>