Refactor roku tests (#64498)

This commit is contained in:
Chris Talkington 2022-01-22 14:31:34 -06:00 committed by GitHub
parent 9d39a38c16
commit 9639968a96
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
32 changed files with 1305 additions and 1036 deletions

View File

@ -1,16 +1,6 @@
"""Tests for the Roku component."""
from http import HTTPStatus
import re
from socket import gaierror as SocketGIAError
from homeassistant.components import ssdp, zeroconf
from homeassistant.components.roku.const import DOMAIN
from homeassistant.components.ssdp import ATTR_UPNP_FRIENDLY_NAME, ATTR_UPNP_SERIAL
from homeassistant.const import CONF_HOST
from homeassistant.core import HomeAssistant
from tests.common import MockConfigEntry, load_fixture
from tests.test_util.aiohttp import AiohttpClientMocker
NAME = "Roku 3"
NAME_ROKUTV = '58" Onn Roku TV'
@ -42,174 +32,3 @@ MOCK_HOMEKIT_DISCOVERY_INFO = zeroconf.ZeroconfServiceInfo(
},
type="mock_type",
)
def mock_connection(
aioclient_mock: AiohttpClientMocker,
device: str = "roku3",
app: str = "roku",
host: str = HOST,
power: bool = True,
media_state: str = "close",
error: bool = False,
server_error: bool = False,
) -> None:
"""Mock the Roku connection."""
roku_url = f"http://{host}:8060"
if error:
mock_connection_error(
aioclient_mock=aioclient_mock, device=device, app=app, host=host
)
return
if server_error:
mock_connection_server_error(
aioclient_mock=aioclient_mock, device=device, app=app, host=host
)
return
info_fixture = f"roku/{device}-device-info.xml"
if not power:
info_fixture = f"roku/{device}-device-info-power-off.xml"
aioclient_mock.get(
f"{roku_url}/query/device-info",
text=load_fixture(info_fixture),
headers={"Content-Type": "text/xml"},
)
apps_fixture = "roku/apps.xml"
if device == "rokutv":
apps_fixture = "roku/apps-tv.xml"
aioclient_mock.get(
f"{roku_url}/query/apps",
text=load_fixture(apps_fixture),
headers={"Content-Type": "text/xml"},
)
aioclient_mock.get(
f"{roku_url}/query/active-app",
text=load_fixture(f"roku/active-app-{app}.xml"),
headers={"Content-Type": "text/xml"},
)
aioclient_mock.get(
f"{roku_url}/query/tv-active-channel",
text=load_fixture("roku/rokutv-tv-active-channel.xml"),
headers={"Content-Type": "text/xml"},
)
aioclient_mock.get(
f"{roku_url}/query/tv-channels",
text=load_fixture("roku/rokutv-tv-channels.xml"),
headers={"Content-Type": "text/xml"},
)
aioclient_mock.get(
f"{roku_url}/query/media-player",
text=load_fixture(f"roku/media-player-{media_state}.xml"),
headers={"Content-Type": "text/xml"},
)
aioclient_mock.post(
re.compile(f"{roku_url}/keypress/.*"),
text="OK",
)
aioclient_mock.post(
re.compile(f"{roku_url}/launch/.*"),
text="OK",
)
aioclient_mock.post(f"{roku_url}/search", text="OK")
def mock_connection_error(
aioclient_mock: AiohttpClientMocker,
device: str = "roku3",
app: str = "roku",
host: str = HOST,
) -> None:
"""Mock the Roku connection error."""
roku_url = f"http://{host}:8060"
aioclient_mock.get(f"{roku_url}/query/device-info", exc=SocketGIAError)
aioclient_mock.get(f"{roku_url}/query/apps", exc=SocketGIAError)
aioclient_mock.get(f"{roku_url}/query/active-app", exc=SocketGIAError)
aioclient_mock.get(f"{roku_url}/query/tv-active-channel", exc=SocketGIAError)
aioclient_mock.get(f"{roku_url}/query/tv-channels", exc=SocketGIAError)
aioclient_mock.post(re.compile(f"{roku_url}/keypress/.*"), exc=SocketGIAError)
aioclient_mock.post(re.compile(f"{roku_url}/launch/.*"), exc=SocketGIAError)
aioclient_mock.post(f"{roku_url}/search", exc=SocketGIAError)
def mock_connection_server_error(
aioclient_mock: AiohttpClientMocker,
device: str = "roku3",
app: str = "roku",
host: str = HOST,
) -> None:
"""Mock the Roku server error."""
roku_url = f"http://{host}:8060"
aioclient_mock.get(
f"{roku_url}/query/device-info", status=HTTPStatus.INTERNAL_SERVER_ERROR
)
aioclient_mock.get(
f"{roku_url}/query/apps", status=HTTPStatus.INTERNAL_SERVER_ERROR
)
aioclient_mock.get(
f"{roku_url}/query/active-app", status=HTTPStatus.INTERNAL_SERVER_ERROR
)
aioclient_mock.get(
f"{roku_url}/query/tv-active-channel", status=HTTPStatus.INTERNAL_SERVER_ERROR
)
aioclient_mock.get(
f"{roku_url}/query/tv-channels", status=HTTPStatus.INTERNAL_SERVER_ERROR
)
aioclient_mock.post(
re.compile(f"{roku_url}/keypress/.*"), status=HTTPStatus.INTERNAL_SERVER_ERROR
)
aioclient_mock.post(
re.compile(f"{roku_url}/launch/.*"), status=HTTPStatus.INTERNAL_SERVER_ERROR
)
aioclient_mock.post(f"{roku_url}/search", status=HTTPStatus.INTERNAL_SERVER_ERROR)
async def setup_integration(
hass: HomeAssistant,
aioclient_mock: AiohttpClientMocker,
device: str = "roku3",
app: str = "roku",
host: str = HOST,
unique_id: str = UPNP_SERIAL,
error: bool = False,
power: bool = True,
media_state: str = "close",
server_error: bool = False,
skip_entry_setup: bool = False,
) -> MockConfigEntry:
"""Set up the Roku integration in Home Assistant."""
entry = MockConfigEntry(domain=DOMAIN, unique_id=unique_id, data={CONF_HOST: host})
entry.add_to_hass(hass)
if not skip_entry_setup:
mock_connection(
aioclient_mock,
device,
app=app,
host=host,
error=error,
power=power,
media_state=media_state,
server_error=server_error,
)
await hass.config_entries.async_setup(entry.entry_id)
await hass.async_block_till_done()
return entry

View File

@ -0,0 +1,86 @@
"""Fixtures for Roku integration tests."""
from collections.abc import Generator
import json
from unittest.mock import MagicMock, patch
import pytest
from rokuecp import Device as RokuDevice
from homeassistant.components.roku.const import DOMAIN
from homeassistant.const import CONF_HOST
from homeassistant.core import HomeAssistant
from tests.common import MockConfigEntry, load_fixture
def app_icon_url(*args, **kwargs):
"""Get the URL to the application icon."""
app_id = args[0]
return f"http://192.168.1.160:8060/query/icon/{app_id}"
@pytest.fixture
def mock_config_entry() -> MockConfigEntry:
"""Return the default mocked config entry."""
return MockConfigEntry(
title="Roku",
domain=DOMAIN,
data={CONF_HOST: "192.168.1.160"},
unique_id="1GU48T017973",
)
@pytest.fixture
def mock_setup_entry() -> Generator[None, None, None]:
"""Mock setting up a config entry."""
with patch("homeassistant.components.roku.async_setup_entry", return_value=True):
yield
@pytest.fixture
def mock_roku_config_flow(
request: pytest.FixtureRequest,
) -> Generator[None, MagicMock, None]:
"""Return a mocked Roku client."""
fixture: str = "roku/roku3.json"
if hasattr(request, "param") and request.param:
fixture = request.param
device = RokuDevice(json.loads(load_fixture(fixture)))
with patch(
"homeassistant.components.roku.config_flow.Roku", autospec=True
) as roku_mock:
client = roku_mock.return_value
client.app_icon_url.side_effect = app_icon_url
client.update.return_value = device
yield client
@pytest.fixture
def mock_roku(request: pytest.FixtureRequest) -> Generator[None, MagicMock, None]:
"""Return a mocked Roku client."""
fixture: str = "roku/roku3.json"
if hasattr(request, "param") and request.param:
fixture = request.param
device = RokuDevice(json.loads(load_fixture(fixture)))
with patch(
"homeassistant.components.roku.coordinator.Roku", autospec=True
) as roku_mock:
client = roku_mock.return_value
client.app_icon_url.side_effect = app_icon_url
client.update.return_value = device
yield client
@pytest.fixture
async def init_integration(
hass: HomeAssistant, mock_config_entry: MockConfigEntry, mock_roku: MagicMock
) -> MockConfigEntry:
"""Set up the Roku integration for testing."""
mock_config_entry.add_to_hass(hass)
await hass.config_entries.async_setup(mock_config_entry.entry_id)
await hass.async_block_till_done()
return mock_config_entry

View File

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

View File

@ -1,4 +0,0 @@
<?xml version="1.0" encoding="UTF-8" ?>
<active-app>
<app id="74519" subtype="rsga" type="appl" version="5.2.0">Pluto TV - It's Free TV</app>
</active-app>

View File

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

View File

@ -1,5 +0,0 @@
<?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

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

View File

@ -1,14 +0,0 @@
<?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>
<app id="74519" subtype="rsga" type="appl" version="5.2.0">Pluto TV - It's Free TV</app>
</apps>

View File

@ -1,11 +0,0 @@
<?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>
<app id="74519" subtype="rsga" type="appl" version="5.2.0">Pluto TV - It's Free TV</app>
</apps>

View File

@ -1,5 +0,0 @@
<?xml version="1.0" encoding="UTF-8" ?>
<player error="false" state="close">
<format audio="eac3" captions="none" drm="none" video="hevc_b"/>
<is_live>false</is_live>
</player>

View File

@ -1,12 +0,0 @@
<?xml version="1.0" encoding="UTF-8" ?>
<player error="false" state="play">
<plugin bandwidth="10000000 bps" id="74519" name="Pluto TV - It's Free TV"/>
<format audio="aac_adts" captions="webvtt" container="hls" drm="none" video="mpeg4_10b"/>
<buffering current="1000" max="1000" target="0"/>
<new_stream speed="128000 bps"/>
<position>73313 ms</position>
<duration>95000 ms</duration>
<is_live>true</is_live>
<runtime>25106 ms</runtime>
<stream_segment bitrate="3063648" media_sequence="49" segment_type="mux" time="70013"/>
</player>

