Add Bang & Olufsen media_player testing (#120580)
This commit is contained in:
parent
2a31774f91
commit
45843a3112
3 changed files with 1354 additions and 3 deletions
|
@ -3,10 +3,26 @@
|
||||||
from collections.abc import Generator
|
from collections.abc import Generator
|
||||||
from unittest.mock import AsyncMock, Mock, patch
|
from unittest.mock import AsyncMock, Mock, patch
|
||||||
|
|
||||||
from mozart_api.models import BeolinkPeer
|
from mozart_api.models import (
|
||||||
|
Action,
|
||||||
|
BeolinkPeer,
|
||||||
|
ContentItem,
|
||||||
|
PlaybackContentMetadata,
|
||||||
|
PlaybackProgress,
|
||||||
|
PlaybackState,
|
||||||
|
ProductState,
|
||||||
|
RemoteMenuItem,
|
||||||
|
RenderingState,
|
||||||
|
SoftwareUpdateStatus,
|
||||||
|
Source,
|
||||||
|
SourceArray,
|
||||||
|
SourceTypeEnum,
|
||||||
|
VolumeState,
|
||||||
|
)
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from homeassistant.components.bang_olufsen.const import DOMAIN
|
from homeassistant.components.bang_olufsen.const import DOMAIN
|
||||||
|
from homeassistant.core import HomeAssistant
|
||||||
|
|
||||||
from .const import (
|
from .const import (
|
||||||
TEST_DATA_CREATE_ENTRY,
|
TEST_DATA_CREATE_ENTRY,
|
||||||
|
@ -30,10 +46,17 @@ def mock_config_entry():
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
async def mock_media_player(hass: HomeAssistant, mock_config_entry, mock_mozart_client):
|
||||||
|
"""Mock media_player entity."""
|
||||||
|
|
||||||
|
mock_config_entry.add_to_hass(hass)
|
||||||
|
await hass.config_entries.async_setup(mock_config_entry.entry_id)
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def mock_mozart_client() -> Generator[AsyncMock]:
|
def mock_mozart_client() -> Generator[AsyncMock]:
|
||||||
"""Mock MozartClient."""
|
"""Mock MozartClient."""
|
||||||
|
|
||||||
with (
|
with (
|
||||||
patch(
|
patch(
|
||||||
"homeassistant.components.bang_olufsen.MozartClient", autospec=True
|
"homeassistant.components.bang_olufsen.MozartClient", autospec=True
|
||||||
|
@ -50,6 +73,170 @@ def mock_mozart_client() -> Generator[AsyncMock]:
|
||||||
client.get_beolink_self.return_value = BeolinkPeer(
|
client.get_beolink_self.return_value = BeolinkPeer(
|
||||||
friendly_name=TEST_FRIENDLY_NAME, jid=TEST_JID_1
|
friendly_name=TEST_FRIENDLY_NAME, jid=TEST_JID_1
|
||||||
)
|
)
|
||||||
|
client.get_softwareupdate_status = AsyncMock()
|
||||||
|
client.get_softwareupdate_status.return_value = SoftwareUpdateStatus(
|
||||||
|
software_version="1.0.0", state=""
|
||||||
|
)
|
||||||
|
client.get_product_state = AsyncMock()
|
||||||
|
client.get_product_state.return_value = ProductState(
|
||||||
|
volume=VolumeState(),
|
||||||
|
playback=PlaybackState(
|
||||||
|
metadata=PlaybackContentMetadata(),
|
||||||
|
progress=PlaybackProgress(),
|
||||||
|
source=Source(),
|
||||||
|
state=RenderingState(value="started"),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
client.get_available_sources = AsyncMock()
|
||||||
|
client.get_available_sources.return_value = SourceArray(
|
||||||
|
items=[
|
||||||
|
# Is in the HIDDEN_SOURCE_IDS constant, so should not be user selectable
|
||||||
|
Source(
|
||||||
|
name="AirPlay",
|
||||||
|
id="airPlay",
|
||||||
|
is_enabled=True,
|
||||||
|
is_multiroom_available=False,
|
||||||
|
),
|
||||||
|
# The only available source
|
||||||
|
Source(
|
||||||
|
name="Tidal",
|
||||||
|
id="tidal",
|
||||||
|
is_enabled=True,
|
||||||
|
is_multiroom_available=True,
|
||||||
|
),
|
||||||
|
# Is disabled, so should not be user selectable
|
||||||
|
Source(
|
||||||
|
name="Powerlink",
|
||||||
|
id="pl",
|
||||||
|
is_enabled=False,
|
||||||
|
),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
client.get_remote_menu = AsyncMock()
|
||||||
|
client.get_remote_menu.return_value = {
|
||||||
|
# Music category, so shouldn't be included in video sources
|
||||||
|
"b355888b-2cde-5f94-8592-d47b71d52a27": RemoteMenuItem(
|
||||||
|
action_list=[
|
||||||
|
Action(
|
||||||
|
button_name=None,
|
||||||
|
content_id="netRadio://6629967157728971",
|
||||||
|
deezer_user_id=None,
|
||||||
|
gain_db=None,
|
||||||
|
listening_mode_id=None,
|
||||||
|
preset_key=None,
|
||||||
|
queue_item=None,
|
||||||
|
queue_settings=None,
|
||||||
|
radio_station_id=None,
|
||||||
|
source=None,
|
||||||
|
speaker_group_id=None,
|
||||||
|
stand_position=None,
|
||||||
|
stop_duration=None,
|
||||||
|
tone_name=None,
|
||||||
|
type="triggerContent",
|
||||||
|
volume_level=None,
|
||||||
|
)
|
||||||
|
],
|
||||||
|
scene_list=None,
|
||||||
|
disabled=None,
|
||||||
|
dynamic_list=None,
|
||||||
|
first_child_menu_item_id=None,
|
||||||
|
label="Yle Radio Suomi Helsinki",
|
||||||
|
next_sibling_menu_item_id="0b4552f8-7ac6-5046-9d44-5410a815b8d6",
|
||||||
|
parent_menu_item_id="eee0c2d0-2b3a-4899-a708-658475c38926",
|
||||||
|
available=None,
|
||||||
|
content=ContentItem(
|
||||||
|
categories=["music"],
|
||||||
|
content_uri="netRadio://6629967157728971",
|
||||||
|
label="Yle Radio Suomi Helsinki",
|
||||||
|
source=SourceTypeEnum(value="netRadio"),
|
||||||
|
),
|
||||||
|
fixed=True,
|
||||||
|
id="b355888b-2cde-5f94-8592-d47b71d52a27",
|
||||||
|
),
|
||||||
|
# Has "hdmi" as category, so should be included in video sources
|
||||||
|
"b6591565-80f4-4356-bcd9-c92ca247f0a9": RemoteMenuItem(
|
||||||
|
action_list=[
|
||||||
|
Action(
|
||||||
|
button_name=None,
|
||||||
|
content_id="tv://hdmi_1",
|
||||||
|
deezer_user_id=None,
|
||||||
|
gain_db=None,
|
||||||
|
listening_mode_id=None,
|
||||||
|
preset_key=None,
|
||||||
|
queue_item=None,
|
||||||
|
queue_settings=None,
|
||||||
|
radio_station_id=None,
|
||||||
|
source=None,
|
||||||
|
speaker_group_id=None,
|
||||||
|
stand_position=None,
|
||||||
|
stop_duration=None,
|
||||||
|
tone_name=None,
|
||||||
|
type="triggerContent",
|
||||||
|
volume_level=None,
|
||||||
|
)
|
||||||
|
],
|
||||||
|
scene_list=None,
|
||||||
|
disabled=False,
|
||||||
|
dynamic_list="none",
|
||||||
|
first_child_menu_item_id=None,
|
||||||
|
label="HDMI A",
|
||||||
|
next_sibling_menu_item_id="0ba98974-7b1f-40dc-bc48-fbacbb0f1793",
|
||||||
|
parent_menu_item_id="b66c835b-6b98-4400-8f84-6348043792c7",
|
||||||
|
available=True,
|
||||||
|
content=ContentItem(
|
||||||
|
categories=["hdmi"],
|
||||||
|
content_uri="tv://hdmi_1",
|
||||||
|
label="HDMI A",
|
||||||
|
source=SourceTypeEnum(value="tv"),
|
||||||
|
),
|
||||||
|
fixed=False,
|
||||||
|
id="b6591565-80f4-4356-bcd9-c92ca247f0a9",
|
||||||
|
),
|
||||||
|
# The parent remote menu item. Has the TV label and should therefore not be included in video sources
|
||||||
|
"b66c835b-6b98-4400-8f84-6348043792c7": RemoteMenuItem(
|
||||||
|
action_list=[],
|
||||||
|
scene_list=None,
|
||||||
|
disabled=False,
|
||||||
|
dynamic_list="none",
|
||||||
|
first_child_menu_item_id="b6591565-80f4-4356-bcd9-c92ca247f0a9",
|
||||||
|
label="TV",
|
||||||
|
next_sibling_menu_item_id="0c4547fe-d3cc-4348-a425-473595b8c9fb",
|
||||||
|
parent_menu_item_id=None,
|
||||||
|
available=True,
|
||||||
|
content=None,
|
||||||
|
fixed=True,
|
||||||
|
id="b66c835b-6b98-4400-8f84-6348043792c7",
|
||||||
|
),
|
||||||
|
# Has an empty content, so should not be included
|
||||||
|
"64c9da45-3682-44a4-8030-09ed3ef44160": RemoteMenuItem(
|
||||||
|
action_list=[],
|
||||||
|
scene_list=None,
|
||||||
|
disabled=False,
|
||||||
|
dynamic_list="none",
|
||||||
|
first_child_menu_item_id=None,
|
||||||
|
label="ListeningPosition",
|
||||||
|
next_sibling_menu_item_id=None,
|
||||||
|
parent_menu_item_id="0c4547fe-d3cc-4348-a425-473595b8c9fb",
|
||||||
|
available=True,
|
||||||
|
content=None,
|
||||||
|
fixed=True,
|
||||||
|
id="64c9da45-3682-44a4-8030-09ed3ef44160",
|
||||||
|
),
|
||||||
|
}
|
||||||
|
client.post_standby = AsyncMock()
|
||||||
|
client.set_current_volume_level = AsyncMock()
|
||||||
|
client.set_volume_mute = AsyncMock()
|
||||||
|
client.post_playback_command = AsyncMock()
|
||||||
|
client.seek_to_position = AsyncMock()
|
||||||
|
client.post_clear_queue = AsyncMock()
|
||||||
|
client.post_overlay_play = AsyncMock()
|
||||||
|
client.post_uri_source = AsyncMock()
|
||||||
|
client.run_provided_scene = AsyncMock()
|
||||||
|
client.activate_preset = AsyncMock()
|
||||||
|
client.start_deezer_flow = AsyncMock()
|
||||||
|
client.add_to_queue = AsyncMock()
|
||||||
|
client.post_remote_trigger = AsyncMock()
|
||||||
|
client.set_active_source = AsyncMock()
|
||||||
|
|
||||||
# Non-REST API client methods
|
# Non-REST API client methods
|
||||||
client.check_device_connection = AsyncMock()
|
client.check_device_connection = AsyncMock()
|
||||||
|
|
|
@ -1,6 +1,25 @@
|
||||||
"""Constants used for testing the bang_olufsen integration."""
|
"""Constants used for testing the bang_olufsen integration."""
|
||||||
|
|
||||||
from ipaddress import IPv4Address, IPv6Address
|
from ipaddress import IPv4Address, IPv6Address
|
||||||
|
from unittest.mock import Mock
|
||||||
|
|
||||||
|
from mozart_api.exceptions import ApiException
|
||||||
|
from mozart_api.models import (
|
||||||
|
Action,
|
||||||
|
OverlayPlayRequest,
|
||||||
|
OverlayPlayRequestTextToSpeechTextToSpeech,
|
||||||
|
PlaybackContentMetadata,
|
||||||
|
PlaybackError,
|
||||||
|
PlaybackProgress,
|
||||||
|
PlayQueueItem,
|
||||||
|
PlayQueueItemType,
|
||||||
|
RenderingState,
|
||||||
|
SceneProperties,
|
||||||
|
UserFlow,
|
||||||
|
VolumeLevel,
|
||||||
|
VolumeMute,
|
||||||
|
VolumeState,
|
||||||
|
)
|
||||||
|
|
||||||
from homeassistant.components.bang_olufsen.const import (
|
from homeassistant.components.bang_olufsen.const import (
|
||||||
ATTR_FRIENDLY_NAME,
|
ATTR_FRIENDLY_NAME,
|
||||||
|
@ -8,6 +27,7 @@ from homeassistant.components.bang_olufsen.const import (
|
||||||
ATTR_SERIAL_NUMBER,
|
ATTR_SERIAL_NUMBER,
|
||||||
ATTR_TYPE_NUMBER,
|
ATTR_TYPE_NUMBER,
|
||||||
CONF_BEOLINK_JID,
|
CONF_BEOLINK_JID,
|
||||||
|
BangOlufsenSource,
|
||||||
)
|
)
|
||||||
from homeassistant.components.zeroconf import ZeroconfServiceInfo
|
from homeassistant.components.zeroconf import ZeroconfServiceInfo
|
||||||
from homeassistant.const import CONF_HOST, CONF_MODEL, CONF_NAME
|
from homeassistant.const import CONF_HOST, CONF_MODEL, CONF_NAME
|
||||||
|
@ -24,7 +44,7 @@ TEST_FRIENDLY_NAME = "Living room Balance"
|
||||||
TEST_TYPE_NUMBER = "1111"
|
TEST_TYPE_NUMBER = "1111"
|
||||||
TEST_ITEM_NUMBER = "1111111"
|
TEST_ITEM_NUMBER = "1111111"
|
||||||
TEST_JID_1 = f"{TEST_TYPE_NUMBER}.{TEST_ITEM_NUMBER}.{TEST_SERIAL_NUMBER}@products.bang-olufsen.com"
|
TEST_JID_1 = f"{TEST_TYPE_NUMBER}.{TEST_ITEM_NUMBER}.{TEST_SERIAL_NUMBER}@products.bang-olufsen.com"
|
||||||
|
TEST_MEDIA_PLAYER_ENTITY_ID = "media_player.beosound_balance_11111111"
|
||||||
|
|
||||||
TEST_HOSTNAME_ZEROCONF = TEST_NAME.replace(" ", "-") + ".local."
|
TEST_HOSTNAME_ZEROCONF = TEST_NAME.replace(" ", "-") + ".local."
|
||||||
TEST_TYPE_ZEROCONF = "_bangolufsen._tcp.local."
|
TEST_TYPE_ZEROCONF = "_bangolufsen._tcp.local."
|
||||||
|
@ -80,3 +100,80 @@ TEST_DATA_ZEROCONF_IPV6 = ZeroconfServiceInfo(
|
||||||
ATTR_ITEM_NUMBER: TEST_ITEM_NUMBER,
|
ATTR_ITEM_NUMBER: TEST_ITEM_NUMBER,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
TEST_AUDIO_SOURCES = [BangOlufsenSource.TIDAL.name]
|
||||||
|
TEST_VIDEO_SOURCES = ["HDMI A"]
|
||||||
|
TEST_SOURCES = TEST_AUDIO_SOURCES + TEST_VIDEO_SOURCES
|
||||||
|
TEST_FALLBACK_SOURCES = [
|
||||||
|
"Audio Streamer",
|
||||||
|
"Spotify Connect",
|
||||||
|
"Line-In",
|
||||||
|
"Optical",
|
||||||
|
"B&O Radio",
|
||||||
|
"Deezer",
|
||||||
|
"Tidal Connect",
|
||||||
|
]
|
||||||
|
TEST_PLAYBACK_METADATA = PlaybackContentMetadata(
|
||||||
|
album_name="Test album",
|
||||||
|
artist_name="Test artist",
|
||||||
|
organization="Test organization",
|
||||||
|
title="Test title",
|
||||||
|
total_duration_seconds=123,
|
||||||
|
track=1,
|
||||||
|
)
|
||||||
|
TEST_PLAYBACK_ERROR = PlaybackError(error="Test error")
|
||||||
|
TEST_PLAYBACK_PROGRESS = PlaybackProgress(progress=123)
|
||||||
|
TEST_PLAYBACK_STATE_PAUSED = RenderingState(value="paused")
|
||||||
|
TEST_PLAYBACK_STATE_PLAYING = RenderingState(value="started")
|
||||||
|
TEST_VOLUME = VolumeState(level=VolumeLevel(level=40))
|
||||||
|
TEST_VOLUME_HOME_ASSISTANT_FORMAT = 0.4
|
||||||
|
TEST_PLAYBACK_STATE_TURN_OFF = RenderingState(value="stopped")
|
||||||
|
TEST_VOLUME_MUTED = VolumeState(
|
||||||
|
muted=VolumeMute(muted=True), level=VolumeLevel(level=40)
|
||||||
|
)
|
||||||
|
TEST_VOLUME_MUTED_HOME_ASSISTANT_FORMAT = True
|
||||||
|
TEST_SEEK_POSITION_HOME_ASSISTANT_FORMAT = 10.0
|
||||||
|
TEST_SEEK_POSITION = 10000
|
||||||
|
TEST_OVERLAY_INVALID_OFFSET_VOLUME_TTS = OverlayPlayRequest(
|
||||||
|
text_to_speech=OverlayPlayRequestTextToSpeechTextToSpeech(
|
||||||
|
lang="da-dk", text="Dette er en test"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
TEST_OVERLAY_OFFSET_VOLUME_TTS = OverlayPlayRequest(
|
||||||
|
text_to_speech=OverlayPlayRequestTextToSpeechTextToSpeech(
|
||||||
|
lang="en-us", text="This is a test"
|
||||||
|
),
|
||||||
|
volume_absolute=60,
|
||||||
|
)
|
||||||
|
TEST_RADIO_STATION = SceneProperties(
|
||||||
|
action_list=[
|
||||||
|
Action(
|
||||||
|
type="radio",
|
||||||
|
radio_station_id="1234567890123456",
|
||||||
|
)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
TEST_DEEZER_FLOW = UserFlow(user_id="123")
|
||||||
|
TEST_DEEZER_PLAYLIST = PlayQueueItem(
|
||||||
|
provider=PlayQueueItemType(value="deezer"),
|
||||||
|
start_now_from_position=123,
|
||||||
|
type="playlist",
|
||||||
|
uri="playlist:1234567890",
|
||||||
|
)
|
||||||
|
TEST_DEEZER_TRACK = PlayQueueItem(
|
||||||
|
provider=PlayQueueItemType(value="deezer"),
|
||||||
|
start_now_from_position=0,
|
||||||
|
type="track",
|
||||||
|
uri="1234567890",
|
||||||
|
)
|
||||||
|
|
||||||
|
# codespell can't see the escaped ', so it thinks the word is misspelled
|
||||||
|
TEST_DEEZER_INVALID_FLOW = ApiException(
|
||||||
|
status=400,
|
||||||
|
reason="Bad Request",
|
||||||
|
http_resp=Mock(
|
||||||
|
status=400,
|
||||||
|
reason="Bad Request",
|
||||||
|
data='{"message": "Couldn\'t start user flow for me"}', # codespell:ignore
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
1067
tests/components/bang_olufsen/test_media_player.py
Normal file
1067
tests/components/bang_olufsen/test_media_player.py
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Add table
Reference in a new issue