diff --git a/homeassistant/components/blebox/helpers.py b/homeassistant/components/blebox/helpers.py index 98b3e7777790d..c076737f2a15e 100644 --- a/homeassistant/components/blebox/helpers.py +++ b/homeassistant/components/blebox/helpers.py @@ -14,7 +14,9 @@ def get_maybe_authenticated_session( ) -> aiohttp.ClientSession: """Return proper session object.""" if username and password: - auth = aiohttp.BasicAuth(login=username, password=password) - return async_create_clientsession(hass, auth=auth) + return async_create_clientsession( + hass, + headers={"Authorization": aiohttp.encode_basic_auth(username, password)}, + ) return async_get_clientsession(hass) diff --git a/homeassistant/components/data_grand_lyon/coordinator.py b/homeassistant/components/data_grand_lyon/coordinator.py index 66562a9c23e9d..46514a916a509 100644 --- a/homeassistant/components/data_grand_lyon/coordinator.py +++ b/homeassistant/components/data_grand_lyon/coordinator.py @@ -106,7 +106,8 @@ async def _async_update_data(self) -> dict[str, list[TclPassage]]: if sorted_passages: stops[subentry.subentry_id] = sorted_passages else: - LOGGER.warning( + # Expected outside service hours, e.g. at night + LOGGER.debug( "No TCL passages found for subentry %s", subentry.subentry_id, ) diff --git a/homeassistant/components/go2rtc/__init__.py b/homeassistant/components/go2rtc/__init__.py index c15fab8f2de2a..9a8604e449d29 100644 --- a/homeassistant/components/go2rtc/__init__.py +++ b/homeassistant/components/go2rtc/__init__.py @@ -7,7 +7,7 @@ from tempfile import mkdtemp from typing import override -from aiohttp import BasicAuth, ClientSession, UnixConnector +from aiohttp import ClientSession, UnixConnector, encode_basic_auth from aiohttp.client_exceptions import ClientConnectionError, ServerConnectionError from awesomeversion import AwesomeVersion from go2rtc_client import Go2RtcRestClient @@ -153,14 +153,13 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: password = token_hex() _LOGGER.debug("Generated random credentials for go2rtc server") - auth = BasicAuth(username, password) # HA will manage the binary temp_dir = mkdtemp(prefix="go2rtc-") # Manually created session (not using the helper) needs to be closed manually # See on_stop listener below session = ClientSession( connector=UnixConnector(path=get_go2rtc_unix_socket_path(temp_dir)), - auth=auth, + headers={"Authorization": encode_basic_auth(username, password)}, ) server = Server( hass, @@ -186,9 +185,9 @@ async def on_stop(event: Event) -> None: url = HA_MANAGED_URL elif username and password: - # Create session with BasicAuth if credentials are provided - auth = BasicAuth(username, password) - session = async_create_clientsession(hass, auth=auth) + session = async_create_clientsession( + hass, headers={"Authorization": encode_basic_auth(username, password)} + ) else: session = async_get_clientsession(hass) diff --git a/homeassistant/components/lyric/api.py b/homeassistant/components/lyric/api.py index 38c6ed59a7789..6469b8e730709 100644 --- a/homeassistant/components/lyric/api.py +++ b/homeassistant/components/lyric/api.py @@ -2,7 +2,7 @@ from typing import cast, override -from aiohttp import BasicAuth, ClientSession +from aiohttp import ClientSession, encode_basic_auth from aiolyric.client import LyricClient from homeassistant.components.application_credentials import AuthImplementation @@ -63,7 +63,7 @@ async def _token_request(self, data: dict) -> dict: data["client_secret"] = self.client_secret headers = { - "Authorization": BasicAuth(self.client_id, self.client_secret).encode(), + "Authorization": encode_basic_auth(self.client_id, self.client_secret), "Content-Type": "application/x-www-form-urlencoded", } diff --git a/homeassistant/components/midea/manifest.json b/homeassistant/components/midea/manifest.json index 400c17ae3efc8..0e1ed59a46ae7 100644 --- a/homeassistant/components/midea/manifest.json +++ b/homeassistant/components/midea/manifest.json @@ -8,5 +8,5 @@ "iot_class": "local_polling", "loggers": ["midealocal"], "quality_scale": "bronze", - "requirements": ["midea-local==9.0.0"] + "requirements": ["midea-local==10.0.0"] } diff --git a/homeassistant/components/mjpeg/camera.py b/homeassistant/components/mjpeg/camera.py index 10dc8e8e3e3c5..cd0c13f549a28 100644 --- a/homeassistant/components/mjpeg/camera.py +++ b/homeassistant/components/mjpeg/camera.py @@ -107,13 +107,17 @@ def __init__( self._mjpeg_url = mjpeg_url self._still_image_url = still_image_url - self._auth = None + self._auth_headers: dict[str, str] | None = None if ( self._username and self._password and self._authentication == HTTP_BASIC_AUTHENTICATION ): - self._auth = aiohttp.BasicAuth(self._username, password=self._password) + self._auth_headers = { + "Authorization": aiohttp.encode_basic_auth( + self._username, self._password + ) + } self._verify_ssl = verify_ssl if unique_id is not None: @@ -145,7 +149,9 @@ async def async_camera_image( websession = async_get_clientsession(self.hass, verify_ssl=self._verify_ssl) try: async with asyncio.timeout(TIMEOUT): - response = await websession.get(self._still_image_url, auth=self._auth) + response = await websession.get( + self._still_image_url, headers=self._auth_headers + ) return await response.read() @@ -223,6 +229,6 @@ async def handle_async_mjpeg_stream( # connect to stream websession = async_get_clientsession(self.hass, verify_ssl=self._verify_ssl) - stream_coro = websession.get(self._mjpeg_url, auth=self._auth) + stream_coro = websession.get(self._mjpeg_url, headers=self._auth_headers) return await async_aiohttp_proxy_web(self.hass, request, stream_coro) diff --git a/homeassistant/components/motioneye/camera.py b/homeassistant/components/motioneye/camera.py index 0675455102444..34b543bce7cac 100644 --- a/homeassistant/components/motioneye/camera.py +++ b/homeassistant/components/motioneye/camera.py @@ -219,7 +219,11 @@ def _set_mjpeg_camera_state_for_camera(self, camera: dict[str, Any]) -> None: self._authentication == HTTP_BASIC_AUTHENTICATION and self._username is not None ): - self._auth = aiohttp.BasicAuth(self._username, password=self._password) + self._auth_headers = { + "Authorization": aiohttp.encode_basic_auth( + self._username, self._password + ) + } def _is_acceptable_streaming_camera(self) -> bool: """Determine if a camera is streaming/usable.""" diff --git a/homeassistant/components/ovhcloud_ai_endpoints/config_flow.py b/homeassistant/components/ovhcloud_ai_endpoints/config_flow.py index 29a5424c223de..d3970fcfc7362 100644 --- a/homeassistant/components/ovhcloud_ai_endpoints/config_flow.py +++ b/homeassistant/components/ovhcloud_ai_endpoints/config_flow.py @@ -176,7 +176,7 @@ async def async_step_reconfigure( existing = subentry.data if user_input is not None: - if not user_input.get(CONF_LLM_HASS_API): + if user_input.get(CONF_LLM_HASS_API) is None: user_input.pop(CONF_LLM_HASS_API, None) user_input[CONF_MODEL] = existing[CONF_MODEL] return self.async_update_and_abort( @@ -221,7 +221,7 @@ async def async_step_init( return self.async_abort(reason="entry_not_loaded") if user_input is not None: - if not user_input.get(CONF_LLM_HASS_API): + if user_input.get(CONF_LLM_HASS_API) is None: user_input.pop(CONF_LLM_HASS_API, None) return self.async_create_entry( title=user_input[CONF_MODEL], data=user_input diff --git a/homeassistant/components/reolink/binary_sensor.py b/homeassistant/components/reolink/binary_sensor.py index f4c8d7435d503..f76629fd39c4d 100644 --- a/homeassistant/components/reolink/binary_sensor.py +++ b/homeassistant/components/reolink/binary_sensor.py @@ -156,6 +156,14 @@ class ReolinkIndexBinarySensorEntityDescription( value=lambda api, ch: api.ai_detected(ch, "cry"), supported=lambda api, ch: api.ai_supported(ch, "cry"), ), + ReolinkBinarySensorEntityDescription( + key="tamper", + translation_key="tamper", + cmd_id=[33], + device_class=BinarySensorDeviceClass.TAMPER, + value=lambda api, ch: api.baichuan.tamper_state(ch), + supported=lambda api, ch: api.supported(ch, "tamper"), + ), ) BINARY_SENSORS = ( diff --git a/homeassistant/components/reolink/icons.json b/homeassistant/components/reolink/icons.json index c5833e5c69c50..103e6a5c6da3d 100644 --- a/homeassistant/components/reolink/icons.json +++ b/homeassistant/components/reolink/icons.json @@ -121,6 +121,12 @@ "on": "mdi:package-variant-closed-check" } }, + "tamper": { + "default": "mdi:shield-check", + "state": { + "on": "mdi:shield-alert" + } + }, "vehicle": { "default": "mdi:car-off", "state": { @@ -634,6 +640,12 @@ }, "siren_on_event": { "default": "mdi:alarm-light" + }, + "tamper_enabled": { + "default": "mdi:shield-check", + "state": { + "off": "mdi:shield" + } } }, "time": { diff --git a/homeassistant/components/reolink/manifest.json b/homeassistant/components/reolink/manifest.json index 1ffc8cfdb97ce..b679a603c6dc4 100644 --- a/homeassistant/components/reolink/manifest.json +++ b/homeassistant/components/reolink/manifest.json @@ -20,5 +20,5 @@ "iot_class": "local_push", "loggers": ["reolink_aio"], "quality_scale": "platinum", - "requirements": ["reolink-aio==0.21.9"] + "requirements": ["reolink-aio==0.21.10"] } diff --git a/homeassistant/components/reolink/number.py b/homeassistant/components/reolink/number.py index 5dcb0fcb6c1ef..f309e283edd5d 100644 --- a/homeassistant/components/reolink/number.py +++ b/homeassistant/components/reolink/number.py @@ -572,7 +572,7 @@ class ReolinkChimeNumberEntityDescription( entity_registry_enabled_default=False, native_step=1, native_min_value=-1, - native_max_value=2700, + native_max_value=6000, supported=lambda api, ch: api.supported(ch, "auto_track_limit"), value=lambda api, ch: api.auto_track_limit_left(ch), method=lambda api, ch, value: api.set_auto_track_limit(ch, left=int(value)), @@ -585,7 +585,7 @@ class ReolinkChimeNumberEntityDescription( entity_registry_enabled_default=False, native_step=1, native_min_value=-1, - native_max_value=2700, + native_max_value=6000, supported=lambda api, ch: api.supported(ch, "auto_track_limit"), value=lambda api, ch: api.auto_track_limit_right(ch), method=lambda api, ch, value: api.set_auto_track_limit(ch, right=int(value)), diff --git a/homeassistant/components/reolink/strings.json b/homeassistant/components/reolink/strings.json index 05ca7a3213d1f..63b41b2f97f60 100644 --- a/homeassistant/components/reolink/strings.json +++ b/homeassistant/components/reolink/strings.json @@ -891,6 +891,9 @@ }, "siren_on_event": { "name": "Siren on event" + }, + "tamper_enabled": { + "name": "Tamper alarm" } }, "time": { diff --git a/homeassistant/components/reolink/switch.py b/homeassistant/components/reolink/switch.py index b09d44d9502d2..5dc7c01a38d72 100644 --- a/homeassistant/components/reolink/switch.py +++ b/homeassistant/components/reolink/switch.py @@ -245,6 +245,17 @@ class ReolinkSwitchIndexEntityDescription( value=lambda api, ch: api.pir_reduce_alarm(ch) is True, method=lambda api, ch, value: api.set_pir(ch, reduce_alarm=value), ), + ReolinkSwitchEntityDescription( + key="tamper_enabled", + cmd_key="763", + cmd_id=763, + translation_key="tamper_enabled", + entity_category=EntityCategory.CONFIG, + entity_registry_enabled_default=False, + supported=lambda api, ch: api.supported(ch, "tamper"), + value=lambda api, ch: api.baichuan.tamper_enabled(ch) is True, + method=lambda api, ch, value: api.baichuan.set_tamper(ch, enable=value), + ), ReolinkSwitchEntityDescription( key="privacy_mode", always_available=True, diff --git a/homeassistant/components/rest/data.py b/homeassistant/components/rest/data.py index b3f35d8802e11..824e54f137ad5 100644 --- a/homeassistant/components/rest/data.py +++ b/homeassistant/components/rest/data.py @@ -5,7 +5,7 @@ import aiohttp from aiohttp import hdrs -from multidict import CIMultiDictProxy +from multidict import CIMultiDict, CIMultiDictProxy import xmltodict from homeassistant.core import HomeAssistant @@ -30,7 +30,7 @@ def __init__( method: str, resource: str, encoding: str, - auth: aiohttp.DigestAuthMiddleware | aiohttp.BasicAuth | tuple[str, str] | None, + auth: aiohttp.DigestAuthMiddleware | tuple[str, str] | None, headers: dict[str, str] | None, params: dict[str, str] | None, data: str | None, @@ -45,13 +45,13 @@ def __init__( self._encoding = encoding self._force_use_set_encoding = False - # Convert auth tuple to aiohttp.BasicAuth if needed + # Convert an auth tuple to a basic Authorization header if needed + self._basic_auth: str | None = None + self._digest_auth: aiohttp.DigestAuthMiddleware | None = None if isinstance(auth, tuple) and len(auth) == 2: - self._auth: aiohttp.BasicAuth | aiohttp.DigestAuthMiddleware | None = ( - aiohttp.BasicAuth(auth[0], auth[1], encoding="utf-8") - ) - else: - self._auth = auth + self._basic_auth = aiohttp.encode_basic_auth(auth[0], auth[1]) + elif isinstance(auth, aiohttp.DigestAuthMiddleware): + self._digest_auth = auth self._headers = headers self._params = params @@ -137,11 +137,14 @@ async def async_update(self, log_errors: bool = True) -> None: "timeout": self._timeout, } - # Handle authentication - if isinstance(self._auth, aiohttp.BasicAuth): - request_kwargs["auth"] = self._auth - elif isinstance(self._auth, aiohttp.DigestAuthMiddleware): - request_kwargs["middlewares"] = (self._auth,) + # Handle authentication. A configured Authorization header wins, + # whatever its casing, so setdefault runs on a CIMultiDict. + if self._basic_auth is not None: + headers = CIMultiDict(rendered_headers or {}) + headers.setdefault(hdrs.AUTHORIZATION, self._basic_auth) + request_kwargs["headers"] = headers + elif self._digest_auth is not None: + request_kwargs["middlewares"] = (self._digest_auth,) # Handle data/content if self._request_data: diff --git a/homeassistant/components/risco/manifest.json b/homeassistant/components/risco/manifest.json index c744385f1abd3..800e3d19e30aa 100644 --- a/homeassistant/components/risco/manifest.json +++ b/homeassistant/components/risco/manifest.json @@ -6,5 +6,5 @@ "documentation": "https://www.home-assistant.io/integrations/risco", "iot_class": "local_push", "loggers": ["pyrisco"], - "requirements": ["pyrisco==0.8.0"] + "requirements": ["pyrisco==0.8.1"] } diff --git a/homeassistant/components/script/__init__.py b/homeassistant/components/script/__init__.py index a5c8f591badb0..b653eea86584e 100644 --- a/homeassistant/components/script/__init__.py +++ b/homeassistant/components/script/__init__.py @@ -250,6 +250,9 @@ async def turn_off_service(service: ServiceCall) -> None: if not script_entities: return + for script_entity in script_entities: + script_entity.async_set_context(service.context) + await asyncio.wait( [ create_eager_task(script_entity.async_turn_off()) diff --git a/pyproject.toml b/pyproject.toml index 83c8c5041738f..5212adac0cd71 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -458,11 +458,6 @@ filterwarnings = [ # Modify app state for testing "ignore:Changing state of started or joined application is deprecated:DeprecationWarning:tests.components.http.test_ban", - # -- Tests - # Ignore custom pytest marks - "ignore:Unknown pytest.mark.disable_autouse_fixture:pytest.PytestUnknownMarkWarning:tests.components.met", - "ignore:Unknown pytest.mark.dataset:pytest.PytestUnknownMarkWarning:tests.components.screenlogic", - # -- DeprecationWarning already fixed in our codebase # https://github.com/kurtmckee/feedparser/ - 6.0.12 "ignore:.*a temporary mapping .* from `updated_parsed` to `published_parsed` if `updated_parsed` doesn't exist:DeprecationWarning:feedparser.util", diff --git a/requirements_all.txt b/requirements_all.txt index 17194718ce2d9..d34b125b2894c 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1589,7 +1589,7 @@ micloud==0.5 microBeesPy==0.3.5 # homeassistant.components.midea -midea-local==9.0.0 +midea-local==10.0.0 # homeassistant.components.mill mill-local==0.5.0 @@ -2530,7 +2530,7 @@ pyrecswitch==1.0.2 pyrepetierng==0.1.0 # homeassistant.components.risco -pyrisco==0.8.0 +pyrisco==0.8.1 # homeassistant.components.rituals_perfume_genie pyrituals==0.0.7 @@ -2925,7 +2925,7 @@ renault-api==0.5.12 renson-endura-delta==1.7.2 # homeassistant.components.reolink -reolink-aio==0.21.9 +reolink-aio==0.21.10 # homeassistant.components.radio_frequency rf-protocols==4.3.0 diff --git a/tests/components/aprilaire/test_init.py b/tests/components/aprilaire/test_init.py index 87e4516ead009..a8f2da2f04aaf 100644 --- a/tests/components/aprilaire/test_init.py +++ b/tests/components/aprilaire/test_init.py @@ -1,6 +1,6 @@ """Tests for the Aprilaire integration setup.""" -from unittest.mock import AsyncMock, patch +from unittest.mock import AsyncMock, MagicMock, patch from pyaprilaire.const import Attribute from syrupy.assertion import SnapshotAssertion @@ -27,6 +27,7 @@ async def test_device_registry( config_entry.add_to_hass(hass) client = AsyncMock() + client.stop_listen = MagicMock() client.data = { Attribute.MAC_ADDRESS: "1234567890ab", Attribute.NAME: "Aprilaire", diff --git a/tests/components/blebox/test_helpers.py b/tests/components/blebox/test_helpers.py index 2acfb8d3b3637..c3e45e9417ae7 100644 --- a/tests/components/blebox/test_helpers.py +++ b/tests/components/blebox/test_helpers.py @@ -1,20 +1,21 @@ """Blebox helpers tests.""" -from aiohttp.helpers import BasicAuth +from aiohttp import encode_basic_auth +from aiohttp.hdrs import AUTHORIZATION from homeassistant.components.blebox.helpers import get_maybe_authenticated_session from homeassistant.core import HomeAssistant async def test_get_maybe_authenticated_session_none(hass: HomeAssistant) -> None: - """Tests if session auth is None.""" + """Tests if the session has no authorization header.""" session = get_maybe_authenticated_session(hass=hass, username="", password="") - assert session.auth is None + assert AUTHORIZATION not in session.headers async def test_get_maybe_authenticated_session_auth(hass: HomeAssistant) -> None: - """Tests if session have BasicAuth.""" + """Tests if the session has a basic authorization header.""" session = get_maybe_authenticated_session( hass=hass, username="user", password="password" ) - assert isinstance(session.auth, BasicAuth) + assert session.headers[AUTHORIZATION] == encode_basic_auth("user", "password") diff --git a/tests/components/bluetooth/conftest.py b/tests/components/bluetooth/conftest.py index 2641f6b6dcd90..6627b91ed1930 100644 --- a/tests/components/bluetooth/conftest.py +++ b/tests/components/bluetooth/conftest.py @@ -3,7 +3,6 @@ from collections.abc import Generator from unittest.mock import patch -from bleak_retry_connector import bleak_manager from dbus_fast.aio import message_bus from habluetooth import BaseHaRemoteScanner import habluetooth.util as habluetooth_utils @@ -21,12 +20,6 @@ ) -@pytest.fixture(name="disable_bluez_manager_socket", autouse=True, scope="package") -def disable_bluez_manager_socket(): - """Mock the bluez manager socket.""" - bleak_manager.get_global_bluez_manager_with_timeout._has_dbus_socket = False - - @pytest.fixture(name="disable_dbus_socket", autouse=True, scope="package") def disable_dbus_socket(): """Mock the dbus message bus to avoid creating a socket.""" diff --git a/tests/components/bluetooth/test_init.py b/tests/components/bluetooth/test_init.py index 0bf983ba1db7d..cc981aecc0fe4 100644 --- a/tests/components/bluetooth/test_init.py +++ b/tests/components/bluetooth/test_init.py @@ -2850,9 +2850,10 @@ def _device_detected( assert _get_manager() is not None scanner = HaBleakScannerWrapper( - filters={"UUIDs": ["cba20d00-224d-11e6-9fb8-0002a5d5c51b"]} + filters={"UUIDs": ["cba20d00-224d-11e6-9fb8-0002a5d5c51b"]}, + detection_callback=_device_detected, ) - scanner.register_detection_callback(_device_detected) + await scanner.start() inject_advertisement(hass, switchbot_device, switchbot_adv_2) await hass.async_block_till_done() @@ -2862,11 +2863,12 @@ def _device_detected( assert discovered == [switchbot_device] assert len(detected) == 1 - scanner.register_detection_callback(_device_detected) - # We should get a reply from the history when we register again + # register_detection_callback is deprecated but still replays the history + with pytest.warns(DeprecationWarning, match="is deprecated"): + scanner.register_detection_callback(_device_detected) assert len(detected) == 2 - scanner.register_detection_callback(_device_detected) - # We should get a reply from the history when we register again + with pytest.warns(DeprecationWarning, match="is deprecated"): + scanner.register_detection_callback(_device_detected) assert len(detected) == 3 with patch_discovered_devices([]): @@ -2923,9 +2925,10 @@ def _device_detected( assert _get_manager() is not None scanner = HaBleakScannerWrapper( - service_uuids=["cba20d00-224d-11e6-9fb8-0002a5d5c51b"] + service_uuids=["cba20d00-224d-11e6-9fb8-0002a5d5c51b"], + detection_callback=_device_detected, ) - scanner.register_detection_callback(_device_detected) + await scanner.start() inject_advertisement(hass, switchbot_device, switchbot_adv) inject_advertisement(hass, switchbot_device, switchbot_adv_2) @@ -2983,9 +2986,10 @@ async def _device_detected( assert _get_manager() is not None scanner = HaBleakScannerWrapper( - service_uuids=["cba20d00-224d-11e6-9fb8-0002a5d5c51b"] + service_uuids=["cba20d00-224d-11e6-9fb8-0002a5d5c51b"], + detection_callback=_device_detected, ) - scanner.register_detection_callback(_device_detected) + await scanner.start() inject_advertisement(hass, switchbot_device, switchbot_adv) inject_advertisement(hass, switchbot_device, switchbot_adv_2) @@ -3037,9 +3041,10 @@ def _device_detected( assert _get_manager() is not None scanner = HaBleakScannerWrapper( - service_uuids=["cba20d00-224d-11e6-9fb8-0002a5d5c51b"] + service_uuids=["cba20d00-224d-11e6-9fb8-0002a5d5c51b"], + detection_callback=_device_detected, ) - scanner.register_detection_callback(_device_detected) + await scanner.start() inject_advertisement(hass, switchbot_device, switchbot_adv) await hass.async_block_till_done() @@ -3086,11 +3091,11 @@ def _device_detected( empty_adv = generate_advertisement_data(local_name="empty") assert _get_manager() is not None - scanner = HaBleakScannerWrapper() + scanner = HaBleakScannerWrapper(detection_callback=_device_detected) + await scanner.start() scanner.set_scanning_filter( service_uuids=["cba20d00-224d-11e6-9fb8-0002a5d5c51b"] ) - scanner.register_detection_callback(_device_detected) inject_advertisement(hass, switchbot_device, switchbot_adv) inject_advertisement(hass, switchbot_device, switchbot_adv_2) @@ -3142,11 +3147,11 @@ def _device_detected( empty_adv = generate_advertisement_data(local_name="empty") assert _get_manager() is not None - scanner = HaBleakScannerWrapper() + scanner = HaBleakScannerWrapper(detection_callback=_device_detected) + await scanner.start() scanner.set_scanning_filter( filters={"UUIDs": ["cba20d00-224d-11e6-9fb8-0002a5d5c51b"]} ) - scanner.register_detection_callback(_device_detected) inject_advertisement(hass, switchbot_device, switchbot_adv) inject_advertisement(hass, switchbot_device, switchbot_adv_2) diff --git a/tests/components/cloud/conftest.py b/tests/components/cloud/conftest.py index 809b5a58ba583..5f2e3a6deb13c 100644 --- a/tests/components/cloud/conftest.py +++ b/tests/components/cloud/conftest.py @@ -79,7 +79,7 @@ async def cloud_fixture() -> AsyncGenerator[MagicMock]: mock_cloud.started = None mock_cloud.payments = MagicMock( spec=payments_api.PaymentsApi, - subscription_info=AsyncMock(), + subscription_info=AsyncMock(return_value={"provider": None}), migrate_paypal_agreement=AsyncMock(), ) mock_cloud.ice_servers = MagicMock( diff --git a/tests/components/esphome/test_websocket_api.py b/tests/components/esphome/test_websocket_api.py index a0b92a9576b81..649935b72dedc 100644 --- a/tests/components/esphome/test_websocket_api.py +++ b/tests/components/esphome/test_websocket_api.py @@ -1,5 +1,7 @@ """Tests for ESPHome websocket API.""" +from aioesphomeapi import APIClient + from homeassistant.components.esphome.const import CONF_NOISE_PSK from homeassistant.components.esphome.websocket_api import ENTRY_ID, TYPE @@ -8,6 +10,7 @@ async def test_get_encryption_key( + mock_client: APIClient, init_integration: MockConfigEntry, hass_ws_client: WebSocketGenerator, ) -> None: diff --git a/tests/components/go2rtc/test_init.py b/tests/components/go2rtc/test_init.py index 6d073c3c28877..97e1ed3b27532 100644 --- a/tests/components/go2rtc/test_init.py +++ b/tests/components/go2rtc/test_init.py @@ -7,7 +7,7 @@ from typing import NamedTuple from unittest.mock import ANY, AsyncMock, Mock, patch -from aiohttp import BasicAuth, UnixConnector +from aiohttp import UnixConnector, encode_basic_auth from aiohttp.client_exceptions import ClientConnectionError, ServerConnectionError from awesomeversion import AwesomeVersion from go2rtc_client import Stream @@ -1267,12 +1267,11 @@ async def test_unix_socket_connection(hass: HomeAssistant, server_dir: Path) -> assert isinstance(connector, UnixConnector) assert connector.path == get_go2rtc_unix_socket_path(server_dir) # Auth should be auto-generated when credentials are not explicitly configured - assert "auth" in call_kwargs - auth = call_kwargs["auth"] - assert isinstance(auth, BasicAuth) - # Verify auto-generated credentials match our mocked values - assert auth.login == "mock_username_token" - assert auth.password == "mock_password_token" + assert call_kwargs["headers"] == { + "Authorization": encode_basic_auth( + "mock_username_token", "mock_password_token" + ) + } hass.bus.async_fire(EVENT_HOMEASSISTANT_STOP) await hass.async_block_till_done() @@ -1300,7 +1299,7 @@ async def test_unix_socket_not_used_for_custom_server(hass: HomeAssistant) -> No @pytest.mark.usefixtures("rest_client", "server") async def test_basic_auth_with_custom_url(hass: HomeAssistant) -> None: - """Test BasicAuth session is created with username/password and URL.""" + """Test an auth header session is created with username/password and URL.""" config = { DOMAIN: { CONF_URL: "http://localhost:1984/", @@ -1318,19 +1317,17 @@ async def test_basic_auth_with_custom_url(hass: HomeAssistant) -> None: assert await async_setup_component(hass, DOMAIN, config) await hass.async_block_till_done(wait_background_tasks=True) - # Verify async_create_clientsession was called with BasicAuth + # Verify async_create_clientsession was called with an auth header mock_create_session.assert_called_once() call_kwargs = mock_create_session.call_args[1] - assert "auth" in call_kwargs - auth = call_kwargs["auth"] - assert isinstance(auth, BasicAuth) - assert auth.login == "test_user" - assert auth.password == "test_pass" + assert call_kwargs["headers"] == { + "Authorization": encode_basic_auth("test_user", "test_pass") + } @pytest.mark.usefixtures("rest_client") async def test_basic_auth_with_debug_ui(hass: HomeAssistant, server_dir: Path) -> None: - """Test BasicAuth session created with username/password and debug_ui.""" + """Test an auth header session is created with username/password and debug_ui.""" config = { DOMAIN: { CONF_DEBUG_UI: True, @@ -1361,18 +1358,16 @@ async def test_basic_auth_with_debug_ui(hass: HomeAssistant, server_dir: Path) - assert await async_setup_component(hass, DOMAIN, config) await hass.async_block_till_done(wait_background_tasks=True) - # Verify ClientSession was created with BasicAuth and UnixConnector + # Verify ClientSession was created with an auth header and UnixConnector mock_session_cls.assert_called_once() call_kwargs = mock_session_cls.call_args[1] assert "connector" in call_kwargs connector = call_kwargs["connector"] assert isinstance(connector, UnixConnector) assert connector.path == get_go2rtc_unix_socket_path(server_dir) - assert "auth" in call_kwargs - auth = call_kwargs["auth"] - assert isinstance(auth, BasicAuth) - assert auth.login == "test_user" - assert auth.password == "test_pass" + assert call_kwargs["headers"] == { + "Authorization": encode_basic_auth("test_user", "test_pass") + } # Verify Server was called with username and password mock_server_cls.assert_called_once() diff --git a/tests/components/google_generative_ai_conversation/test_diagnostics.py b/tests/components/google_generative_ai_conversation/test_diagnostics.py index e9d8c6544aab5..7b8742b49f8e2 100644 --- a/tests/components/google_generative_ai_conversation/test_diagnostics.py +++ b/tests/components/google_generative_ai_conversation/test_diagnostics.py @@ -1,5 +1,7 @@ """Tests for the Google Generative AI Conversation diagnostics.""" +from unittest.mock import patch + from syrupy.assertion import SnapshotAssertion from homeassistant.components.google_generative_ai_conversation.const import ( @@ -52,7 +54,8 @@ async def test_diagnostics( CONF_DANGEROUS_BLOCK_THRESHOLD: RECOMMENDED_HARM_BLOCK_THRESHOLD, }, ) - await hass.config_entries.async_setup(mock_config_entry.entry_id) + with patch("google.genai.models.AsyncModels.get"): + await hass.config_entries.async_setup(mock_config_entry.entry_id) assert ( await get_diagnostics_for_config_entry(hass, hass_client, mock_config_entry) == snapshot diff --git a/tests/components/homeassistant_yellow/test_config_flow.py b/tests/components/homeassistant_yellow/test_config_flow.py index 33d6aa0a23c7f..f1987f12e04c2 100644 --- a/tests/components/homeassistant_yellow/test_config_flow.py +++ b/tests/components/homeassistant_yellow/test_config_flow.py @@ -522,7 +522,7 @@ async def mock_install_firmware_step( } -@pytest.mark.usefixtures("supervisor_client") +@pytest.mark.usefixtures("addon_store_info", "supervisor_client") async def test_options_flow_multipan_uninstall(hass: HomeAssistant) -> None: """Test options flow for when multi-PAN firmware is installed.""" mock_integration(hass, MockModule("hassio")) diff --git a/tests/components/http/test_ban.py b/tests/components/http/test_ban.py index ff6465e91f87b..58498d99f5213 100644 --- a/tests/components/http/test_ban.py +++ b/tests/components/http/test_ban.py @@ -255,6 +255,7 @@ async def test_ip_ban_manager_never_started( "os_info", "store_info", "supervisor_info", + "supervisor_root_info", "homeassistant_info", "host_info", "network_info", diff --git a/tests/components/imap/conftest.py b/tests/components/imap/conftest.py index 87663031e7a19..ecc9e8a1fb418 100644 --- a/tests/components/imap/conftest.py +++ b/tests/components/imap/conftest.py @@ -121,4 +121,5 @@ async def wait_hello_from_server() -> None: imap_mock.fetch.return_value = Response(*imap_fetch) imap_mock.wait_hello_from_server.side_effect = wait_hello_from_server imap_mock.timeout = 3 + imap_mock.idle_start.return_value.done = MagicMock(return_value=True) yield imap_mock diff --git a/tests/components/met/conftest.py b/tests/components/met/conftest.py index 92b81d3d32043..cba457bac4e8e 100644 --- a/tests/components/met/conftest.py +++ b/tests/components/met/conftest.py @@ -5,6 +5,13 @@ import pytest +def pytest_configure(config: pytest.Config) -> None: + """Register the mark used to opt out of the autouse fixtures.""" + config.addinivalue_line( + "markers", "disable_autouse_fixture: mark test to skip an autouse fixture" + ) + + @pytest.fixture def mock_weather(): """Mock weather data.""" diff --git a/tests/components/ovhcloud_ai_endpoints/test_config_flow.py b/tests/components/ovhcloud_ai_endpoints/test_config_flow.py index 1b04d662bb5e5..c342c96378a4a 100644 --- a/tests/components/ovhcloud_ai_endpoints/test_config_flow.py +++ b/tests/components/ovhcloud_ai_endpoints/test_config_flow.py @@ -201,6 +201,7 @@ async def test_create_conversation_agent_no_control( assert result["data"] == { CONF_MODEL: "Mistral-Nemo-Instruct-2407", CONF_PROMPT: "you are an assistant", + CONF_LLM_HASS_API: [], } @@ -499,5 +500,11 @@ async def test_reconfigure_conversation_agent_clears_llm_api( subentry = mock_config_entry.subentries[subentry_id] assert subentry.data[CONF_PROMPT] == "updated prompt" - assert CONF_LLM_HASS_API not in subentry.data + assert subentry.data[CONF_LLM_HASS_API] == [] assert subentry.data[CONF_MODEL] == "Meta-Llama-3_3-70B-Instruct" + + result = await mock_config_entry.start_subentry_reconfigure_flow(hass, subentry_id) + + schema = result["data_schema"].schema + key = next(k for k in schema if k == CONF_LLM_HASS_API) + assert key.default() == [] diff --git a/tests/components/reolink/snapshots/test_binary_sensor.ambr b/tests/components/reolink/snapshots/test_binary_sensor.ambr index d031f47192769..2725b53246416 100644 --- a/tests/components/reolink/snapshots/test_binary_sensor.ambr +++ b/tests/components/reolink/snapshots/test_binary_sensor.ambr @@ -655,6 +655,57 @@ 'state': 'on', }) # --- +# name: test_all_entities[binary_sensor.test_reolink_cam_tamper-entry] + EntityRegistryEntrySnapshot({ + 'aliases': list([ + None, + ]), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'binary_sensor', + 'entity_category': None, + 'entity_id': 'binary_sensor.test_reolink_cam_tamper', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Tamper', + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Tamper', + 'platform': 'reolink', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'tamper', + 'unique_id': 'ABC1234567D89EFG_DEF7654321D89GHT_tamper', + 'unit_of_measurement': None, + }) +# --- +# name: test_all_entities[binary_sensor.test_reolink_cam_tamper-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + : 'tamper', + : 'test_reolink_cam Tamper', + }), + 'context': , + 'entity_id': 'binary_sensor.test_reolink_cam_tamper', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'on', + }) +# --- # name: test_all_entities[binary_sensor.test_reolink_cam_vehicle-entry] EntityRegistryEntrySnapshot({ 'aliases': list([ diff --git a/tests/components/reolink/snapshots/test_diagnostics.ambr b/tests/components/reolink/snapshots/test_diagnostics.ambr index 48b1a55edccf1..1de0fe0c10ff6 100644 --- a/tests/components/reolink/snapshots/test_diagnostics.ambr +++ b/tests/components/reolink/snapshots/test_diagnostics.ambr @@ -128,6 +128,10 @@ '0': 1, 'null': 1, }), + '763': dict({ + '0': 1, + 'null': 1, + }), 'DingDongOpt': dict({ '0': 2, 'null': 2, diff --git a/tests/components/reolink/snapshots/test_number.ambr b/tests/components/reolink/snapshots/test_number.ambr index e6746d5a002a9..867cd7e0b5357 100644 --- a/tests/components/reolink/snapshots/test_number.ambr +++ b/tests/components/reolink/snapshots/test_number.ambr @@ -1445,7 +1445,7 @@ ]), 'area_id': None, 'capabilities': dict({ - : 2700, + : 6000, : -1, : , : 1, @@ -1484,7 +1484,7 @@ StateSnapshot({ 'attributes': ReadOnlyDict({ : 'test_reolink_cam Auto track limit left', - : 2700, + : 6000, : -1, : , : 1, @@ -1504,7 +1504,7 @@ ]), 'area_id': None, 'capabilities': dict({ - : 2700, + : 6000, : -1, : , : 1, @@ -1543,7 +1543,7 @@ StateSnapshot({ 'attributes': ReadOnlyDict({ : 'test_reolink_cam Auto track limit right', - : 2700, + : 6000, : -1, : , : 1, diff --git a/tests/components/reolink/snapshots/test_switch.ambr b/tests/components/reolink/snapshots/test_switch.ambr index 0d1ac08c5606c..d2e7e42a952de 100644 --- a/tests/components/reolink/snapshots/test_switch.ambr +++ b/tests/components/reolink/snapshots/test_switch.ambr @@ -1049,6 +1049,56 @@ 'state': 'on', }) # --- +# name: test_all_entities[switch.test_reolink_cam_tamper_alarm-entry] + EntityRegistryEntrySnapshot({ + 'aliases': list([ + None, + ]), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'switch', + 'entity_category': , + 'entity_id': 'switch.test_reolink_cam_tamper_alarm', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Tamper alarm', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Tamper alarm', + 'platform': 'reolink', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'tamper_enabled', + 'unique_id': 'ABC1234567D89EFG_DEF7654321D89GHT_tamper_enabled', + 'unit_of_measurement': None, + }) +# --- +# name: test_all_entities[switch.test_reolink_cam_tamper_alarm-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + : 'test_reolink_cam Tamper alarm', + }), + 'context': , + 'entity_id': 'switch.test_reolink_cam_tamper_alarm', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'off', + }) +# --- # name: test_all_entities[switch.test_reolink_name_email_on_event-entry] EntityRegistryEntrySnapshot({ 'aliases': list([ @@ -2399,3 +2449,53 @@ 'state': 'on', }) # --- +# name: test_all_entities_dual_lens[switch.test_reolink_name_tamper_alarm-entry] + EntityRegistryEntrySnapshot({ + 'aliases': list([ + None, + ]), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'switch', + 'entity_category': , + 'entity_id': 'switch.test_reolink_name_tamper_alarm', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Tamper alarm', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Tamper alarm', + 'platform': 'reolink', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'tamper_enabled', + 'unique_id': 'ABC1234567D89EFG_0_tamper_enabled', + 'unit_of_measurement': None, + }) +# --- +# name: test_all_entities_dual_lens[switch.test_reolink_name_tamper_alarm-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + : 'test_reolink_name Tamper alarm', + }), + 'context': , + 'entity_id': 'switch.test_reolink_name_tamper_alarm', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'off', + }) +# --- diff --git a/tests/components/rest/test_data.py b/tests/components/rest/test_data.py index 9dd1b0fcec2b4..9c9fde5ebcbb8 100644 --- a/tests/components/rest/test_data.py +++ b/tests/components/rest/test_data.py @@ -4,7 +4,9 @@ import logging from unittest.mock import patch +from aiohttp import hdrs from freezegun.api import FrozenDateTimeFactory +from multidict import CIMultiDict import pytest from homeassistant.components.rest import DOMAIN @@ -551,3 +553,51 @@ async def test_rest_data_boolean_params_converted_to_strings( assert url.query["boolFalse"] == "false" assert url.query["stringParam"] == "test" assert url.query["intParam"] == "123" + + +@pytest.mark.parametrize( + "header_name", + [ + pytest.param("Authorization", id="canonical_casing"), + pytest.param("authorization", id="lowercase"), + ], +) +async def test_rest_data_configured_authorization_header_wins( + hass: HomeAssistant, + aioclient_mock: AiohttpClientMocker, + header_name: str, +) -> None: + """Test a configured Authorization header replaces generated basic auth.""" + aioclient_mock.get( + "http://example.com/api", + status=200, + json={"status": "ok"}, + headers={"Content-Type": "application/json"}, + ) + + assert await async_setup_component( + hass, + DOMAIN, + { + DOMAIN: { + "resource": "http://example.com/api", + "method": "GET", + "username": "user", + "password": "pass", + "headers": {header_name: "Bearer configured"}, + "sensor": [ + { + "name": "test_sensor", + "value_template": "{{ value_json.status }}", + } + ], + } + }, + ) + await hass.async_block_till_done() + + assert len(aioclient_mock.mock_calls) == 1 + _method, _url, _data, headers = aioclient_mock.mock_calls[0] + + # The generated basic auth must not be sent as a second Authorization header + assert CIMultiDict(headers).getall(hdrs.AUTHORIZATION) == ["Bearer configured"] diff --git a/tests/components/screenlogic/conftest.py b/tests/components/screenlogic/conftest.py index 25727bf7a8c3a..4f938a86c48e6 100644 --- a/tests/components/screenlogic/conftest.py +++ b/tests/components/screenlogic/conftest.py @@ -19,6 +19,11 @@ from tests.common import MockConfigEntry +def pytest_configure(config: pytest.Config) -> None: + """Register the mark used to select the dataset.""" + config.addinivalue_line("markers", "dataset: mark test with the dataset to load") + + @pytest.fixture def mock_config_entry() -> MockConfigEntry: """Return a mocked config entry.""" diff --git a/tests/components/script/test_init.py b/tests/components/script/test_init.py index 80ad3cfa28506..a1667eb5f9e8c 100644 --- a/tests/components/script/test_init.py +++ b/tests/components/script/test_init.py @@ -650,18 +650,35 @@ async def test_shared_context(hass: HomeAssistant) -> None: event_mock = Mock() run_mock = Mock() + started_flag = asyncio.Event() - hass.bus.async_listen(event, event_mock) + @callback + def event_started(event): + event_mock(event) + started_flag.set() + + hass.bus.async_listen(event, event_started) hass.bus.async_listen(EVENT_SCRIPT_STARTED, run_mock) assert await async_setup_component( - hass, DOMAIN, {"script": {"test": {"sequence": [{"event": event}]}}} + hass, + DOMAIN, + { + "script": { + "test": { + "sequence": [ + {"event": event}, + {"wait_template": "{{ is_state('test.script', 'on') }}"}, + ] + } + } + }, ) await hass.services.async_call( DOMAIN, SERVICE_TURN_ON, {ATTR_ENTITY_ID: ENTITY_ID}, context=context ) - await hass.async_block_till_done() + await asyncio.wait_for(started_flag.wait(), 1) assert event_mock.call_count == 1 assert run_mock.call_count == 1 @@ -681,6 +698,20 @@ async def test_shared_context(hass: HomeAssistant) -> None: assert state is not None assert state.context == context + # Stopping the script is attributed to whoever asked for the stop + stop_context = Context() + await hass.services.async_call( + DOMAIN, + SERVICE_TURN_OFF, + {ATTR_ENTITY_ID: ENTITY_ID}, + blocking=True, + context=stop_context, + ) + await hass.async_block_till_done() + + assert not script.is_on(hass, ENTITY_ID) + assert hass.states.get(ENTITY_ID).context is stop_context + async def test_logging_script_error( hass: HomeAssistant, caplog: pytest.LogCaptureFixture diff --git a/tests/components/shelly/conftest.py b/tests/components/shelly/conftest.py index d032eec14fdda..ddd01d8a6efae 100644 --- a/tests/components/shelly/conftest.py +++ b/tests/components/shelly/conftest.py @@ -603,6 +603,7 @@ def _mock_rpc_device(version: str | None = None): zigbee_firmware=False, ip_address="10.10.10.10", wifi_setconfig=AsyncMock(return_value={"restart_required": True}), + ble_getconfig=AsyncMock(return_value={}), ble_setconfig=AsyncMock(return_value={"restart_required": False}), shutdown=AsyncMock(), ) @@ -630,6 +631,7 @@ def _mock_blu_rtv_device(version: str | None = None): ), xmod_info={}, wifi_setconfig=AsyncMock(return_value={}), + ble_getconfig=AsyncMock(return_value={}), ble_setconfig=AsyncMock(return_value={}), ) type(device).name = PropertyMock(return_value="Test name") diff --git a/tests/components/xbox/snapshots/test_media_player.ambr b/tests/components/xbox/snapshots/test_media_player.ambr index cce999c5d953f..5ee52538864f0 100644 --- a/tests/components/xbox/snapshots/test_media_player.ambr +++ b/tests/components/xbox/snapshots/test_media_player.ambr @@ -176,7 +176,7 @@ StateSnapshot({ 'attributes': ReadOnlyDict({ : 'https://store-images.s-microsoft.com/image/apps.9815.9007199266246365.7dc5d343-fe4a-40c3-93dd-c78e77f97331.45eebdef-f725-4799-bbf8-9ad8391a8279', - : '/api/media_player_proxy/media_player.xone?token=mock_token&cache=1cae983bd1c4c429', + : '/api/media_player_proxy/media_player.xone?token=mock_token_0123456789abcdef01234&cache=1cae983bd1c4c429', : 'XONE', : '9WZDNCRFJ3TJ', : , @@ -233,7 +233,7 @@ StateSnapshot({ 'attributes': ReadOnlyDict({ : 'https://store-images.s-microsoft.com/image/apps.9815.9007199266246365.7dc5d343-fe4a-40c3-93dd-c78e77f97331.45eebdef-f725-4799-bbf8-9ad8391a8279', - : '/api/media_player_proxy/media_player.xonex?token=mock_token&cache=1cae983bd1c4c429', + : '/api/media_player_proxy/media_player.xonex?token=mock_token_0123456789abcdef01234&cache=1cae983bd1c4c429', : 'XONEX', : '9WZDNCRFJ3TJ', : , @@ -398,7 +398,7 @@ StateSnapshot({ 'attributes': ReadOnlyDict({ : 'https://images-eds-ssl.xboxlive.com/image?url=8Oaj9Ryq1G1_p3lLnXlsaZgGzAie6Mnu24_PawYuDYIoH77pJ.X5Z.MqQPibUVTcbx57bBxf63xu2Ef8acP3S7Uz80NbHc5nza..4R00GT1V5G760cdfX7Hl0uIHdHCbkzTikdvNE0TedhKgQfQy.2gjOGbd8kXZXzy4VzeJiNPLhLq2QUQbo8q3sVoSPaw73J4BxM7gaNX8V8qLcWtO5sn6vgbTso51OaEIn4zeAiw-', - : '/api/media_player_proxy/media_player.xone?token=mock_token&cache=cf419ddd9fb966d6', + : '/api/media_player_proxy/media_player.xone?token=mock_token_0123456789abcdef01234&cache=cf419ddd9fb966d6', : 'XONE', : '9VWGNH0VBZJX', : , @@ -455,7 +455,7 @@ StateSnapshot({ 'attributes': ReadOnlyDict({ : 'https://images-eds-ssl.xboxlive.com/image?url=8Oaj9Ryq1G1_p3lLnXlsaZgGzAie6Mnu24_PawYuDYIoH77pJ.X5Z.MqQPibUVTcbx57bBxf63xu2Ef8acP3S7Uz80NbHc5nza..4R00GT1V5G760cdfX7Hl0uIHdHCbkzTikdvNE0TedhKgQfQy.2gjOGbd8kXZXzy4VzeJiNPLhLq2QUQbo8q3sVoSPaw73J4BxM7gaNX8V8qLcWtO5sn6vgbTso51OaEIn4zeAiw-', - : '/api/media_player_proxy/media_player.xonex?token=mock_token&cache=cf419ddd9fb966d6', + : '/api/media_player_proxy/media_player.xonex?token=mock_token_0123456789abcdef01234&cache=cf419ddd9fb966d6', : 'XONEX', : '9VWGNH0VBZJX', : , diff --git a/tests/components/xbox/test_media_player.py b/tests/components/xbox/test_media_player.py index f0c48763dca97..c32c51b13ca00 100644 --- a/tests/components/xbox/test_media_player.py +++ b/tests/components/xbox/test_media_player.py @@ -64,7 +64,9 @@ def media_player_only() -> Generator[None]: @pytest.fixture(autouse=True) def mock_token() -> Generator[MagicMock]: """Mock token generator.""" - with patch("secrets.token_hex", return_value="mock_token") as token: + with patch( + "secrets.token_hex", return_value="mock_token_0123456789abcdef01234" + ) as token: yield token diff --git a/tests/components/zwave_js/test_config_flow.py b/tests/components/zwave_js/test_config_flow.py index fe5ac5b6384b3..1395660631290 100644 --- a/tests/components/zwave_js/test_config_flow.py +++ b/tests/components/zwave_js/test_config_flow.py @@ -2552,7 +2552,7 @@ async def test_usb_discovery_leaves_manual_entry_alone( assert entry.data == {"url": "ws://external-server:3000"} -@pytest.mark.usefixtures("supervisor", "addon_info") +@pytest.mark.usefixtures("supervisor", "addon_info", "addon_store_info") async def test_usb_discovery_ignored( hass: HomeAssistant, mock_usb_serial_by_id: MagicMock, diff --git a/tests/conftest.py b/tests/conftest.py index 665d019330a21..082f1278ddd14 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -32,6 +32,7 @@ from aiohttp.typedefs import JSONDecoder from aiohttp.web import Application import bcrypt +from bleak_retry_connector import bleak_manager import freezegun import multidict import pytest @@ -1975,6 +1976,8 @@ async def mock_enable_bluetooth( @pytest.fixture(autouse=True, scope="session") def mock_bluetooth_adapters() -> Generator[None]: """Fixture to mock bluetooth adapters.""" + bleak_manager.get_global_bluez_manager_with_timeout._has_dbus_socket = False + with ( # Simulate the Bluetooth management API being unavailable, as it is on # CI and most dev machines. Letting the real setup() run would attempt