View File

@ -1,12 +0,0 @@
<?xml version="1.0" encoding="UTF-8" ?>
<player error="false" state="pause">
<plugin bandwidth="10000000 bps" id="74519" name="Pluto TV - It's Free TV"/>
<format audio="aac_adts" captions="webvtt" container="hls" drm="none" video="mpeg4_10b"/>
<buffering current="1000" max="1000" target="0"/>
<new_stream speed="128000 bps"/>
<position>313813 ms</position>
<duration>6496762 ms</duration>
<is_live>false</is_live>
<runtime>15000 ms</runtime>
<stream_segment bitrate="3063648" media_sequence="61" segment_type="mux" time="310013"/>
</player>

View File

@ -1,12 +0,0 @@
<?xml version="1.0" encoding="UTF-8" ?>
<player error="false" state="play">
<plugin bandwidth="10000000 bps" id="74519" name="Pluto TV - It's Free TV"/>
<format audio="aac_adts" captions="webvtt" container="hls" drm="none" video="mpeg4_10b"/>
<buffering current="1000" max="1000" target="0"/>
<new_stream speed="128000 bps"/>
<position>38813 ms</position>
<duration>6496762 ms</duration>
<is_live>false</is_live>
<runtime>15000 ms</runtime>
<stream_segment bitrate="2000" media_sequence="68" segment_type="captions" time="39013"/>
</player>

View File

@ -0,0 +1,93 @@
{
"available": true,
"standby": false,
"info": {
"udn": "015e5108-9000-1046-8035-b0a737964dfb",
"serial-number": "1GU48T017973",
"device-id": "1GU48T017973",
"vendor-name": "Roku",
"model-number": "4200X",
"model-name": "Roku 3",
"model-region": "US",
"supports-ethernet": "true",
"wifi-mac": "b0:a7:37:96:4d:fb",
"ethernet-mac": "b0:a7:37:96:4d:fa",
"network-type": "ethernet",
"user-device-name": "My Roku 3",
"software-version": "7.5.0",
"software-build": "09021",
"secure-device": "true",
"language": "en",
"country": "US",
"locale": "en_US",
"time-zone": "US/Pacific",
"time-zone-offset": "-480",
"power-mode": "PowerOn",
"supports-suspend": "false",
"supports-find-remote": "false",
"supports-audio-guide": "false",
"developer-enabled": "true",
"keyed-developer-id": "70f6ed9c90cf60718a26f3a7c3e5af1c3ec29558",
"search-enabled": "true",
"voice-search-enabled": "true",
"notifications-enabled": "true",
"notifications-first-use": "false",
"supports-private-listening": "false",
"headphones-connected": "false"
},
"app": {
"@id": "12",
"@type": "appl",
"@version": "4.1.218",
"#text": "Netflix"
},
"apps": [
{
"@id": "11",
"#text": "Roku Channel Store"
},
{
"@id": "12",
"#text": "Netflix"
},
{
"@id": "13",
"#text": "Amazon Video on Demand"
},
{
"@id": "14",
"#text": "MLB.TV®"
},
{
"@id": "26",
"#text": "Free FrameChannel Service"
},
{
"@id": "27",
"#text": "Mediafly"
},
{
"@id": "28",
"#text": "Pandora"
},
{
"@id": "74519",
"@subtype": "rsga",
"@type": "appl",
"@version": "5.2.0",
"#text": "Pluto TV - It's Free TV"
}
],
"media": {
"@error": "false",
"@state": "close",
"format":
{
"@audio": "eac3",
"@captions": "none",
"@drm": "none",
"@video": "hevc_b"
},
"is_live": "false"
}
}

View File

@ -1,35 +0,0 @@
<?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>PowerOff</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

@ -1,35 +0,0 @@
<?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,90 @@
{
"available": true,
"standby": true,
"info": {
"udn": "015e5108-9000-1046-8035-b0a737964dfb",
"serial-number": "1GU48T017973",
"device-id": "1GU48T017973",
"vendor-name": "Roku",
"model-number": "4200X",
"model-name": "Roku 3",
"model-region": "US",
"supports-ethernet": "true",
"wifi-mac": "b0:a7:37:96:4d:fb",
"ethernet-mac": "b0:a7:37:96:4d:fa",
"network-type": "ethernet",
"user-device-name": "My Roku 3",
"software-version": "7.5.0",
"software-build": "09021",
"secure-device": "true",
"language": "en",
"country": "US",
"locale": "en_US",
"time-zone": "US/Pacific",
"time-zone-offset": "-480",
"power-mode": "PowerOn",
"supports-suspend": "false",
"supports-find-remote": "false",
"supports-audio-guide": "false",
"developer-enabled": "true",
"keyed-developer-id": "70f6ed9c90cf60718a26f3a7c3e5af1c3ec29558",
"search-enabled": "true",
"voice-search-enabled": "true",
"notifications-enabled": "true",
"notifications-first-use": "false",
"supports-private-listening": "false",
"headphones-connected": "false"
},
"app": {
"#text": "Roku"
},
"apps": [
{
"@id": "11",
"#text": "Roku Channel Store"
},
{
"@id": "12",
"#text": "Netflix"
},
{
"@id": "13",
"#text": "Amazon Video on Demand"
},
{
"@id": "14",
"#text": "MLB.TV®"
},
{
"@id": "26",
"#text": "Free FrameChannel Service"
},
{
"@id": "27",
"#text": "Mediafly"
},
{
"@id": "28",
"#text": "Pandora"
},
{
"@id": "74519",
"@subtype": "rsga",
"@type": "appl",
"@version": "5.2.0",
"#text": "Pluto TV - It's Free TV"
}
],
"media": {
"@error": "false",
"@state": "close",
"format":
{
"@audio": "eac3",
"@captions": "none",
"@drm": "none",
"@video": "hevc_b"
},
"is_live": "false"
}
}

View File

@ -0,0 +1,116 @@
{
"available": true,
"standby": false,
"info": {
"udn": "015e5108-9000-1046-8035-b0a737964dfb",
"serial-number": "1GU48T017973",
"device-id": "1GU48T017973",
"vendor-name": "Roku",
"model-number": "4200X",
"model-name": "Roku 3",
"model-region": "US",
"supports-ethernet": "true",
"wifi-mac": "b0:a7:37:96:4d:fb",
"ethernet-mac": "b0:a7:37:96:4d:fa",
"network-type": "ethernet",
"user-device-name": "My Roku 3",
"software-version": "7.5.0",
"software-build": "09021",
"secure-device": "true",
"language": "en",
"country": "US",
"locale": "en_US",
"time-zone": "US/Pacific",
"time-zone-offset": "-480",
"power-mode": "PowerOn",
"supports-suspend": "false",
"supports-find-remote": "false",
"supports-audio-guide": "false",
"developer-enabled": "true",
"keyed-developer-id": "70f6ed9c90cf60718a26f3a7c3e5af1c3ec29558",
"search-enabled": "true",
"voice-search-enabled": "true",
"notifications-enabled": "true",
"notifications-first-use": "false",
"supports-private-listening": "false",
"headphones-connected": "false"
},
"app": {
"@id": "74519",
"@subtype": "rsga",
"@type": "appl",
"@version": "5.2.0",
"#text": "Pluto TV - It's Free TV"
},
"apps": [
{
"@id": "11",
"#text": "Roku Channel Store"
},
{
"@id": "12",
"#text": "Netflix"
},
{
"@id": "13",
"#text": "Amazon Video on Demand"
},
{
"@id": "14",
"#text": "MLB.TV®"
},
{
"@id": "26",
"#text": "Free FrameChannel Service"
},
{
"@id": "27",
"#text": "Mediafly"
},
{
"@id": "28",
"#text": "Pandora"
},
{
"@id": "74519",
"@subtype": "rsga",
"@type": "appl",
"@version": "5.2.0",
"#text": "Pluto TV - It's Free TV"
}
],
"media": {
"@error": "false",
"@state": "pause",
"plugin": {
"@bandwidth": "10000000 bps",
"@id": "74519",
"@name": "Pluto TV - It's Free TV"
},
"format": {
"@audio": "aac_adts",
"@captions": "webvtt",
"@container": "hls",
"@drm": "none",
"@video": "mpeg4_10b"
},
"buffering": {
"@current": "1000",
"@max": "1000",
"@target": "0"
},
"new_stream": {
"@speed": "128000 bps"
},
"position": "313813 ms",
"duration": "6496762 ms",
"is_live": "false",
"runtime": "15000 ms",
"stream_segment": {
"@bitrate": "3063648",
"@media_sequence": "61",
"@segment_type": "mux",
"@time": "310013"
}
}
}

View File

@ -0,0 +1,116 @@
{
"available": true,
"standby": false,
"info": {
"udn": "015e5108-9000-1046-8035-b0a737964dfb",
"serial-number": "1GU48T017973",
"device-id": "1GU48T017973",
"vendor-name": "Roku",
"model-number": "4200X",
"model-name": "Roku 3",
"model-region": "US",
"supports-ethernet": "true",
"wifi-mac": "b0:a7:37:96:4d:fb",
"ethernet-mac": "b0:a7:37:96:4d:fa",
"network-type": "ethernet",
"user-device-name": "My Roku 3",
"software-version": "7.5.0",
"software-build": "09021",
"secure-device": "true",
"language": "en",
"country": "US",
"locale": "en_US",
"time-zone": "US/Pacific",
"time-zone-offset": "-480",
"power-mode": "PowerOn",
"supports-suspend": "false",
"supports-find-remote": "false",
"supports-audio-guide": "false",
"developer-enabled": "true",
"keyed-developer-id": "70f6ed9c90cf60718a26f3a7c3e5af1c3ec29558",
"search-enabled": "true",
"voice-search-enabled": "true",
"notifications-enabled": "true",
"notifications-first-use": "false",
"supports-private-listening": "false",
"headphones-connected": "false"
},
"app": {
"@id": "74519",
"@subtype": "rsga",
"@type": "appl",
"@version": "5.2.0",
"#text": "Pluto TV - It's Free TV"
},
"apps": [
{
"@id": "11",
"#text": "Roku Channel Store"
},
{
"@id": "12",
"#text": "Netflix"
},
{
"@id": "13",
"#text": "Amazon Video on Demand"
},
{
"@id": "14",
"#text": "MLB.TV®"
},
{
"@id": "26",
"#text": "Free FrameChannel Service"
},
{
"@id": "27",
"#text": "Mediafly"
},
{
"@id": "28",
"#text": "Pandora"
},
{
"@id": "74519",
"@subtype": "rsga",
"@type": "appl",
"@version": "5.2.0",
"#text": "Pluto TV - It's Free TV"
}
],
"media": {
"@error": "false",
"@state": "play",
"plugin": {
"@bandwidth": "10000000 bps",
"@id": "74519",
"@name": "Pluto TV - It's Free TV"
},
"format": {
"@audio": "aac_adts",
"@captions": "webvtt",
"@container": "hls",
"@drm": "none",
"@video": "mpeg4_10b"
},
"buffering": {
"@current": "1000",
"@max": "1000",
"@target": "0"
},
"new_stream": {
"@speed": "128000 bps"
},
"position": "38813 ms",
"duration": "6496762 ms",
"is_live": "false",
"runtime": "15000 ms",
"stream_segment": {
"@bitrate": "2000",
"@media_sequence": "68",
"@segment_type": "captions",
"@time": "39013"
}
}
}

