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.""" """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 import ssdp, zeroconf
from homeassistant.components.roku.const import DOMAIN
from homeassistant.components.ssdp import ATTR_UPNP_FRIENDLY_NAME, ATTR_UPNP_SERIAL 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 = "Roku 3"
NAME_ROKUTV = '58" Onn Roku TV' NAME_ROKUTV = '58" Onn Roku TV'
@ -42,174 +32,3 @@ MOCK_HOMEKIT_DISCOVERY_INFO = zeroconf.ZeroconfServiceInfo(
}, },
type="mock_type", 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.""" """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.binary_sensor import STATE_OFF, STATE_ON
from homeassistant.components.roku.const import DOMAIN from homeassistant.components.roku.const import DOMAIN
from homeassistant.const import ATTR_DEVICE_CLASS, ATTR_FRIENDLY_NAME, ATTR_ICON 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 import device_registry as dr, entity_registry as er
from homeassistant.helpers.entity import EntityCategory from homeassistant.helpers.entity import EntityCategory
from tests.components.roku import UPNP_SERIAL, setup_integration from tests.common import MockConfigEntry
from tests.test_util.aiohttp import AiohttpClientMocker from tests.components.roku import UPNP_SERIAL
async def test_roku_binary_sensors( async def test_roku_binary_sensors(
hass: HomeAssistant, hass: HomeAssistant, init_integration: MockConfigEntry
aioclient_mock: AiohttpClientMocker,
) -> None: ) -> None:
"""Test the Roku binary sensors.""" """Test the Roku binary sensors."""
await setup_integration(hass, aioclient_mock)
entity_registry = er.async_get(hass) entity_registry = er.async_get(hass)
device_registry = dr.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.name == "My Roku 3"
assert device_entry.entry_type is None assert device_entry.entry_type is None
assert device_entry.sw_version == "7.5.0" 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( async def test_rokutv_binary_sensors(
hass: HomeAssistant, hass: HomeAssistant,
aioclient_mock: AiohttpClientMocker, init_integration: MockConfigEntry,
mock_roku: MagicMock,
) -> None: ) -> None:
"""Test the Roku binary sensors.""" """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) entity_registry = er.async_get(hass)
device_registry = dr.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.name == '58" Onn Roku TV'
assert device_entry.entry_type is None assert device_entry.entry_type is None
assert device_entry.sw_version == "9.2.0" 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.""" """Test the Roku config flow."""
import dataclasses 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.components.roku.const import DOMAIN
from homeassistant.config_entries import SOURCE_HOMEKIT, SOURCE_SSDP, SOURCE_USER from homeassistant.config_entries import SOURCE_HOMEKIT, SOURCE_SSDP, SOURCE_USER
@ -12,6 +15,7 @@ from homeassistant.data_entry_flow import (
RESULT_TYPE_FORM, RESULT_TYPE_FORM,
) )
from tests.common import MockConfigEntry
from tests.components.roku import ( from tests.components.roku import (
HOMEKIT_HOST, HOMEKIT_HOST,
HOST, HOST,
@ -19,20 +23,18 @@ from tests.components.roku import (
MOCK_SSDP_DISCOVERY_INFO, MOCK_SSDP_DISCOVERY_INFO,
NAME_ROKUTV, NAME_ROKUTV,
UPNP_FRIENDLY_NAME, UPNP_FRIENDLY_NAME,
mock_connection,
setup_integration,
) )
from tests.test_util.aiohttp import AiohttpClientMocker
async def test_duplicate_error( async def test_duplicate_error(
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker hass: HomeAssistant,
mock_config_entry: MockConfigEntry,
mock_roku_config_flow: MagicMock,
) -> None: ) -> None:
"""Test that errors are shown when duplicates are added.""" """Test that errors are shown when duplicates are added."""
await setup_integration(hass, aioclient_mock, skip_entry_setup=True) mock_config_entry.add_to_hass(hass)
mock_connection(aioclient_mock)
user_input = {CONF_HOST: HOST} user_input = {CONF_HOST: mock_config_entry.data[CONF_HOST]}
result = await hass.config_entries.flow.async_init( result = await hass.config_entries.flow.async_init(
DOMAIN, context={CONF_SOURCE: SOURCE_USER}, data=user_input 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["type"] == RESULT_TYPE_ABORT
assert result["reason"] == "already_configured" 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( result = await hass.config_entries.flow.async_init(
DOMAIN, context={CONF_SOURCE: SOURCE_USER}, data=user_input DOMAIN, context={CONF_SOURCE: SOURCE_USER}, data=user_input
) )
@ -57,11 +59,12 @@ async def test_duplicate_error(
assert result["reason"] == "already_configured" 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.""" """Test the user step."""
mock_connection(aioclient_mock)
result = await hass.config_entries.flow.async_init( result = await hass.config_entries.flow.async_init(
DOMAIN, context={CONF_SOURCE: SOURCE_USER} DOMAIN, context={CONF_SOURCE: SOURCE_USER}
) )
@ -69,29 +72,26 @@ async def test_form(hass: HomeAssistant, aioclient_mock: AiohttpClientMocker) ->
assert result["errors"] == {} assert result["errors"] == {}
user_input = {CONF_HOST: HOST} user_input = {CONF_HOST: HOST}
with patch( result = await hass.config_entries.flow.async_configure(
"homeassistant.components.roku.async_setup_entry", flow_id=result["flow_id"], user_input=user_input
return_value=True, )
) as mock_setup_entry: 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["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 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( async def test_form_cannot_connect(
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker hass: HomeAssistant, mock_roku_config_flow: MagicMock
) -> None: ) -> None:
"""Test we handle cannot connect roku error.""" """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( result = await hass.config_entries.flow.async_init(
DOMAIN, context={CONF_SOURCE: SOURCE_USER} DOMAIN, context={CONF_SOURCE: SOURCE_USER}
@ -106,40 +106,29 @@ async def test_form_cannot_connect(
async def test_form_unknown_error( async def test_form_unknown_error(
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker hass: HomeAssistant, mock_roku_config_flow: MagicMock
) -> None: ) -> None:
"""Test we handle unknown error.""" """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( result = await hass.config_entries.flow.async_init(
DOMAIN, context={CONF_SOURCE: SOURCE_USER} DOMAIN, context={CONF_SOURCE: SOURCE_USER}
) )
user_input = {CONF_HOST: HOST} user_input = {CONF_HOST: HOST}
with patch( result = await hass.config_entries.flow.async_configure(
"homeassistant.components.roku.config_flow.Roku._request", flow_id=result["flow_id"], user_input=user_input
side_effect=Exception, )
) as mock_validate_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["type"] == RESULT_TYPE_ABORT
assert result["reason"] == "unknown" assert result["reason"] == "unknown"
await hass.async_block_till_done()
assert len(mock_validate_input.mock_calls) == 1
async def test_homekit_cannot_connect( async def test_homekit_cannot_connect(
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker hass: HomeAssistant, mock_roku_config_flow: MagicMock
) -> None: ) -> None:
"""Test we abort homekit flow on connection error.""" """Test we abort homekit flow on connection error."""
mock_connection( mock_roku_config_flow.update.side_effect = RokuConnectionError
aioclient_mock,
host=HOMEKIT_HOST,
error=True,
)
discovery_info = dataclasses.replace(MOCK_HOMEKIT_DISCOVERY_INFO) discovery_info = dataclasses.replace(MOCK_HOMEKIT_DISCOVERY_INFO)
result = await hass.config_entries.flow.async_init( result = await hass.config_entries.flow.async_init(
@ -153,32 +142,31 @@ async def test_homekit_cannot_connect(
async def test_homekit_unknown_error( async def test_homekit_unknown_error(
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker hass: HomeAssistant, mock_roku_config_flow: MagicMock
) -> None: ) -> None:
"""Test we abort homekit flow on unknown error.""" """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) discovery_info = dataclasses.replace(MOCK_HOMEKIT_DISCOVERY_INFO)
with patch( result = await hass.config_entries.flow.async_init(
"homeassistant.components.roku.config_flow.Roku._request", DOMAIN,
side_effect=Exception, 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["type"] == RESULT_TYPE_ABORT
assert result["reason"] == "unknown" assert result["reason"] == "unknown"
@pytest.mark.parametrize(
"mock_roku_config_flow", ["roku/rokutv-7820x.json"], indirect=True
)
async def test_homekit_discovery( async def test_homekit_discovery(
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker hass: HomeAssistant,
mock_roku_config_flow: MagicMock,
mock_setup_entry: None,
) -> None: ) -> None:
"""Test the homekit discovery flow.""" """Test the homekit discovery flow."""
mock_connection(aioclient_mock, device="rokutv", host=HOMEKIT_HOST)
discovery_info = dataclasses.replace(MOCK_HOMEKIT_DISCOVERY_INFO) discovery_info = dataclasses.replace(MOCK_HOMEKIT_DISCOVERY_INFO)
result = await hass.config_entries.flow.async_init( result = await hass.config_entries.flow.async_init(
DOMAIN, context={CONF_SOURCE: SOURCE_HOMEKIT}, data=discovery_info 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["step_id"] == "discovery_confirm"
assert result["description_placeholders"] == {CONF_NAME: NAME_ROKUTV} assert result["description_placeholders"] == {CONF_NAME: NAME_ROKUTV}
with patch( result = await hass.config_entries.flow.async_configure(
"homeassistant.components.roku.async_setup_entry", flow_id=result["flow_id"], user_input={}
return_value=True, )
) as mock_setup_entry: 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["type"] == RESULT_TYPE_CREATE_ENTRY
assert result["title"] == NAME_ROKUTV assert result["title"] == NAME_ROKUTV
assert result["data"] assert "data" in result
assert result["data"][CONF_HOST] == HOMEKIT_HOST assert result["data"][CONF_HOST] == HOMEKIT_HOST
assert result["data"][CONF_NAME] == NAME_ROKUTV assert result["data"][CONF_NAME] == NAME_ROKUTV
assert len(mock_setup_entry.mock_calls) == 1
# test abort on existing host # test abort on existing host
discovery_info = dataclasses.replace(MOCK_HOMEKIT_DISCOVERY_INFO) discovery_info = dataclasses.replace(MOCK_HOMEKIT_DISCOVERY_INFO)
result = await hass.config_entries.flow.async_init( result = await hass.config_entries.flow.async_init(
@ -217,10 +199,10 @@ async def test_homekit_discovery(
async def test_ssdp_cannot_connect( async def test_ssdp_cannot_connect(
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker hass: HomeAssistant, mock_roku_config_flow: MagicMock
) -> None: ) -> None:
"""Test we abort SSDP flow on connection error.""" """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) discovery_info = dataclasses.replace(MOCK_SSDP_DISCOVERY_INFO)
result = await hass.config_entries.flow.async_init( result = await hass.config_entries.flow.async_init(
@ -234,32 +216,28 @@ async def test_ssdp_cannot_connect(
async def test_ssdp_unknown_error( async def test_ssdp_unknown_error(
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker hass: HomeAssistant, mock_roku_config_flow: MagicMock
) -> None: ) -> None:
"""Test we abort SSDP flow on unknown error.""" """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) discovery_info = dataclasses.replace(MOCK_SSDP_DISCOVERY_INFO)
with patch( result = await hass.config_entries.flow.async_init(
"homeassistant.components.roku.config_flow.Roku._request", DOMAIN,
side_effect=Exception, 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["type"] == RESULT_TYPE_ABORT
assert result["reason"] == "unknown" assert result["reason"] == "unknown"
async def test_ssdp_discovery( async def test_ssdp_discovery(
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker hass: HomeAssistant,
mock_roku_config_flow: MagicMock,
mock_setup_entry: None,
) -> None: ) -> None:
"""Test the SSDP discovery flow.""" """Test the SSDP discovery flow."""
mock_connection(aioclient_mock)
discovery_info = dataclasses.replace(MOCK_SSDP_DISCOVERY_INFO) discovery_info = dataclasses.replace(MOCK_SSDP_DISCOVERY_INFO)
result = await hass.config_entries.flow.async_init( result = await hass.config_entries.flow.async_init(
DOMAIN, context={CONF_SOURCE: SOURCE_SSDP}, data=discovery_info 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["step_id"] == "discovery_confirm"
assert result["description_placeholders"] == {CONF_NAME: UPNP_FRIENDLY_NAME} assert result["description_placeholders"] == {CONF_NAME: UPNP_FRIENDLY_NAME}
with patch( result = await hass.config_entries.flow.async_configure(
"homeassistant.components.roku.async_setup_entry", flow_id=result["flow_id"], user_input={}
return_value=True, )
) as mock_setup_entry: 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["type"] == RESULT_TYPE_CREATE_ENTRY
assert result["title"] == UPNP_FRIENDLY_NAME assert result["title"] == UPNP_FRIENDLY_NAME
@ -284,5 +258,3 @@ async def test_ssdp_discovery(
assert result["data"] assert result["data"]
assert result["data"][CONF_HOST] == HOST assert result["data"][CONF_HOST] == HOST
assert result["data"][CONF_NAME] == UPNP_FRIENDLY_NAME 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.""" """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.components.roku.const import DOMAIN
from homeassistant.config_entries import ConfigEntryState from homeassistant.config_entries import ConfigEntryState
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from tests.components.roku import setup_integration from tests.common import MockConfigEntry
from tests.test_util.aiohttp import AiohttpClientMocker
@patch(
"homeassistant.components.roku.coordinator.Roku._request",
side_effect=RokuConnectionError,
)
async def test_config_entry_not_ready( async def test_config_entry_not_ready(
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker mock_request: MagicMock, hass: HomeAssistant, mock_config_entry: MockConfigEntry
) -> None: ) -> None:
"""Test the Roku configuration entry not ready.""" """Test the Roku configuration entry not ready."""
entry = await setup_integration(hass, aioclient_mock, error=True) mock_config_entry.add_to_hass(hass)
await hass.config_entries.async_setup(mock_config_entry.entry_id)
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)
await hass.async_block_till_done() await hass.async_block_till_done()
assert entry.entry_id not in hass.data[DOMAIN] assert mock_request.call_count == 1
assert entry.state is ConfigEntryState.NOT_LOADED 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.""" """Tests for the Roku Media Player platform."""
from datetime import timedelta from datetime import timedelta
from unittest.mock import patch from unittest.mock import MagicMock, patch
import pytest
from rokuecp import RokuError from rokuecp import RokuError
from homeassistant.components.media_player import MediaPlayerDeviceClass 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.helpers import device_registry as dr, entity_registry as er
from homeassistant.util import dt as dt_util from homeassistant.util import dt as dt_util
from tests.common import async_fire_time_changed from tests.common import MockConfigEntry, async_fire_time_changed
from tests.components.roku import NAME_ROKUTV, UPNP_SERIAL, setup_integration
from tests.test_util.aiohttp import AiohttpClientMocker
MAIN_ENTITY_ID = f"{MP_DOMAIN}.my_roku_3" MAIN_ENTITY_ID = f"{MP_DOMAIN}.my_roku_3"
TV_ENTITY_ID = f"{MP_DOMAIN}.58_onn_roku_tv" 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, init_integration: MockConfigEntry) -> None:
async def test_setup(hass: HomeAssistant, aioclient_mock: AiohttpClientMocker) -> None:
"""Test setup with basic config.""" """Test setup with basic config."""
await setup_integration(hass, aioclient_mock)
entity_registry = er.async_get(hass) entity_registry = er.async_get(hass)
device_registry = dr.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 state
assert entry assert entry
assert entry.original_device_class is MediaPlayerDeviceClass.RECEIVER assert entry.original_device_class is MediaPlayerDeviceClass.RECEIVER
assert entry.unique_id == UPNP_SERIAL assert entry.unique_id == "1GU48T017973"
assert entry.device_id assert entry.device_id
device_entry = device_registry.async_get(entry.device_id) device_entry = device_registry.async_get(entry.device_id)
assert device_entry assert device_entry
assert device_entry.identifiers == {(DOMAIN, UPNP_SERIAL)} assert device_entry.identifiers == {(DOMAIN, "1GU48T017973")}
assert device_entry.connections == { assert device_entry.connections == {
(dr.CONNECTION_NETWORK_MAC, "b0:a7:37:96:4d:fb"), (dr.CONNECTION_NETWORK_MAC, "b0:a7:37:96:4d:fb"),
(dr.CONNECTION_NETWORK_MAC, "b0:a7:37:96:4d:fa"), (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.model == "Roku 3"
assert device_entry.name == "My Roku 3" assert device_entry.name == "My Roku 3"
assert device_entry.entry_type is None assert device_entry.entry_type is None
assert device_entry.hw_version == "4200X"
assert device_entry.sw_version == "7.5.0" 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( async def test_idle_setup(
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker hass: HomeAssistant,
init_integration: MockConfigEntry,
mock_roku: MagicMock,
) -> None: ) -> None:
"""Test setup with idle device.""" """Test setup with idle device."""
await setup_integration(hass, aioclient_mock, power=False)
state = hass.states.get(MAIN_ENTITY_ID) state = hass.states.get(MAIN_ENTITY_ID)
assert state assert state
assert state.state == STATE_STANDBY assert state.state == STATE_STANDBY
@pytest.mark.parametrize("mock_roku", ["roku/rokutv-7820x.json"], indirect=True)
async def test_tv_setup( async def test_tv_setup(
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker hass: HomeAssistant,
init_integration: MockConfigEntry,
mock_roku: MagicMock,
) -> None: ) -> None:
"""Test Roku TV setup.""" """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) entity_registry = er.async_get(hass)
device_registry = dr.async_get(hass) device_registry = dr.async_get(hass)
@ -155,37 +141,41 @@ async def test_tv_setup(
assert state assert state
assert entry assert entry
assert entry.original_device_class is MediaPlayerDeviceClass.TV assert entry.original_device_class is MediaPlayerDeviceClass.TV
assert entry.unique_id == TV_SERIAL assert entry.unique_id == "YN00H5555555"
assert entry.device_id assert entry.device_id
device_entry = device_registry.async_get(entry.device_id) device_entry = device_registry.async_get(entry.device_id)
assert device_entry assert device_entry
assert device_entry.identifiers == {(DOMAIN, TV_SERIAL)} assert device_entry.identifiers == {(DOMAIN, "YN00H5555555")}
assert device_entry.connections == { assert device_entry.connections == {
(dr.CONNECTION_NETWORK_MAC, "d8:13:99:f8:b0:c6"), (dr.CONNECTION_NETWORK_MAC, "d8:13:99:f8:b0:c6"),
(dr.CONNECTION_NETWORK_MAC, "d4:3a:2e:07:fd:cb"), (dr.CONNECTION_NETWORK_MAC, "d4:3a:2e:07:fd:cb"),
} }
assert device_entry.manufacturer == TV_MANUFACTURER assert device_entry.manufacturer == "Onn"
assert device_entry.model == TV_MODEL assert device_entry.model == "100005844"
assert device_entry.name == '58" Onn Roku TV' assert device_entry.name == '58" Onn Roku TV'
assert device_entry.entry_type is None assert device_entry.entry_type is None
assert device_entry.sw_version == "9.2.0"
assert device_entry.hw_version == "7820X" 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( async def test_availability(
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker hass: HomeAssistant,
mock_roku: MagicMock,
mock_config_entry: MockConfigEntry,
) -> None: ) -> None:
"""Test entity availability.""" """Test entity availability."""
now = dt_util.utcnow() now = dt_util.utcnow()
future = now + timedelta(minutes=1) future = now + timedelta(minutes=1)
mock_config_entry.add_to_hass(hass)
with patch("homeassistant.util.dt.utcnow", return_value=now): 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( with patch("homeassistant.util.dt.utcnow", return_value=future):
"homeassistant.components.roku.coordinator.Roku.update", side_effect=RokuError mock_roku.update.side_effect = RokuError
), patch("homeassistant.util.dt.utcnow", return_value=future):
async_fire_time_changed(hass, future) async_fire_time_changed(hass, future)
await hass.async_block_till_done() await hass.async_block_till_done()
assert hass.states.get(MAIN_ENTITY_ID).state == STATE_UNAVAILABLE assert hass.states.get(MAIN_ENTITY_ID).state == STATE_UNAVAILABLE
@ -193,17 +183,18 @@ async def test_availability(
future += timedelta(minutes=1) future += timedelta(minutes=1)
with patch("homeassistant.util.dt.utcnow", return_value=future): with patch("homeassistant.util.dt.utcnow", return_value=future):
mock_roku.update.side_effect = None
async_fire_time_changed(hass, future) async_fire_time_changed(hass, future)
await hass.async_block_till_done() await hass.async_block_till_done()
assert hass.states.get(MAIN_ENTITY_ID).state == STATE_HOME assert hass.states.get(MAIN_ENTITY_ID).state == STATE_HOME
async def test_supported_features( async def test_supported_features(
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker hass: HomeAssistant,
init_integration: MockConfigEntry,
mock_roku: MagicMock,
) -> None: ) -> None:
"""Test supported features.""" """Test supported features."""
await setup_integration(hass, aioclient_mock)
# Features supported for Rokus # Features supported for Rokus
state = hass.states.get(MAIN_ENTITY_ID) state = hass.states.get(MAIN_ENTITY_ID)
assert ( 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( async def test_tv_supported_features(
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker hass: HomeAssistant,
init_integration: MockConfigEntry,
mock_roku: MagicMock,
) -> None: ) -> None:
"""Test supported features for Roku TV.""" """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) state = hass.states.get(TV_ENTITY_ID)
assert state
assert ( assert (
SUPPORT_PREVIOUS_TRACK SUPPORT_PREVIOUS_TRACK
| SUPPORT_NEXT_TRACK | SUPPORT_NEXT_TRACK
@ -253,12 +239,11 @@ async def test_tv_supported_features(
async def test_attributes( async def test_attributes(
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker hass: HomeAssistant, init_integration: MockConfigEntry
) -> None: ) -> None:
"""Test attributes.""" """Test attributes."""
await setup_integration(hass, aioclient_mock)
state = hass.states.get(MAIN_ENTITY_ID) state = hass.states.get(MAIN_ENTITY_ID)
assert state
assert state.state == STATE_HOME assert state.state == STATE_HOME
assert state.attributes.get(ATTR_MEDIA_CONTENT_TYPE) is None 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" assert state.attributes.get(ATTR_INPUT_SOURCE) == "Roku"
@pytest.mark.parametrize("mock_roku", ["roku/roku3-app.json"], indirect=True)
async def test_attributes_app( async def test_attributes_app(
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker hass: HomeAssistant,
init_integration: MockConfigEntry,
mock_roku: MagicMock,
) -> None: ) -> None:
"""Test attributes for app.""" """Test attributes for app."""
await setup_integration(hass, aioclient_mock, app="netflix")
state = hass.states.get(MAIN_ENTITY_ID) state = hass.states.get(MAIN_ENTITY_ID)
assert state
assert state.state == STATE_ON assert state.state == STATE_ON
assert state.attributes.get(ATTR_MEDIA_CONTENT_TYPE) == MEDIA_TYPE_APP 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" 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( async def test_attributes_app_media_playing(
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker hass: HomeAssistant,
init_integration: MockConfigEntry,
mock_roku: MagicMock,
) -> None: ) -> None:
"""Test attributes for app with playing media.""" """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) state = hass.states.get(MAIN_ENTITY_ID)
assert state
assert state.state == STATE_PLAYING assert state.state == STATE_PLAYING
assert state.attributes.get(ATTR_MEDIA_CONTENT_TYPE) == MEDIA_TYPE_APP 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" 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( async def test_attributes_app_media_paused(
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker hass: HomeAssistant,
init_integration: MockConfigEntry,
mock_roku: MagicMock,
) -> None: ) -> None:
"""Test attributes for app with paused media.""" """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) state = hass.states.get(MAIN_ENTITY_ID)
assert state
assert state.state == STATE_PAUSED assert state.state == STATE_PAUSED
assert state.attributes.get(ATTR_MEDIA_CONTENT_TYPE) == MEDIA_TYPE_APP 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" 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( async def test_attributes_screensaver(
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker hass: HomeAssistant,
init_integration: MockConfigEntry,
mock_roku: MagicMock,
) -> None: ) -> None:
"""Test attributes for app with screensaver.""" """Test attributes for app with screensaver."""
await setup_integration(hass, aioclient_mock, app="screensaver")
state = hass.states.get(MAIN_ENTITY_ID) state = hass.states.get(MAIN_ENTITY_ID)
assert state
assert state.state == STATE_IDLE assert state.state == STATE_IDLE
assert state.attributes.get(ATTR_MEDIA_CONTENT_TYPE) is None 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" assert state.attributes.get(ATTR_INPUT_SOURCE) == "Roku"
@pytest.mark.parametrize("mock_roku", ["roku/rokutv-7820x.json"], indirect=True)
async def test_tv_attributes( async def test_tv_attributes(
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker hass: HomeAssistant, init_integration: MockConfigEntry
) -> None: ) -> None:
"""Test attributes for Roku TV.""" """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) state = hass.states.get(TV_ENTITY_ID)
assert state
assert state.state == STATE_ON assert state.state == STATE_ON
assert state.attributes.get(ATTR_APP_ID) == "tvinput.dtv" 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" 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( async def test_services(
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker hass: HomeAssistant,
init_integration: MockConfigEntry,
mock_roku: MagicMock,
) -> None: ) -> None:
"""Test the different media player services.""" """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: assert mock_roku.remote.call_count == 1
await hass.services.async_call( mock_roku.remote.assert_called_with("poweroff")
MP_DOMAIN, SERVICE_TURN_OFF, {ATTR_ENTITY_ID: MAIN_ENTITY_ID}, blocking=True
)
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: assert mock_roku.remote.call_count == 2
await hass.services.async_call( mock_roku.remote.assert_called_with("poweron")
MP_DOMAIN, SERVICE_TURN_ON, {ATTR_ENTITY_ID: MAIN_ENTITY_ID}, blocking=True
)
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: assert mock_roku.remote.call_count == 3
await hass.services.async_call( mock_roku.remote.assert_called_with("play")
MP_DOMAIN,
SERVICE_MEDIA_PAUSE,
{ATTR_ENTITY_ID: MAIN_ENTITY_ID},
blocking=True,
)
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: assert mock_roku.remote.call_count == 4
await hass.services.async_call( mock_roku.remote.assert_called_with("play")
MP_DOMAIN,
SERVICE_MEDIA_PLAY,
{ATTR_ENTITY_ID: MAIN_ENTITY_ID},
blocking=True,
)
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: assert mock_roku.remote.call_count == 5
await hass.services.async_call( mock_roku.remote.assert_called_with("play")
MP_DOMAIN,
SERVICE_MEDIA_PLAY_PAUSE,
{ATTR_ENTITY_ID: MAIN_ENTITY_ID},
blocking=True,
)
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: assert mock_roku.remote.call_count == 6
await hass.services.async_call( mock_roku.remote.assert_called_with("forward")
MP_DOMAIN,
SERVICE_MEDIA_NEXT_TRACK,
{ATTR_ENTITY_ID: MAIN_ENTITY_ID},
blocking=True,
)
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: assert mock_roku.remote.call_count == 7
await hass.services.async_call( mock_roku.remote.assert_called_with("reverse")
MP_DOMAIN,
SERVICE_MEDIA_PREVIOUS_TRACK,
{ATTR_ENTITY_ID: MAIN_ENTITY_ID},
blocking=True,
)
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: assert mock_roku.remote.call_count == 8
await hass.services.async_call( mock_roku.remote.assert_called_with("home")
MP_DOMAIN,
SERVICE_PLAY_MEDIA, await hass.services.async_call(
{ MP_DOMAIN,
ATTR_ENTITY_ID: MAIN_ENTITY_ID, SERVICE_PLAY_MEDIA,
ATTR_MEDIA_CONTENT_TYPE: MEDIA_TYPE_APP, {
ATTR_MEDIA_CONTENT_ID: "11", 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(
await hass.services.async_call( MP_DOMAIN,
MP_DOMAIN, SERVICE_PLAY_MEDIA,
SERVICE_PLAY_MEDIA, {
{ ATTR_ENTITY_ID: MAIN_ENTITY_ID,
ATTR_ENTITY_ID: MAIN_ENTITY_ID, ATTR_MEDIA_CONTENT_TYPE: MEDIA_TYPE_URL,
ATTR_MEDIA_CONTENT_TYPE: MEDIA_TYPE_APP, ATTR_MEDIA_CONTENT_ID: "https://awesome.tld/media.mp4",
ATTR_MEDIA_CONTENT_ID: "291097", ATTR_MEDIA_EXTRA: {
ATTR_MEDIA_EXTRA: { ATTR_NAME: "Sent from HA",
ATTR_MEDIA_TYPE: "movie", ATTR_FORMAT: "mp4",
ATTR_CONTENT_ID: "8e06a8b7-d667-4e31-939d-f40a6dd78a88",
},
}, },
blocking=True, },
) blocking=True,
)
launch_mock.assert_called_once_with( assert mock_roku.play_video.call_count == 1
"291097", mock_roku.play_video.assert_called_with(
{ "https://awesome.tld/media.mp4",
"contentID": "8e06a8b7-d667-4e31-939d-f40a6dd78a88", {
"MediaType": "movie", "videoName": "Sent from HA",
}, "videoFormat": "mp4",
) },
)
with patch("homeassistant.components.roku.coordinator.Roku.play_video") as pv_mock: await hass.services.async_call(
await hass.services.async_call( MP_DOMAIN,
MP_DOMAIN, SERVICE_PLAY_MEDIA,
SERVICE_PLAY_MEDIA, {
{ ATTR_ENTITY_ID: MAIN_ENTITY_ID,
ATTR_ENTITY_ID: MAIN_ENTITY_ID, ATTR_MEDIA_CONTENT_TYPE: FORMAT_CONTENT_TYPE[HLS_PROVIDER],
ATTR_MEDIA_CONTENT_TYPE: MEDIA_TYPE_URL, ATTR_MEDIA_CONTENT_ID: "https://awesome.tld/api/hls/api_token/master_playlist.m3u8",
ATTR_MEDIA_CONTENT_ID: "https://awesome.tld/media.mp4", },
ATTR_MEDIA_EXTRA: { blocking=True,
ATTR_NAME: "Sent from HA", )
ATTR_FORMAT: "mp4",
},
},
blocking=True,
)
pv_mock.assert_called_once_with( assert mock_roku.play_video.call_count == 2
"https://awesome.tld/media.mp4", mock_roku.play_video.assert_called_with(
{ "https://awesome.tld/api/hls/api_token/master_playlist.m3u8",
"videoName": "Sent from HA", {
"videoFormat": "mp4", "MediaType": "hls",
}, },
) )
with patch("homeassistant.components.roku.coordinator.Roku.play_video") as pv_mock: await hass.services.async_call(
await hass.services.async_call( MP_DOMAIN,
MP_DOMAIN, SERVICE_SELECT_SOURCE,
SERVICE_PLAY_MEDIA, {ATTR_ENTITY_ID: MAIN_ENTITY_ID, ATTR_INPUT_SOURCE: "Netflix"},
{ blocking=True,
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( assert mock_roku.launch.call_count == 3
"https://awesome.tld/api/hls/api_token/master_playlist.m3u8", mock_roku.launch.assert_called_with("12")
{
"MediaType": "hls",
},
)
with patch("homeassistant.components.roku.coordinator.Roku.remote") as remote_mock: await hass.services.async_call(
await hass.services.async_call( MP_DOMAIN,
MP_DOMAIN, SERVICE_SELECT_SOURCE,
SERVICE_SELECT_SOURCE, {ATTR_ENTITY_ID: MAIN_ENTITY_ID, ATTR_INPUT_SOURCE: 12},
{ATTR_ENTITY_ID: MAIN_ENTITY_ID, ATTR_INPUT_SOURCE: "Home"}, blocking=True,
blocking=True, )
)
remote_mock.assert_called_once_with("home") assert mock_roku.launch.call_count == 4
mock_roku.launch.assert_called_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: "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")
@pytest.mark.parametrize("mock_roku", ["roku/rokutv-7820x.json"], indirect=True)
async def test_tv_services( async def test_tv_services(
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker hass: HomeAssistant,
init_integration: MockConfigEntry,
mock_roku: MagicMock,
) -> None: ) -> None:
"""Test the media player services related to Roku TV.""" """Test the media player services related to Roku TV."""
await setup_integration( await hass.services.async_call(
hass, MP_DOMAIN, SERVICE_VOLUME_UP, {ATTR_ENTITY_ID: TV_ENTITY_ID}, blocking=True
aioclient_mock,
device="rokutv",
app="tvinput-dtv",
host=TV_HOST,
unique_id=TV_SERIAL,
) )
with patch("homeassistant.components.roku.coordinator.Roku.remote") as remote_mock: assert mock_roku.remote.call_count == 1
await hass.services.async_call( mock_roku.remote.assert_called_with("volume_up")
MP_DOMAIN, SERVICE_VOLUME_UP, {ATTR_ENTITY_ID: TV_ENTITY_ID}, blocking=True
)
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: assert mock_roku.remote.call_count == 2
await hass.services.async_call( mock_roku.remote.assert_called_with("volume_down")
MP_DOMAIN,
SERVICE_VOLUME_DOWN,
{ATTR_ENTITY_ID: TV_ENTITY_ID},
blocking=True,
)
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: assert mock_roku.remote.call_count == 3
await hass.services.async_call( mock_roku.remote.assert_called_with("volume_mute")
MP_DOMAIN,
SERVICE_VOLUME_MUTE,
{ATTR_ENTITY_ID: TV_ENTITY_ID, ATTR_MEDIA_VOLUME_MUTED: True},
blocking=True,
)
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: assert mock_roku.tune.call_count == 1
await hass.services.async_call( mock_roku.tune.assert_called_with("55")
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")
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.""" """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) client = await hass_ws_client(hass)
await client.send_json( await client.send_json(
@ -741,7 +695,13 @@ async def test_media_browse(hass, aioclient_mock, hass_ws_client):
assert not msg["success"] 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.""" """Test browsing media with internal url."""
await async_process_ha_core_config( await async_process_ha_core_config(
hass, 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" 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) client = await hass_ws_client(hass)
with patch( with patch(
@ -804,16 +755,15 @@ async def test_media_browse_internal(hass, aioclient_mock, hass_ws_client):
async def test_integration_services( async def test_integration_services(
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker hass: HomeAssistant,
init_integration: MockConfigEntry,
mock_roku: MagicMock,
) -> None: ) -> None:
"""Test integration services.""" """Test integration services."""
await setup_integration(hass, aioclient_mock) await hass.services.async_call(
DOMAIN,
with patch("homeassistant.components.roku.coordinator.Roku.search") as search_mock: SERVICE_SEARCH,
await hass.services.async_call( {ATTR_ENTITY_ID: MAIN_ENTITY_ID, ATTR_KEYWORD: "Space Jam"},
DOMAIN, blocking=True,
SERVICE_SEARCH, )
{ATTR_ENTITY_ID: MAIN_ENTITY_ID, ATTR_KEYWORD: "Space Jam"}, mock_roku.search.assert_called_once_with("Space Jam")
blocking=True,
)
search_mock.assert_called_once_with("Space Jam")

View File

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

View File

@ -1,4 +1,8 @@
"""Tests for the sensors provided by the Roku integration.""" """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.components.roku.const import DOMAIN
from homeassistant.const import ( from homeassistant.const import (
ATTR_DEVICE_CLASS, 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 import device_registry as dr, entity_registry as er
from homeassistant.helpers.entity import EntityCategory from homeassistant.helpers.entity import EntityCategory
from tests.components.roku import UPNP_SERIAL, setup_integration from tests.common import MockConfigEntry
from tests.test_util.aiohttp import AiohttpClientMocker from tests.components.roku import UPNP_SERIAL
async def test_roku_sensors( async def test_roku_sensors(
hass: HomeAssistant, hass: HomeAssistant,
aioclient_mock: AiohttpClientMocker, init_integration: MockConfigEntry,
) -> None: ) -> None:
"""Test the Roku sensors.""" """Test the Roku sensors."""
await setup_integration(hass, aioclient_mock)
entity_registry = er.async_get(hass) entity_registry = er.async_get(hass)
device_registry = dr.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.name == "My Roku 3"
assert device_entry.entry_type is None assert device_entry.entry_type is None
assert device_entry.sw_version == "7.5.0" 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( async def test_rokutv_sensors(
hass: HomeAssistant, hass: HomeAssistant,
aioclient_mock: AiohttpClientMocker, init_integration: MockConfigEntry,
mock_roku: MagicMock,
) -> None: ) -> None:
"""Test the Roku TV sensors.""" """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) entity_registry = er.async_get(hass)
device_registry = dr.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.name == '58" Onn Roku TV'
assert device_entry.entry_type is None assert device_entry.entry_type is None
assert device_entry.sw_version == "9.2.0" assert device_entry.sw_version == "9.2.0"
assert device_entry.hw_version == "7820X"
assert device_entry.suggested_area == "Living room"