"""Test the Gardena Bluetooth setup.""" import asyncio from datetime import timedelta from unittest.mock import Mock from gardena_bluetooth.const import ( AquaContour, AquaContourBattery, Battery, DeviceConfiguration, DeviceInformation, ) from habluetooth import BluetoothServiceInfo import pytest from syrupy.assertion import SnapshotAssertion from homeassistant.components.gardena_bluetooth import DeviceUnavailable from homeassistant.components.gardena_bluetooth.const import DOMAIN from homeassistant.config_entries import ConfigEntryState from homeassistant.core import HomeAssistant from homeassistant.helpers import device_registry as dr from homeassistant.util import utcnow from . import ( AQUA_CONTOUR_SERVICE_INFO, MISSING_MANUFACTURER_DATA_SERVICE_INFO, WATER_TIMER_SERVICE_INFO, get_config_entry, ) from tests.common import MockConfigEntry, async_fire_time_changed from tests.components.bluetooth import inject_bluetooth_service_info @pytest.mark.parametrize( ("service_info", "char_values"), [ pytest.param( WATER_TIMER_SERVICE_INFO, { Battery.battery_level.uuid: Battery.battery_level.encode(100), DeviceInformation.model_number.uuid: ( DeviceInformation.model_number.encode("Model Number TBD") ), DeviceInformation.firmware_version.uuid: ( DeviceInformation.firmware_version.encode("1.2.3") ), DeviceConfiguration.custom_device_name.uuid: ( DeviceConfiguration.custom_device_name.encode("My timer") ), }, id=WATER_TIMER_SERVICE_INFO.name, ), pytest.param( AQUA_CONTOUR_SERVICE_INFO, { AquaContourBattery.battery_level.uuid: ( AquaContourBattery.battery_level.encode(100) ), DeviceInformation.model_number.uuid: ( DeviceInformation.model_number.encode("Aqua Contour") ), DeviceInformation.firmware_version.uuid: ( DeviceInformation.firmware_version.encode("2.0.0") ), AquaContour.custom_device_name.uuid: ( AquaContour.custom_device_name.encode("My contour") ), }, id=AQUA_CONTOUR_SERVICE_INFO.name, ), ], ) async def test_setup( hass: HomeAssistant, device_registry: dr.DeviceRegistry, mock_read_char_raw: dict[str, bytes], service_info: BluetoothServiceInfo, char_values: dict[str, bytes], snapshot: SnapshotAssertion, ) -> None: """Test setup creates expected devices.""" mock_entry = get_config_entry(service_info) mock_read_char_raw.update(char_values) inject_bluetooth_service_info(hass, service_info) mock_entry.add_to_hass(hass) assert await hass.config_entries.async_setup(mock_entry.entry_id) is True device = device_registry.async_get_device( identifiers={(DOMAIN, service_info.address)} ) assert device == snapshot async def test_setup_delayed_product( hass: HomeAssistant, device_registry: dr.DeviceRegistry, mock_entry: MockConfigEntry, mock_read_char_raw: dict[str, bytes], manufacturer_request_event: asyncio.Event, snapshot: SnapshotAssertion, ) -> None: """Test setup creates expected devices.""" mock_read_char_raw[Battery.battery_level.uuid] = Battery.battery_level.encode(100) mock_entry.add_to_hass(hass) manufacturer_request_event.clear() async with asyncio.TaskGroup() as tg: setup_task = tg.create_task( hass.config_entries.async_setup(mock_entry.entry_id) ) await manufacturer_request_event.wait() assert mock_entry.state is ConfigEntryState.SETUP_IN_PROGRESS inject_bluetooth_service_info(hass, MISSING_MANUFACTURER_DATA_SERVICE_INFO) inject_bluetooth_service_info(hass, WATER_TIMER_SERVICE_INFO) assert await setup_task is True async def test_setup_retry( hass: HomeAssistant, mock_entry: MockConfigEntry, mock_client: Mock ) -> None: """Test setup creates expected devices.""" inject_bluetooth_service_info(hass, WATER_TIMER_SERVICE_INFO) original_read_char = mock_client.read_char.side_effect mock_client.read_char.side_effect = DeviceUnavailable mock_entry.add_to_hass(hass) await hass.config_entries.async_setup(mock_entry.entry_id) await hass.async_block_till_done() assert mock_entry.state is ConfigEntryState.SETUP_RETRY mock_client.read_char.side_effect = original_read_char async_fire_time_changed(hass, utcnow() + timedelta(seconds=10)) await hass.async_block_till_done(wait_background_tasks=True) assert mock_entry.state is ConfigEntryState.LOADED