View File

@ -0,0 +1,96 @@
{
"available": true,
"standby": false,
"info": {
"udn": "015e5108-9000-1046-8035-b0a737964dfb",
"serial-number": "1GU48T017973",
"device-id": "1GU48T017973",
"vendor-name": "Roku",
"model-number": "4200X",
"model-name": "Roku 3",
"model-region": "US",
"supports-ethernet": "true",
"wifi-mac": "b0:a7:37:96:4d:fb",
"ethernet-mac": "b0:a7:37:96:4d:fa",
"network-type": "ethernet",
"user-device-name": "My Roku 3",
"software-version": "7.5.0",
"software-build": "09021",
"secure-device": "true",
"language": "en",
"country": "US",
"locale": "en_US",
"time-zone": "US/Pacific",
"time-zone-offset": "-480",
"power-mode": "PowerOn",
"supports-suspend": "false",
"supports-find-remote": "false",
"supports-audio-guide": "false",
"developer-enabled": "true",
"keyed-developer-id": "70f6ed9c90cf60718a26f3a7c3e5af1c3ec29558",
"search-enabled": "true",
"voice-search-enabled": "true",
"notifications-enabled": "true",
"notifications-first-use": "false",
"supports-private-listening": "false",
"headphones-connected": "false"
},
"app": {
"app": "Roku",
"screensaver": {
"@id": "55545",
"@type": "ssvr",
"@version": "2.0.1",
"#text": "Default screensaver"
}
},
"apps": [
{
"@id": "11",
"#text": "Roku Channel Store"
},
{
"@id": "12",
"#text": "Netflix"
},
{
"@id": "13",
"#text": "Amazon Video on Demand"
},
{
"@id": "14",
"#text": "MLB.TV®"
},
{
"@id": "26",
"#text": "Free FrameChannel Service"
},
{
"@id": "27",
"#text": "Mediafly"
},
{
"@id": "28",
"#text": "Pandora"
},
{
"@id": "74519",
"@subtype": "rsga",
"@type": "appl",
"@version": "5.2.0",
"#text": "Pluto TV - It's Free TV"
}
],
"media": {
"@error": "false",
"@state": "close",
"format":
{
"@audio": "eac3",
"@captions": "none",
"@drm": "none",
"@video": "hevc_b"
},
"is_live": "false"
}
}

View File

@ -0,0 +1,90 @@
{
"available": true,
"standby": false,
"info": {
"udn": "015e5108-9000-1046-8035-b0a737964dfb",
"serial-number": "1GU48T017973",
"device-id": "1GU48T017973",
"vendor-name": "Roku",
"model-number": "4200X",
"model-name": "Roku 3",
"model-region": "US",
"supports-ethernet": "true",
"wifi-mac": "b0:a7:37:96:4d:fb",
"ethernet-mac": "b0:a7:37:96:4d:fa",
"network-type": "ethernet",
"user-device-name": "My Roku 3",
"software-version": "7.5.0",
"software-build": "09021",
"secure-device": "true",
"language": "en",
"country": "US",
"locale": "en_US",
"time-zone": "US/Pacific",
"time-zone-offset": "-480",
"power-mode": "PowerOn",
"supports-suspend": "false",
"supports-find-remote": "false",
"supports-audio-guide": "false",
"developer-enabled": "true",
"keyed-developer-id": "70f6ed9c90cf60718a26f3a7c3e5af1c3ec29558",
"search-enabled": "true",
"voice-search-enabled": "true",
"notifications-enabled": "true",
"notifications-first-use": "false",
"supports-private-listening": "false",
"headphones-connected": "false"
},
"app": {
"#text": "Roku"
},
"apps": [
{
"@id": "11",
"#text": "Roku Channel Store"
},
{
"@id": "12",
"#text": "Netflix"
},
{
"@id": "13",
"#text": "Amazon Video on Demand"
},
{
"@id": "14",
"#text": "MLB.TV®"
},
{
"@id": "26",
"#text": "Free FrameChannel Service"
},
{
"@id": "27",
"#text": "Mediafly"
},
{
"@id": "28",
"#text": "Pandora"
},
{
"@id": "74519",
"@subtype": "rsga",
"@type": "appl",
"@version": "5.2.0",
"#text": "Pluto TV - It's Free TV"
}
],
"media": {
"@error": "false",
"@state": "close",
"format":
{
"@audio": "eac3",
"@captions": "none",
"@drm": "none",
"@video": "hevc_b"
},
"is_live": "false"
}
}

View File

@ -0,0 +1,184 @@
{
"available": true,
"standby": false,
"info": {
"udn": "015e5555-9000-5555-5555-b0a555555dfb",
"serial-number": "YN00H5555555",
"device-id": "0S596H055555",
"advertising-id": "055555a9-d82b-5c75-b8fe-5555550cb7ee",
"vendor-name": "Onn",
"model-name": "100005844",
"model-number": "7820X",
"model-region": "US",
"is-tv": "true",
"is-stick": "false",
"screen-size": "58",
"panel-id": "2",
"tuner-type": "ATSC",
"supports-ethernet": "true",
"wifi-mac": "d8:13:99:f8:b0:c6",
"wifi-driver": "realtek",
"ethernet-mac": "d4:3a:2e:07:fd:cb",
"network-type": "wifi",
"network-name": "NetworkSSID",
"friendly-device-name": "58\" Onn Roku TV",
"friendly-model-name": "Onn Roku TV",
"default-device-name": "Onn Roku TV - YN00H5555555",
"user-device-name": "58\" Onn Roku TV",
"user-device-location": "Living room",
"build-number": "AT9.20E04502A",
"software-version": "9.2.0",
"software-build": "4502",
"secure-device": "true",
"language": "en",
"country": "US",
"locale": "en_US",
"time-zone-auto": "true",
"time-zone": "US/Central",
"time-zone-name": "United States/Central",
"time-zone-tz": "America/Chicago",
"time-zone-offset": "-300",
"clock-format": "12-hour",
"uptime": "264789",
"power-mode": "PowerOn",
"supports-suspend": "true",
"supports-find-remote": "true",
"find-remote-is-possible": "false",
"supports-audio-guide": "true",
"supports-rva": "true",
"developer-enabled": "false",
"keyed-developer-id": [],
"search-enabled": "true",
"search-channels-enabled": "true",
"voice-search-enabled": "true",
"notifications-enabled": "true",
"notifications-first-use": "false",
"supports-private-listening": "true",
"supports-private-listening-dtv": "true",
"supports-warm-standby": "true",
"headphones-connected": "false",
"expert-pq-enabled": "0.9",
"supports-ecs-textedit": "true",
"supports-ecs-microphone": "true",
"supports-wake-on-wlan": "true",
"supports-airplay": "true",
"has-play-on-roku": "true",
"has-mobile-screensaver": "true",
"support-url": "https://www.onntvsupport.com/",
"grandcentral-version": "2.9.57",
"trc-version": "3.0",
"trc-channel-version": "2.9.42",
"davinci-version": "2.8.20",
"has-wifi-extender": "false",
"has-wifi-5G-support": "true",
"can-use-wifi-extender": "true"
},
"app": {
"@id": "tvinput.dtv",
"@type": "tvin",
"@version": "1.0.0",
"#text": "Antenna TV"
},
"apps": [
{
"@id": "tvinput.hdmi2",
"@type": "tvin",
"@version": "1.0.0",
"#text": "Satellite TV"
},
{
"@id": "tvinput.hdmi1",
"@type": "tvin",
"@version": "1.0.0",
"#text": "Blu-ray player"
},
{
"@id": "tvinput.dtv",
"@type": "tvin",
"@version": "1.0.0",
"#text": "Antenna TV"
},
{
"@id": "11",
"#text": "Roku Channel Store"
},
{
"@id": "12",
"#text": "Netflix"
},
{
"@id": "13",
"#text": "Amazon Video on Demand"
},
{
"@id": "14",
"#text": "MLB.TV®"
},
{
"@id": "26",
"#text": "Free FrameChannel Service"
},
{
"@id": "27",
"#text": "Mediafly"
},
{
"@id": "28",
"#text": "Pandora"
},
{
"@id": "74519",
"@subtype": "rsga",
"@type": "appl",
"@version": "5.2.0",
"#text": "Pluto TV - It's Free TV"
}
],
"channel": {
"number": "14.3",
"name": "getTV",
"type": "air-digital",
"user-hidden": "false",
"active-input": "true",
"signal-state": "valid",
"signal-mode": "480i",
"signal-quality": "20",
"signal-strength": "-75",
"program-title": "Airwolf",
"program-description": "The team will travel all around the world in order to shut down a global crime ring.",
"program-ratings": "TV-14-D-V",
"program-analog-audio": "none",
"program-digital-audio": "stereo",
"program-audio-languages": "eng",
"program-audio-formats": "AC3",
"program-audio-language": "eng",
"program-audio-format": "AC3",
"program-has-cc": "true"
},
"channels": [
{
"number": "1.1",
"name": "WhatsOn",
"type": "air-digital",
"user-hidden": "false"
},
{
"number": "1.3",
"name": "QVC",
"type": "air-digital",
"user-hidden": "false"
}
],
"media": {
"@error": "false",
"@state": "close",
"format":
{
"@audio": "eac3",
"@captions": "none",
"@drm": "none",
"@video": "hevc_b"
},
"is_live": "false"
}
}

View File

@ -1,72 +0,0 @@
<?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>

View File

@ -1,73 +0,0 @@
<?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>
<supports-airplay>true</supports-airplay>
<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>

View File

@ -1,24 +0,0 @@
<?xml version="1.0" encoding="UTF-8" ?>
<tv-channel>
<channel>
<number>14.3</number>
<name>getTV</name>
<type>air-digital</type>
<user-hidden>false</user-hidden>
<active-input>true</active-input>
<signal-state>valid</signal-state>
<signal-mode>480i</signal-mode>
<signal-quality>20</signal-quality>
<signal-strength>-75</signal-strength>
<program-title>Airwolf</program-title>
<program-description>The team will travel all around the world in order to shut down a global crime ring.</program-description>
<program-ratings>TV-14-D-V</program-ratings>
<program-analog-audio>none</program-analog-audio>
<program-digital-audio>stereo</program-digital-audio>
<program-audio-languages>eng</program-audio-languages>
<program-audio-formats>AC3</program-audio-formats>
<program-audio-language>eng</program-audio-language>
<program-audio-format>AC3</program-audio-format>
<program-has-cc>true</program-has-cc>
</channel>
</tv-channel>

View File

@ -1,15 +0,0 @@
<?xml version="1.0" encoding="UTF-8" ?>
<tv-channels>
<channel>
<number>1.1</number>
<name>WhatsOn</name>
<type>air-digital</type>
<user-hidden>false</user-hidden>
</channel>
<channel>
<number>1.3</number>
<name>QVC</name>
<type>air-digital</type>
<user-hidden>false</user-hidden>
</channel>
</tv-channels>

View File

@ -1,4 +1,8 @@
"""Tests for the sensors provided by the Roku integration."""
from unittest.mock import MagicMock
import pytest
from homeassistant.components.binary_sensor import STATE_OFF, STATE_ON
from homeassistant.components.roku.const import DOMAIN
from homeassistant.const import ATTR_DEVICE_CLASS, ATTR_FRIENDLY_NAME, ATTR_ICON
@ -6,17 +10,14 @@ from homeassistant.core import HomeAssistant
from homeassistant.helpers import device_registry as dr, entity_registry as er
from homeassistant.helpers.entity import EntityCategory
from tests.components.roku import UPNP_SERIAL, setup_integration
from tests.test_util.aiohttp import AiohttpClientMocker
from tests.common import MockConfigEntry
from tests.components.roku import UPNP_SERIAL
async def test_roku_binary_sensors(
hass: HomeAssistant,
aioclient_mock: AiohttpClientMocker,
hass: HomeAssistant, init_integration: MockConfigEntry
) -> None:
"""Test the Roku binary sensors."""
await setup_integration(hass, aioclient_mock)
entity_registry = er.async_get(hass)
device_registry = dr.async_get(hass)
@ -77,22 +78,17 @@ async def test_roku_binary_sensors(
assert device_entry.name == "My Roku 3"
assert device_entry.entry_type is None
assert device_entry.sw_version == "7.5.0"
assert device_entry.hw_version == "4200X"
assert device_entry.suggested_area is None
@pytest.mark.parametrize("mock_roku", ["roku/rokutv-7820x.json"], indirect=True)
async def test_rokutv_binary_sensors(
hass: HomeAssistant,
aioclient_mock: AiohttpClientMocker,
init_integration: MockConfigEntry,
mock_roku: MagicMock,
) -> None:
"""Test the Roku binary sensors."""
await setup_integration(
hass,
aioclient_mock,
device="rokutv",
app="tvinput-dtv",
host="192.168.1.161",
unique_id="YN00H5555555",
)
entity_registry = er.async_get(hass)
device_registry = dr.async_get(hass)
@ -167,3 +163,5 @@ async def test_rokutv_binary_sensors(
assert device_entry.name == '58" Onn Roku TV'
assert device_entry.entry_type is None
assert device_entry.sw_version == "9.2.0"
assert device_entry.hw_version == "7820X"
assert device_entry.suggested_area == "Living room"

View File

@ -1,6 +1,9 @@
"""Test the Roku config flow."""
import dataclasses
from unittest.mock import patch
from unittest.mock import MagicMock
import pytest
from rokuecp import RokuConnectionError
from homeassistant.components.roku.const import DOMAIN
from homeassistant.config_entries import SOURCE_HOMEKIT, SOURCE_SSDP, SOURCE_USER
@ -12,6 +15,7 @@ from homeassistant.data_entry_flow import (
RESULT_TYPE_FORM,
)
from tests.common import MockConfigEntry
from tests.components.roku import (
HOMEKIT_HOST,
HOST,
@ -19,20 +23,18 @@ from tests.components.roku import (
MOCK_SSDP_DISCOVERY_INFO,
NAME_ROKUTV,
UPNP_FRIENDLY_NAME,
mock_connection,
setup_integration,
)
from tests.test_util.aiohttp import AiohttpClientMocker
async def test_duplicate_error(
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker
hass: HomeAssistant,
mock_config_entry: MockConfigEntry,
mock_roku_config_flow: MagicMock,
) -> None:
"""Test that errors are shown when duplicates are added."""
await setup_integration(hass, aioclient_mock, skip_entry_setup=True)
mock_connection(aioclient_mock)
mock_config_entry.add_to_hass(hass)
user_input = {CONF_HOST: HOST}
user_input = {CONF_HOST: mock_config_entry.data[CONF_HOST]}
result = await hass.config_entries.flow.async_init(
DOMAIN, context={CONF_SOURCE: SOURCE_USER}, data=user_input
)
@ -40,7 +42,7 @@ async def test_duplicate_error(
assert result["type"] == RESULT_TYPE_ABORT
assert result["reason"] == "already_configured"
user_input = {CONF_HOST: HOST}
user_input = {CONF_HOST: mock_config_entry.data[CONF_HOST]}
result = await hass.config_entries.flow.async_init(
DOMAIN, context={CONF_SOURCE: SOURCE_USER}, data=user_input
)
@ -57,11 +59,12 @@ async def test_duplicate_error(
assert result["reason"] == "already_configured"
async def test_form(hass: HomeAssistant, aioclient_mock: AiohttpClientMocker) -> None:
async def test_form(
hass: HomeAssistant,
mock_roku_config_flow: MagicMock,
mock_setup_entry: None,
) -> None:
"""Test the user step."""
mock_connection(aioclient_mock)
result = await hass.config_entries.flow.async_init(
DOMAIN, context={CONF_SOURCE: SOURCE_USER}
)
@ -69,29 +72,26 @@ async def test_form(hass: HomeAssistant, aioclient_mock: AiohttpClientMocker) ->
assert result["errors"] == {}
user_input = {CONF_HOST: HOST}
with patch(
"homeassistant.components.roku.async_setup_entry",
return_value=True,
) as mock_setup_entry:
result = await hass.config_entries.flow.async_configure(
flow_id=result["flow_id"], user_input=user_input
)
await hass.async_block_till_done()
result = await hass.config_entries.flow.async_configure(
flow_id=result["flow_id"], user_input=user_input
)
await hass.async_block_till_done()
assert result["type"] == RESULT_TYPE_CREATE_ENTRY
assert result["title"] == UPNP_FRIENDLY_NAME
assert result["title"] == "My Roku 3"
assert result["data"]
assert "data" in result
assert result["data"][CONF_HOST] == HOST
assert len(mock_setup_entry.mock_calls) == 1
assert "result" in result
assert result["result"].unique_id == "1GU48T017973"
async def test_form_cannot_connect(
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker
hass: HomeAssistant, mock_roku_config_flow: MagicMock
) -> None:
"""Test we handle cannot connect roku error."""
mock_connection(aioclient_mock, error=True)
mock_roku_config_flow.update.side_effect = RokuConnectionError
result = await hass.config_entries.flow.async_init(
DOMAIN, context={CONF_SOURCE: SOURCE_USER}
@ -106,40 +106,29 @@ async def test_form_cannot_connect(
async def test_form_unknown_error(
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker
hass: HomeAssistant, mock_roku_config_flow: MagicMock
) -> None:
"""Test we handle unknown error."""
mock_connection(aioclient_mock)
mock_roku_config_flow.update.side_effect = Exception
result = await hass.config_entries.flow.async_init(
DOMAIN, context={CONF_SOURCE: SOURCE_USER}
)
user_input = {CONF_HOST: HOST}
with patch(
"homeassistant.components.roku.config_flow.Roku._request",
side_effect=Exception,
) as mock_validate_input:
result = await hass.config_entries.flow.async_configure(
flow_id=result["flow_id"], user_input=user_input
)
result = await hass.config_entries.flow.async_configure(
flow_id=result["flow_id"], user_input=user_input
)
assert result["type"] == RESULT_TYPE_ABORT
assert result["reason"] == "unknown"
await hass.async_block_till_done()
assert len(mock_validate_input.mock_calls) == 1
async def test_homekit_cannot_connect(
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker
hass: HomeAssistant, mock_roku_config_flow: MagicMock
) -> None:
"""Test we abort homekit flow on connection error."""
mock_connection(
aioclient_mock,
host=HOMEKIT_HOST,
error=True,
)
mock_roku_config_flow.update.side_effect = RokuConnectionError
discovery_info = dataclasses.replace(MOCK_HOMEKIT_DISCOVERY_INFO)
result = await hass.config_entries.flow.async_init(
@ -153,32 +142,31 @@ async def test_homekit_cannot_connect(
async def test_homekit_unknown_error(
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker
hass: HomeAssistant, mock_roku_config_flow: MagicMock
) -> None:
"""Test we abort homekit flow on unknown error."""
mock_connection(aioclient_mock)
mock_roku_config_flow.update.side_effect = Exception
discovery_info = dataclasses.replace(MOCK_HOMEKIT_DISCOVERY_INFO)
with patch(
"homeassistant.components.roku.config_flow.Roku._request",
side_effect=Exception,
):
result = await hass.config_entries.flow.async_init(
DOMAIN,
context={CONF_SOURCE: SOURCE_HOMEKIT},
data=discovery_info,
)
result = await hass.config_entries.flow.async_init(
DOMAIN,
context={CONF_SOURCE: SOURCE_HOMEKIT},
data=discovery_info,
)
assert result["type"] == RESULT_TYPE_ABORT
assert result["reason"] == "unknown"
@pytest.mark.parametrize(
"mock_roku_config_flow", ["roku/rokutv-7820x.json"], indirect=True
)
async def test_homekit_discovery(
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker
hass: HomeAssistant,
mock_roku_config_flow: MagicMock,
mock_setup_entry: None,
) -> None:
"""Test the homekit discovery flow."""
mock_connection(aioclient_mock, device="rokutv", host=HOMEKIT_HOST)
discovery_info = dataclasses.replace(MOCK_HOMEKIT_DISCOVERY_INFO)
result = await hass.config_entries.flow.async_init(
DOMAIN, context={CONF_SOURCE: SOURCE_HOMEKIT}, data=discovery_info
@ -188,24 +176,18 @@ async def test_homekit_discovery(
assert result["step_id"] == "discovery_confirm"
assert result["description_placeholders"] == {CONF_NAME: NAME_ROKUTV}
with patch(
"homeassistant.components.roku.async_setup_entry",
return_value=True,
) as mock_setup_entry:
result = await hass.config_entries.flow.async_configure(
flow_id=result["flow_id"], user_input={}
)
await hass.async_block_till_done()
result = await hass.config_entries.flow.async_configure(
flow_id=result["flow_id"], user_input={}
)
await hass.async_block_till_done()
assert result["type"] == RESULT_TYPE_CREATE_ENTRY
assert result["title"] == NAME_ROKUTV
assert result["data"]
assert "data" in result
assert result["data"][CONF_HOST] == HOMEKIT_HOST
assert result["data"][CONF_NAME] == NAME_ROKUTV
assert len(mock_setup_entry.mock_calls) == 1
# test abort on existing host
discovery_info = dataclasses.replace(MOCK_HOMEKIT_DISCOVERY_INFO)
result = await hass.config_entries.flow.async_init(
@ -217,10 +199,10 @@ async def test_homekit_discovery(
async def test_ssdp_cannot_connect(
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker
hass: HomeAssistant, mock_roku_config_flow: MagicMock
) -> None:
"""Test we abort SSDP flow on connection error."""
mock_connection(aioclient_mock, error=True)
mock_roku_config_flow.update.side_effect = RokuConnectionError
discovery_info = dataclasses.replace(MOCK_SSDP_DISCOVERY_INFO)
result = await hass.config_entries.flow.async_init(
@ -234,32 +216,28 @@ async def test_ssdp_cannot_connect(
async def test_ssdp_unknown_error(
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker
hass: HomeAssistant, mock_roku_config_flow: MagicMock
) -> None:
"""Test we abort SSDP flow on unknown error."""
mock_connection(aioclient_mock)
mock_roku_config_flow.update.side_effect = Exception
discovery_info = dataclasses.replace(MOCK_SSDP_DISCOVERY_INFO)
with patch(
"homeassistant.components.roku.config_flow.Roku._request",
side_effect=Exception,
):
result = await hass.config_entries.flow.async_init(
DOMAIN,
context={CONF_SOURCE: SOURCE_SSDP},
data=discovery_info,
)
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"] == "unknown"
async def test_ssdp_discovery(
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker
hass: HomeAssistant,
mock_roku_config_flow: MagicMock,
mock_setup_entry: None,
) -> None:
"""Test the SSDP discovery flow."""
mock_connection(aioclient_mock)
discovery_info = dataclasses.replace(MOCK_SSDP_DISCOVERY_INFO)
result = await hass.config_entries.flow.async_init(
DOMAIN, context={CONF_SOURCE: SOURCE_SSDP}, data=discovery_info
@ -269,14 +247,10 @@ async def test_ssdp_discovery(
assert result["step_id"] == "discovery_confirm"
assert result["description_placeholders"] == {CONF_NAME: UPNP_FRIENDLY_NAME}
with patch(
"homeassistant.components.roku.async_setup_entry",
return_value=True,
) as mock_setup_entry:
result = await hass.config_entries.flow.async_configure(
flow_id=result["flow_id"], user_input={}
)
await hass.async_block_till_done()
result = await hass.config_entries.flow.async_configure(
flow_id=result["flow_id"], user_input={}
)
await hass.async_block_till_done()
assert result["type"] == RESULT_TYPE_CREATE_ENTRY
assert result["title"] == UPNP_FRIENDLY_NAME
@ -284,5 +258,3 @@ async def test_ssdp_discovery(
assert result["data"]
assert result["data"][CONF_HOST] == HOST
assert result["data"][CONF_NAME] == UPNP_FRIENDLY_NAME
assert len(mock_setup_entry.mock_calls) == 1

View File

@ -1,41 +1,45 @@
"""Tests for the Roku integration."""
from unittest.mock import patch
from unittest.mock import AsyncMock, MagicMock, patch
from rokuecp import RokuConnectionError
from homeassistant.components.roku.const import DOMAIN
from homeassistant.config_entries import ConfigEntryState
from homeassistant.core import HomeAssistant
from tests.components.roku import setup_integration
from tests.test_util.aiohttp import AiohttpClientMocker
from tests.common import MockConfigEntry
@patch(
"homeassistant.components.roku.coordinator.Roku._request",
side_effect=RokuConnectionError,
)
async def test_config_entry_not_ready(
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker
mock_request: MagicMock, hass: HomeAssistant, mock_config_entry: MockConfigEntry
) -> None:
"""Test the Roku configuration entry not ready."""
entry = await setup_integration(hass, aioclient_mock, error=True)
assert entry.state is ConfigEntryState.SETUP_RETRY
async def test_unload_config_entry(
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker
) -> None:
"""Test the Roku configuration entry unloading."""
with 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, aioclient_mock)
assert hass.data[DOMAIN][entry.entry_id]
assert entry.state is ConfigEntryState.LOADED
await hass.config_entries.async_unload(entry.entry_id)
mock_config_entry.add_to_hass(hass)
await hass.config_entries.async_setup(mock_config_entry.entry_id)
await hass.async_block_till_done()
assert entry.entry_id not in hass.data[DOMAIN]
assert entry.state is ConfigEntryState.NOT_LOADED
assert mock_request.call_count == 1
assert mock_config_entry.state is ConfigEntryState.SETUP_RETRY
async def test_load_unload_config_entry(
hass: HomeAssistant,
mock_config_entry: MockConfigEntry,
mock_roku: AsyncMock,
) -> None:
"""Test the Roku configuration entry loading/unloading."""
mock_config_entry.add_to_hass(hass)
await hass.config_entries.async_setup(mock_config_entry.entry_id)
await hass.async_block_till_done()
assert mock_config_entry.entry_id in hass.data[DOMAIN]
assert mock_config_entry.state is ConfigEntryState.LOADED
await hass.config_entries.async_unload(mock_config_entry.entry_id)
await hass.async_block_till_done()
assert mock_config_entry.entry_id not in hass.data[DOMAIN]
assert mock_config_entry.state is ConfigEntryState.NOT_LOADED

View File

@ -1,7 +1,8 @@
"""Tests for the Roku Media Player platform."""
from datetime import timedelta
from unittest.mock import patch
from unittest.mock import MagicMock, patch
import pytest
from rokuecp import RokuError
from homeassistant.components.media_player import MediaPlayerDeviceClass
@ -76,25 +77,14 @@ from homeassistant.core import HomeAssistant
from homeassistant.helpers import device_registry as dr, entity_registry as er
from homeassistant.util import dt as dt_util
from tests.common import async_fire_time_changed
from tests.components.roku import NAME_ROKUTV, UPNP_SERIAL, setup_integration
from tests.test_util.aiohttp import AiohttpClientMocker
from tests.common import MockConfigEntry, async_fire_time_changed
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_LOCATION = "Living room"
TV_MANUFACTURER = "Onn"
TV_MODEL = "100005844"
TV_SERIAL = "YN00H5555555"
TV_SW_VERSION = "9.2.0"
async def test_setup(hass: HomeAssistant, aioclient_mock: AiohttpClientMocker) -> None:
async def test_setup(hass: HomeAssistant, init_integration: MockConfigEntry) -> None:
"""Test setup with basic config."""
await setup_integration(hass, aioclient_mock)
entity_registry = er.async_get(hass)
device_registry = dr.async_get(hass)
@ -104,12 +94,12 @@ async def test_setup(hass: HomeAssistant, aioclient_mock: AiohttpClientMocker) -
assert state
assert entry
assert entry.original_device_class is MediaPlayerDeviceClass.RECEIVER
assert entry.unique_id == UPNP_SERIAL
assert entry.unique_id == "1GU48T017973"
assert entry.device_id
device_entry = device_registry.async_get(entry.device_id)
assert device_entry
assert device_entry.identifiers == {(DOMAIN, UPNP_SERIAL)}
assert device_entry.identifiers == {(DOMAIN, "1GU48T017973")}
assert device_entry.connections == {
(dr.CONNECTION_NETWORK_MAC, "b0:a7:37:96:4d:fb"),
(dr.CONNECTION_NETWORK_MAC, "b0:a7:37:96:4d:fa"),
@ -118,34 +108,30 @@ async def test_setup(hass: HomeAssistant, aioclient_mock: AiohttpClientMocker) -
assert device_entry.model == "Roku 3"
assert device_entry.name == "My Roku 3"
assert device_entry.entry_type is None
assert device_entry.hw_version == "4200X"
assert device_entry.sw_version == "7.5.0"
assert device_entry.hw_version == "4200X"
assert device_entry.suggested_area is None
@pytest.mark.parametrize("mock_roku", ["roku/roku3-idle.json"], indirect=True)
async def test_idle_setup(
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker
hass: HomeAssistant,
init_integration: MockConfigEntry,
mock_roku: MagicMock,
) -> None:
"""Test setup with idle device."""
await setup_integration(hass, aioclient_mock, power=False)
state = hass.states.get(MAIN_ENTITY_ID)
assert state
assert state.state == STATE_STANDBY
@pytest.mark.parametrize("mock_roku", ["roku/rokutv-7820x.json"], indirect=True)
async def test_tv_setup(
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker
hass: HomeAssistant,
init_integration: MockConfigEntry,
mock_roku: MagicMock,
) -> None:
"""Test Roku TV setup."""
await setup_integration(
hass,
aioclient_mock,
device="rokutv",
app="tvinput-dtv",
host=TV_HOST,
unique_id=TV_SERIAL,
)
entity_registry = er.async_get(hass)
device_registry = dr.async_get(hass)
@ -155,37 +141,41 @@ async def test_tv_setup(
assert state
assert entry
assert entry.original_device_class is MediaPlayerDeviceClass.TV
assert entry.unique_id == TV_SERIAL
assert entry.unique_id == "YN00H5555555"
assert entry.device_id
device_entry = device_registry.async_get(entry.device_id)
assert device_entry
assert device_entry.identifiers == {(DOMAIN, TV_SERIAL)}
assert device_entry.identifiers == {(DOMAIN, "YN00H5555555")}
assert device_entry.connections == {
(dr.CONNECTION_NETWORK_MAC, "d8:13:99:f8:b0:c6"),
(dr.CONNECTION_NETWORK_MAC, "d4:3a:2e:07:fd:cb"),
}
assert device_entry.manufacturer == TV_MANUFACTURER
assert device_entry.model == TV_MODEL
assert device_entry.manufacturer == "Onn"
assert device_entry.model == "100005844"
assert device_entry.name == '58" Onn Roku TV'
assert device_entry.entry_type is None
assert device_entry.sw_version == "9.2.0"
assert device_entry.hw_version == "7820X"
assert device_entry.sw_version == TV_SW_VERSION
assert device_entry.suggested_area == "Living room"
async def test_availability(
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker
hass: HomeAssistant,
mock_roku: MagicMock,
mock_config_entry: MockConfigEntry,
) -> None:
"""Test entity availability."""
now = dt_util.utcnow()
future = now + timedelta(minutes=1)
mock_config_entry.add_to_hass(hass)
with patch("homeassistant.util.dt.utcnow", return_value=now):
await setup_integration(hass, aioclient_mock)
await hass.config_entries.async_setup(mock_config_entry.entry_id)
await hass.async_block_till_done()
with patch(
"homeassistant.components.roku.coordinator.Roku.update", side_effect=RokuError
), patch("homeassistant.util.dt.utcnow", return_value=future):
with patch("homeassistant.util.dt.utcnow", return_value=future):
mock_roku.update.side_effect = RokuError
async_fire_time_changed(hass, future)
await hass.async_block_till_done()
assert hass.states.get(MAIN_ENTITY_ID).state == STATE_UNAVAILABLE
@ -193,17 +183,18 @@ async def test_availability(
future += timedelta(minutes=1)
with patch("homeassistant.util.dt.utcnow", return_value=future):
mock_roku.update.side_effect = None
async_fire_time_changed(hass, future)
await hass.async_block_till_done()
assert hass.states.get(MAIN_ENTITY_ID).state == STATE_HOME
async def test_supported_features(
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker
hass: HomeAssistant,
init_integration: MockConfigEntry,
mock_roku: MagicMock,
) -> None:
"""Test supported features."""
await setup_integration(hass, aioclient_mock)
# Features supported for Rokus
state = hass.states.get(MAIN_ENTITY_ID)
assert (
@ -222,20 +213,15 @@ async def test_supported_features(
)
@pytest.mark.parametrize("mock_roku", ["roku/rokutv-7820x.json"], indirect=True)
async def test_tv_supported_features(
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker
hass: HomeAssistant,
init_integration: MockConfigEntry,
mock_roku: MagicMock,
) -> None:
"""Test supported features for Roku TV."""
await setup_integration(
hass,
aioclient_mock,
device="rokutv",
app="tvinput-dtv",
host=TV_HOST,
unique_id=TV_SERIAL,
)
state = hass.states.get(TV_ENTITY_ID)
assert state
assert (
SUPPORT_PREVIOUS_TRACK
| SUPPORT_NEXT_TRACK
@ -253,12 +239,11 @@ async def test_tv_supported_features(
async def test_attributes(
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker
hass: HomeAssistant, init_integration: MockConfigEntry
) -> None:
"""Test attributes."""
await setup_integration(hass, aioclient_mock)
state = hass.states.get(MAIN_ENTITY_ID)
assert state
assert state.state == STATE_HOME
assert state.attributes.get(ATTR_MEDIA_CONTENT_TYPE) is None
@ -267,13 +252,15 @@ async def test_attributes(
assert state.attributes.get(ATTR_INPUT_SOURCE) == "Roku"
@pytest.mark.parametrize("mock_roku", ["roku/roku3-app.json"], indirect=True)
async def test_attributes_app(
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker
hass: HomeAssistant,
init_integration: MockConfigEntry,
mock_roku: MagicMock,
) -> None:
"""Test attributes for app."""
await setup_integration(hass, aioclient_mock, app="netflix")
state = hass.states.get(MAIN_ENTITY_ID)
assert state
assert state.state == STATE_ON
assert state.attributes.get(ATTR_MEDIA_CONTENT_TYPE) == MEDIA_TYPE_APP
@ -282,13 +269,15 @@ async def test_attributes_app(
assert state.attributes.get(ATTR_INPUT_SOURCE) == "Netflix"
@pytest.mark.parametrize("mock_roku", ["roku/roku3-media-playing.json"], indirect=True)
async def test_attributes_app_media_playing(
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker
hass: HomeAssistant,
init_integration: MockConfigEntry,
mock_roku: MagicMock,
) -> None:
"""Test attributes for app with playing media."""
await setup_integration(hass, aioclient_mock, app="pluto", media_state="play")
state = hass.states.get(MAIN_ENTITY_ID)
assert state
assert state.state == STATE_PLAYING
assert state.attributes.get(ATTR_MEDIA_CONTENT_TYPE) == MEDIA_TYPE_APP
@ -299,13 +288,15 @@ async def test_attributes_app_media_playing(
assert state.attributes.get(ATTR_INPUT_SOURCE) == "Pluto TV - It's Free TV"
@pytest.mark.parametrize("mock_roku", ["roku/roku3-media-paused.json"], indirect=True)
async def test_attributes_app_media_paused(
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker
hass: HomeAssistant,
init_integration: MockConfigEntry,
mock_roku: MagicMock,
) -> None:
"""Test attributes for app with paused media."""
await setup_integration(hass, aioclient_mock, app="pluto", media_state="pause")
state = hass.states.get(MAIN_ENTITY_ID)
assert state
assert state.state == STATE_PAUSED
assert state.attributes.get(ATTR_MEDIA_CONTENT_TYPE) == MEDIA_TYPE_APP
@ -316,13 +307,15 @@ async def test_attributes_app_media_paused(
assert state.attributes.get(ATTR_INPUT_SOURCE) == "Pluto TV - It's Free TV"
@pytest.mark.parametrize("mock_roku", ["roku/roku3-screensaver.json"], indirect=True)
async def test_attributes_screensaver(
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker
hass: HomeAssistant,
init_integration: MockConfigEntry,
mock_roku: MagicMock,
) -> None:
"""Test attributes for app with screensaver."""
await setup_integration(hass, aioclient_mock, app="screensaver")
state = hass.states.get(MAIN_ENTITY_ID)
assert state
assert state.state == STATE_IDLE
assert state.attributes.get(ATTR_MEDIA_CONTENT_TYPE) is None
@ -331,20 +324,13 @@ async def test_attributes_screensaver(
assert state.attributes.get(ATTR_INPUT_SOURCE) == "Roku"
@pytest.mark.parametrize("mock_roku", ["roku/rokutv-7820x.json"], indirect=True)
async def test_tv_attributes(
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker
hass: HomeAssistant, init_integration: MockConfigEntry
) -> None:
"""Test attributes for Roku TV."""
await setup_integration(
hass,
aioclient_mock,
device="rokutv",
app="tvinput-dtv",
host=TV_HOST,
unique_id=TV_SERIAL,
)
state = hass.states.get(TV_ENTITY_ID)
assert state
assert state.state == STATE_ON
assert state.attributes.get(ATTR_APP_ID) == "tvinput.dtv"
@ -355,277 +341,245 @@ async def test_tv_attributes(
assert state.attributes.get(ATTR_MEDIA_TITLE) == "Airwolf"
async def test_tv_device_registry(
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker
) -> None:
"""Test device registered for Roku TV in the device registry."""
await setup_integration(
hass,
aioclient_mock,
device="rokutv",
app="tvinput-dtv",
host=TV_HOST,
unique_id=TV_SERIAL,
)
device_registry = dr.async_get(hass)
reg_device = device_registry.async_get_device(identifiers={(DOMAIN, TV_SERIAL)})
assert reg_device.model == TV_MODEL
assert reg_device.sw_version == TV_SW_VERSION
assert reg_device.manufacturer == TV_MANUFACTURER
assert reg_device.suggested_area == TV_LOCATION
assert reg_device.name == NAME_ROKUTV
async def test_services(
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker
hass: HomeAssistant,
init_integration: MockConfigEntry,
mock_roku: MagicMock,
) -> None:
"""Test the different media player services."""
await setup_integration(hass, aioclient_mock)
await hass.services.async_call(
MP_DOMAIN, SERVICE_TURN_OFF, {ATTR_ENTITY_ID: MAIN_ENTITY_ID}, blocking=True
)
with patch("homeassistant.components.roku.coordinator.Roku.remote") as remote_mock:
await hass.services.async_call(
MP_DOMAIN, SERVICE_TURN_OFF, {ATTR_ENTITY_ID: MAIN_ENTITY_ID}, blocking=True
)
assert mock_roku.remote.call_count == 1
mock_roku.remote.assert_called_with("poweroff")
remote_mock.assert_called_once_with("poweroff")
await hass.services.async_call(
MP_DOMAIN, SERVICE_TURN_ON, {ATTR_ENTITY_ID: MAIN_ENTITY_ID}, blocking=True
)
with patch("homeassistant.components.roku.coordinator.Roku.remote") as remote_mock:
await hass.services.async_call(
MP_DOMAIN, SERVICE_TURN_ON, {ATTR_ENTITY_ID: MAIN_ENTITY_ID}, blocking=True
)
assert mock_roku.remote.call_count == 2
mock_roku.remote.assert_called_with("poweron")
remote_mock.assert_called_once_with("poweron")
await hass.services.async_call(
MP_DOMAIN,
SERVICE_MEDIA_PAUSE,
{ATTR_ENTITY_ID: MAIN_ENTITY_ID},
blocking=True,
)
with patch("homeassistant.components.roku.coordinator.Roku.remote") as remote_mock:
await hass.services.async_call(
MP_DOMAIN,
SERVICE_MEDIA_PAUSE,
{ATTR_ENTITY_ID: MAIN_ENTITY_ID},
blocking=True,
)
assert mock_roku.remote.call_count == 3
mock_roku.remote.assert_called_with("play")
remote_mock.assert_called_once_with("play")
await hass.services.async_call(
MP_DOMAIN,
SERVICE_MEDIA_PLAY,
{ATTR_ENTITY_ID: MAIN_ENTITY_ID},
blocking=True,
)
with patch("homeassistant.components.roku.coordinator.Roku.remote") as remote_mock:
await hass.services.async_call(
MP_DOMAIN,
SERVICE_MEDIA_PLAY,
{ATTR_ENTITY_ID: MAIN_ENTITY_ID},
blocking=True,
)
assert mock_roku.remote.call_count == 4
mock_roku.remote.assert_called_with("play")
remote_mock.assert_called_once_with("play")
await hass.services.async_call(
MP_DOMAIN,
SERVICE_MEDIA_PLAY_PAUSE,
{ATTR_ENTITY_ID: MAIN_ENTITY_ID},
blocking=True,
)
with patch("homeassistant.components.roku.coordinator.Roku.remote") as remote_mock:
await hass.services.async_call(
MP_DOMAIN,
SERVICE_MEDIA_PLAY_PAUSE,
{ATTR_ENTITY_ID: MAIN_ENTITY_ID},
blocking=True,
)
assert mock_roku.remote.call_count == 5
mock_roku.remote.assert_called_with("play")
remote_mock.assert_called_once_with("play")
await hass.services.async_call(
MP_DOMAIN,
SERVICE_MEDIA_NEXT_TRACK,
{ATTR_ENTITY_ID: MAIN_ENTITY_ID},
blocking=True,
)
with patch("homeassistant.components.roku.coordinator.Roku.remote") as remote_mock:
await hass.services.async_call(
MP_DOMAIN,
SERVICE_MEDIA_NEXT_TRACK,
{ATTR_ENTITY_ID: MAIN_ENTITY_ID},
blocking=True,
)
assert mock_roku.remote.call_count == 6
mock_roku.remote.assert_called_with("forward")
remote_mock.assert_called_once_with("forward")
await hass.services.async_call(
MP_DOMAIN,
SERVICE_MEDIA_PREVIOUS_TRACK,
{ATTR_ENTITY_ID: MAIN_ENTITY_ID},
blocking=True,
)
with patch("homeassistant.components.roku.coordinator.Roku.remote") as remote_mock:
await hass.services.async_call(
MP_DOMAIN,
SERVICE_MEDIA_PREVIOUS_TRACK,
{ATTR_ENTITY_ID: MAIN_ENTITY_ID},
blocking=True,
)
assert mock_roku.remote.call_count == 7
mock_roku.remote.assert_called_with("reverse")
remote_mock.assert_called_once_with("reverse")
await hass.services.async_call(
MP_DOMAIN,
SERVICE_SELECT_SOURCE,
{ATTR_ENTITY_ID: MAIN_ENTITY_ID, ATTR_INPUT_SOURCE: "Home"},
blocking=True,
)
with patch("homeassistant.components.roku.coordinator.Roku.launch") as launch_mock:
await hass.services.async_call(
MP_DOMAIN,
SERVICE_PLAY_MEDIA,
{
ATTR_ENTITY_ID: MAIN_ENTITY_ID,
ATTR_MEDIA_CONTENT_TYPE: MEDIA_TYPE_APP,
ATTR_MEDIA_CONTENT_ID: "11",
assert mock_roku.remote.call_count == 8
mock_roku.remote.assert_called_with("home")
await hass.services.async_call(
MP_DOMAIN,
SERVICE_PLAY_MEDIA,
{
ATTR_ENTITY_ID: MAIN_ENTITY_ID,
ATTR_MEDIA_CONTENT_TYPE: MEDIA_TYPE_APP,
ATTR_MEDIA_CONTENT_ID: "11",
},
blocking=True,
)
assert mock_roku.launch.call_count == 1
mock_roku.launch.assert_called_with("11", {})
await hass.services.async_call(
MP_DOMAIN,
SERVICE_PLAY_MEDIA,
{
ATTR_ENTITY_ID: MAIN_ENTITY_ID,
ATTR_MEDIA_CONTENT_TYPE: MEDIA_TYPE_APP,
ATTR_MEDIA_CONTENT_ID: "291097",
ATTR_MEDIA_EXTRA: {
ATTR_MEDIA_TYPE: "movie",
ATTR_CONTENT_ID: "8e06a8b7-d667-4e31-939d-f40a6dd78a88",
},
blocking=True,
)
},
blocking=True,
)
launch_mock.assert_called_once_with("11", {})
assert mock_roku.launch.call_count == 2
mock_roku.launch.assert_called_with(
"291097",
{
"contentID": "8e06a8b7-d667-4e31-939d-f40a6dd78a88",
"MediaType": "movie",
},
)
with patch("homeassistant.components.roku.coordinator.Roku.launch") as launch_mock:
await hass.services.async_call(
MP_DOMAIN,
SERVICE_PLAY_MEDIA,
{
ATTR_ENTITY_ID: MAIN_ENTITY_ID,
ATTR_MEDIA_CONTENT_TYPE: MEDIA_TYPE_APP,
ATTR_MEDIA_CONTENT_ID: "291097",
ATTR_MEDIA_EXTRA: {
ATTR_MEDIA_TYPE: "movie",
ATTR_CONTENT_ID: "8e06a8b7-d667-4e31-939d-f40a6dd78a88",
},
await hass.services.async_call(
MP_DOMAIN,
SERVICE_PLAY_MEDIA,
{
ATTR_ENTITY_ID: MAIN_ENTITY_ID,
ATTR_MEDIA_CONTENT_TYPE: MEDIA_TYPE_URL,
ATTR_MEDIA_CONTENT_ID: "https://awesome.tld/media.mp4",
ATTR_MEDIA_EXTRA: {
ATTR_NAME: "Sent from HA",
ATTR_FORMAT: "mp4",
},
blocking=True,
)
},
blocking=True,
)
launch_mock.assert_called_once_with(
"291097",
{
"contentID": "8e06a8b7-d667-4e31-939d-f40a6dd78a88",
"MediaType": "movie",
},
)
assert mock_roku.play_video.call_count == 1
mock_roku.play_video.assert_called_with(
"https://awesome.tld/media.mp4",
{
"videoName": "Sent from HA",
"videoFormat": "mp4",
},
)
with patch("homeassistant.components.roku.coordinator.Roku.play_video") as pv_mock:
await hass.services.async_call(
MP_DOMAIN,
SERVICE_PLAY_MEDIA,
{
ATTR_ENTITY_ID: MAIN_ENTITY_ID,
ATTR_MEDIA_CONTENT_TYPE: MEDIA_TYPE_URL,
ATTR_MEDIA_CONTENT_ID: "https://awesome.tld/media.mp4",
ATTR_MEDIA_EXTRA: {
ATTR_NAME: "Sent from HA",
ATTR_FORMAT: "mp4",
},
},
blocking=True,
)
await hass.services.async_call(
MP_DOMAIN,
SERVICE_PLAY_MEDIA,
{
ATTR_ENTITY_ID: MAIN_ENTITY_ID,
ATTR_MEDIA_CONTENT_TYPE: FORMAT_CONTENT_TYPE[HLS_PROVIDER],
ATTR_MEDIA_CONTENT_ID: "https://awesome.tld/api/hls/api_token/master_playlist.m3u8",
},
blocking=True,
)
pv_mock.assert_called_once_with(
"https://awesome.tld/media.mp4",
{
"videoName": "Sent from HA",
"videoFormat": "mp4",
},
)
assert mock_roku.play_video.call_count == 2
mock_roku.play_video.assert_called_with(
"https://awesome.tld/api/hls/api_token/master_playlist.m3u8",
{
"MediaType": "hls",
},
)
with patch("homeassistant.components.roku.coordinator.Roku.play_video") as pv_mock:
await hass.services.async_call(
MP_DOMAIN,
SERVICE_PLAY_MEDIA,
{
ATTR_ENTITY_ID: MAIN_ENTITY_ID,
ATTR_MEDIA_CONTENT_TYPE: FORMAT_CONTENT_TYPE[HLS_PROVIDER],
ATTR_MEDIA_CONTENT_ID: "https://awesome.tld/api/hls/api_token/master_playlist.m3u8",
},
blocking=True,
)
await hass.services.async_call(
MP_DOMAIN,
SERVICE_SELECT_SOURCE,
{ATTR_ENTITY_ID: MAIN_ENTITY_ID, ATTR_INPUT_SOURCE: "Netflix"},
blocking=True,
)
pv_mock.assert_called_once_with(
"https://awesome.tld/api/hls/api_token/master_playlist.m3u8",
{
"MediaType": "hls",
},
)
assert mock_roku.launch.call_count == 3
mock_roku.launch.assert_called_with("12")
with patch("homeassistant.components.roku.coordinator.Roku.remote") 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,
)
await hass.services.async_call(
MP_DOMAIN,
SERVICE_SELECT_SOURCE,
{ATTR_ENTITY_ID: MAIN_ENTITY_ID, ATTR_INPUT_SOURCE: 12},
blocking=True,
)
remote_mock.assert_called_once_with("home")
with patch("homeassistant.components.roku.coordinator.Roku.launch") as launch_mock:
await hass.services.async_call(
MP_DOMAIN,
SERVICE_SELECT_SOURCE,
{ATTR_ENTITY_ID: MAIN_ENTITY_ID, ATTR_INPUT_SOURCE: "Netflix"},
blocking=True,
)
launch_mock.assert_called_once_with("12")
with patch("homeassistant.components.roku.coordinator.Roku.launch") as launch_mock:
await hass.services.async_call(
MP_DOMAIN,
SERVICE_SELECT_SOURCE,
{ATTR_ENTITY_ID: MAIN_ENTITY_ID, ATTR_INPUT_SOURCE: 12},
blocking=True,
)
launch_mock.assert_called_once_with("12")
assert mock_roku.launch.call_count == 4
mock_roku.launch.assert_called_with("12")
@pytest.mark.parametrize("mock_roku", ["roku/rokutv-7820x.json"], indirect=True)
async def test_tv_services(
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker
hass: HomeAssistant,
init_integration: MockConfigEntry,
mock_roku: MagicMock,
) -> None:
"""Test the media player services related to Roku TV."""
await setup_integration(
hass,
aioclient_mock,
device="rokutv",
app="tvinput-dtv",
host=TV_HOST,
unique_id=TV_SERIAL,
await hass.services.async_call(
MP_DOMAIN, SERVICE_VOLUME_UP, {ATTR_ENTITY_ID: TV_ENTITY_ID}, blocking=True
)
with patch("homeassistant.components.roku.coordinator.Roku.remote") as remote_mock:
await hass.services.async_call(
MP_DOMAIN, SERVICE_VOLUME_UP, {ATTR_ENTITY_ID: TV_ENTITY_ID}, blocking=True
)
assert mock_roku.remote.call_count == 1
mock_roku.remote.assert_called_with("volume_up")
remote_mock.assert_called_once_with("volume_up")
await hass.services.async_call(
MP_DOMAIN,
SERVICE_VOLUME_DOWN,
{ATTR_ENTITY_ID: TV_ENTITY_ID},
blocking=True,
)
with patch("homeassistant.components.roku.coordinator.Roku.remote") as remote_mock:
await hass.services.async_call(
MP_DOMAIN,
SERVICE_VOLUME_DOWN,
{ATTR_ENTITY_ID: TV_ENTITY_ID},
blocking=True,
)
assert mock_roku.remote.call_count == 2
mock_roku.remote.assert_called_with("volume_down")
remote_mock.assert_called_once_with("volume_down")
await hass.services.async_call(
MP_DOMAIN,
SERVICE_VOLUME_MUTE,
{ATTR_ENTITY_ID: TV_ENTITY_ID, ATTR_MEDIA_VOLUME_MUTED: True},
blocking=True,
)
with patch("homeassistant.components.roku.coordinator.Roku.remote") 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,
)
assert mock_roku.remote.call_count == 3
mock_roku.remote.assert_called_with("volume_mute")
remote_mock.assert_called_once_with("volume_mute")
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,
)
with patch("homeassistant.components.roku.coordinator.Roku.tune") 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_with("55")
assert mock_roku.tune.call_count == 1
mock_roku.tune.assert_called_with("55")
async def test_media_browse(hass, aioclient_mock, hass_ws_client):
@pytest.mark.parametrize("mock_roku", ["roku/rokutv-7820x.json"], indirect=True)
async def test_media_browse(
hass,
init_integration,
mock_roku,
hass_ws_client,
):
"""Test browsing media."""
await setup_integration(
hass,
aioclient_mock,
device="rokutv",
app="tvinput-dtv",
host=TV_HOST,
unique_id=TV_SERIAL,
)
client = await hass_ws_client(hass)
await client.send_json(
@ -741,7 +695,13 @@ async def test_media_browse(hass, aioclient_mock, hass_ws_client):
assert not msg["success"]
async def test_media_browse_internal(hass, aioclient_mock, hass_ws_client):
@pytest.mark.parametrize("mock_roku", ["roku/rokutv-7820x.json"], indirect=True)
async def test_media_browse_internal(
hass,
init_integration,
mock_roku,
hass_ws_client,
):
"""Test browsing media with internal url."""
await async_process_ha_core_config(
hass,
@ -750,15 +710,6 @@ async def test_media_browse_internal(hass, aioclient_mock, hass_ws_client):
assert hass.config.internal_url == "http://example.local:8123"
await setup_integration(
hass,
aioclient_mock,
device="rokutv",
app="tvinput-dtv",
host=TV_HOST,
unique_id=TV_SERIAL,
)
client = await hass_ws_client(hass)
with patch(
@ -804,16 +755,15 @@ async def test_media_browse_internal(hass, aioclient_mock, hass_ws_client):
async def test_integration_services(
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker
hass: HomeAssistant,
init_integration: MockConfigEntry,
mock_roku: MagicMock,
) -> None:
"""Test integration services."""
await setup_integration(hass, aioclient_mock)
with patch("homeassistant.components.roku.coordinator.Roku.search") as search_mock:
await hass.services.async_call(
DOMAIN,
SERVICE_SEARCH,
{ATTR_ENTITY_ID: MAIN_ENTITY_ID, ATTR_KEYWORD: "Space Jam"},
blocking=True,
)
search_mock.assert_called_once_with("Space Jam")
await hass.services.async_call(
DOMAIN,
SERVICE_SEARCH,
{ATTR_ENTITY_ID: MAIN_ENTITY_ID, ATTR_KEYWORD: "Space Jam"},
blocking=True,
)
mock_roku.search.assert_called_once_with("Space Jam")

View File

@ -1,5 +1,5 @@
"""The tests for the Roku remote platform."""
from unittest.mock import patch
from unittest.mock import MagicMock
from homeassistant.components.remote import (
ATTR_COMMAND,
@ -10,26 +10,23 @@ from homeassistant.const import ATTR_ENTITY_ID, SERVICE_TURN_OFF, SERVICE_TURN_O
from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry as er
from tests.components.roku import UPNP_SERIAL, setup_integration
from tests.test_util.aiohttp import AiohttpClientMocker
from tests.common import MockConfigEntry
from tests.components.roku import UPNP_SERIAL
MAIN_ENTITY_ID = f"{REMOTE_DOMAIN}.my_roku_3"
# pylint: disable=redefined-outer-name
async def test_setup(hass: HomeAssistant, aioclient_mock: AiohttpClientMocker) -> None:
async def test_setup(hass: HomeAssistant, init_integration: MockConfigEntry) -> None:
"""Test setup with basic config."""
await setup_integration(hass, aioclient_mock)
assert hass.states.get(MAIN_ENTITY_ID)
async def test_unique_id(
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker
hass: HomeAssistant, init_integration: MockConfigEntry
) -> None:
"""Test unique id."""
await setup_integration(hass, aioclient_mock)
entity_registry = er.async_get(hass)
main = entity_registry.async_get(MAIN_ENTITY_ID)
@ -37,34 +34,34 @@ async def test_unique_id(
async def test_main_services(
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker
hass: HomeAssistant,
init_integration: MockConfigEntry,
mock_roku: MagicMock,
) -> None:
"""Test platform services."""
await setup_integration(hass, aioclient_mock)
await hass.services.async_call(
REMOTE_DOMAIN,
SERVICE_TURN_OFF,
{ATTR_ENTITY_ID: MAIN_ENTITY_ID},
blocking=True,
)
assert mock_roku.remote.call_count == 1
mock_roku.remote.assert_called_with("poweroff")
with patch("homeassistant.components.roku.coordinator.Roku.remote") as remote_mock:
await hass.services.async_call(
REMOTE_DOMAIN,
SERVICE_TURN_OFF,
{ATTR_ENTITY_ID: MAIN_ENTITY_ID},
blocking=True,
)
remote_mock.assert_called_once_with("poweroff")
await hass.services.async_call(
REMOTE_DOMAIN,
SERVICE_TURN_ON,
{ATTR_ENTITY_ID: MAIN_ENTITY_ID},
blocking=True,
)
assert mock_roku.remote.call_count == 2
mock_roku.remote.assert_called_with("poweron")
with patch("homeassistant.components.roku.coordinator.Roku.remote") as remote_mock:
await hass.services.async_call(
REMOTE_DOMAIN,
SERVICE_TURN_ON,
{ATTR_ENTITY_ID: MAIN_ENTITY_ID},
blocking=True,
)
remote_mock.assert_called_once_with("poweron")
with patch("homeassistant.components.roku.coordinator.Roku.remote") as remote_mock:
await hass.services.async_call(
REMOTE_DOMAIN,
SERVICE_SEND_COMMAND,
{ATTR_ENTITY_ID: MAIN_ENTITY_ID, ATTR_COMMAND: ["home"]},
blocking=True,
)
remote_mock.assert_called_once_with("home")
await hass.services.async_call(
REMOTE_DOMAIN,
SERVICE_SEND_COMMAND,
{ATTR_ENTITY_ID: MAIN_ENTITY_ID, ATTR_COMMAND: ["home"]},
blocking=True,
)
assert mock_roku.remote.call_count == 3
mock_roku.remote.assert_called_with("home")

View File

@ -1,4 +1,8 @@
"""Tests for the sensors provided by the Roku integration."""
from unittest.mock import MagicMock
import pytest
from homeassistant.components.roku.const import DOMAIN
from homeassistant.const import (
ATTR_DEVICE_CLASS,
@ -10,17 +14,15 @@ from homeassistant.core import HomeAssistant
from homeassistant.helpers import device_registry as dr, entity_registry as er
from homeassistant.helpers.entity import EntityCategory
from tests.components.roku import UPNP_SERIAL, setup_integration
from tests.test_util.aiohttp import AiohttpClientMocker
from tests.common import MockConfigEntry
from tests.components.roku import UPNP_SERIAL
async def test_roku_sensors(
hass: HomeAssistant,
aioclient_mock: AiohttpClientMocker,
init_integration: MockConfigEntry,
) -> None:
"""Test the Roku sensors."""
await setup_integration(hass, aioclient_mock)
entity_registry = er.async_get(hass)
device_registry = dr.async_get(hass)
@ -59,22 +61,17 @@ async def test_roku_sensors(
assert device_entry.name == "My Roku 3"
assert device_entry.entry_type is None
assert device_entry.sw_version == "7.5.0"
assert device_entry.hw_version == "4200X"
assert device_entry.suggested_area is None
@pytest.mark.parametrize("mock_roku", ["roku/rokutv-7820x.json"], indirect=True)
async def test_rokutv_sensors(
hass: HomeAssistant,
aioclient_mock: AiohttpClientMocker,
init_integration: MockConfigEntry,
mock_roku: MagicMock,
) -> None:
"""Test the Roku TV sensors."""
await setup_integration(
hass,
aioclient_mock,
device="rokutv",
app="tvinput-dtv",
host="192.168.1.161",
unique_id="YN00H5555555",
)
entity_registry = er.async_get(hass)
device_registry = dr.async_get(hass)
@ -113,3 +110,5 @@ async def test_rokutv_sensors(
assert device_entry.name == '58" Onn Roku TV'
assert device_entry.entry_type is None
assert device_entry.sw_version == "9.2.0"
assert device_entry.hw_version == "7820X"
assert device_entry.suggested_area == "Living room"