From 06d04c001d1150d9f36d11354f3e419b976b7de0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ab=C3=ADlio=20Costa?= Date: Thu, 26 Jun 2025 19:55:46 +0100 Subject: [PATCH] Use non-autospec mock for Reolink's host tests (#147619) --- tests/components/reolink/conftest.py | 1 + tests/components/reolink/test_host.py | 144 +++++++++++--------------- 2 files changed, 59 insertions(+), 86 deletions(-) diff --git a/tests/components/reolink/conftest.py b/tests/components/reolink/conftest.py index 6d5e7d2688e..256c50c9ea2 100644 --- a/tests/components/reolink/conftest.py +++ b/tests/components/reolink/conftest.py @@ -81,6 +81,7 @@ def _init_host_mock(host_mock: MagicMock) -> None: host_mock.set_audio = AsyncMock() host_mock.set_email = AsyncMock() host_mock.ONVIF_event_callback = AsyncMock() + host_mock.renew = AsyncMock() host_mock.is_nvr = True host_mock.is_hub = False host_mock.mac_address = TEST_MAC diff --git a/tests/components/reolink/test_host.py b/tests/components/reolink/test_host.py index f997a1ac08a..6ae7c66704c 100644 --- a/tests/components/reolink/test_host.py +++ b/tests/components/reolink/test_host.py @@ -39,11 +39,10 @@ async def test_setup_with_tcp_push( hass: HomeAssistant, freezer: FrozenDateTimeFactory, config_entry: MockConfigEntry, - reolink_connect: MagicMock, + reolink_host: MagicMock, ) -> None: """Test successful setup of the integration with TCP push callbacks.""" - reolink_connect.baichuan.events_active = True - reolink_connect.baichuan.subscribe_events.reset_mock(side_effect=True) + reolink_host.baichuan.events_active = True with patch("homeassistant.components.reolink.PLATFORMS", [Platform.BINARY_SENSOR]): assert await hass.config_entries.async_setup(config_entry.entry_id) await hass.async_block_till_done() @@ -54,47 +53,39 @@ async def test_setup_with_tcp_push( await hass.async_block_till_done() # ONVIF push subscription not called - assert not reolink_connect.subscribe.called - - reolink_connect.baichuan.events_active = False - reolink_connect.baichuan.subscribe_events.side_effect = ReolinkError("Test error") + assert not reolink_host.subscribe.called async def test_unloading_with_tcp_push( hass: HomeAssistant, config_entry: MockConfigEntry, - reolink_connect: MagicMock, + reolink_host: MagicMock, ) -> None: """Test successful unloading of the integration with TCP push callbacks.""" - reolink_connect.baichuan.events_active = True - reolink_connect.baichuan.subscribe_events.reset_mock(side_effect=True) + reolink_host.baichuan.events_active = True with patch("homeassistant.components.reolink.PLATFORMS", [Platform.BINARY_SENSOR]): assert await hass.config_entries.async_setup(config_entry.entry_id) await hass.async_block_till_done() assert config_entry.state is ConfigEntryState.LOADED - reolink_connect.baichuan.unsubscribe_events.side_effect = ReolinkError("Test error") + reolink_host.baichuan.unsubscribe_events.side_effect = ReolinkError("Test error") # Unload the config entry assert await hass.config_entries.async_unload(config_entry.entry_id) await hass.async_block_till_done() assert config_entry.state is ConfigEntryState.NOT_LOADED - reolink_connect.baichuan.events_active = False - reolink_connect.baichuan.subscribe_events.side_effect = ReolinkError("Test error") - reolink_connect.baichuan.unsubscribe_events.reset_mock(side_effect=True) - async def test_webhook_callback( hass: HomeAssistant, hass_client_no_auth: ClientSessionGenerator, freezer: FrozenDateTimeFactory, config_entry: MockConfigEntry, - reolink_connect: MagicMock, + reolink_host: MagicMock, entity_registry: er.EntityRegistry, ) -> None: """Test webhook callback with motion sensor.""" - reolink_connect.motion_detected.return_value = False + reolink_host.motion_detected.return_value = False with patch("homeassistant.components.reolink.PLATFORMS", [Platform.BINARY_SENSOR]): assert await hass.config_entries.async_setup(config_entry.entry_id) @@ -115,9 +106,9 @@ async def test_webhook_callback( assert hass.states.get(entity_id).state == STATE_OFF # test webhook callback success all channels - reolink_connect.get_motion_state_all_ch.return_value = True - reolink_connect.motion_detected.return_value = True - reolink_connect.ONVIF_event_callback.return_value = None + reolink_host.get_motion_state_all_ch.return_value = True + reolink_host.motion_detected.return_value = True + reolink_host.ONVIF_event_callback.return_value = None await client.post(f"/api/webhook/{webhook_id}") await hass.async_block_till_done() signal_all.assert_called_once() @@ -129,7 +120,7 @@ async def test_webhook_callback( # test webhook callback all channels with failure to read motion_state signal_all.reset_mock() - reolink_connect.get_motion_state_all_ch.return_value = False + reolink_host.get_motion_state_all_ch.return_value = False await client.post(f"/api/webhook/{webhook_id}") await hass.async_block_till_done() signal_all.assert_not_called() @@ -137,8 +128,8 @@ async def test_webhook_callback( assert hass.states.get(entity_id).state == STATE_ON # test webhook callback success single channel - reolink_connect.motion_detected.return_value = False - reolink_connect.ONVIF_event_callback.return_value = [0] + reolink_host.motion_detected.return_value = False + reolink_host.ONVIF_event_callback.return_value = [0] await client.post(f"/api/webhook/{webhook_id}", data="test_data") await hass.async_block_till_done() signal_ch.assert_called_once() @@ -146,7 +137,7 @@ async def test_webhook_callback( # test webhook callback single channel with error in event callback signal_ch.reset_mock() - reolink_connect.ONVIF_event_callback.side_effect = Exception("Test error") + reolink_host.ONVIF_event_callback.side_effect = Exception("Test error") await client.post(f"/api/webhook/{webhook_id}", data="test_data") await hass.async_block_till_done() signal_ch.assert_not_called() @@ -171,45 +162,42 @@ async def test_webhook_callback( await async_handle_webhook(hass, webhook_id, request) signal_all.assert_not_called() - reolink_connect.ONVIF_event_callback.reset_mock(side_effect=True) - async def test_no_mac( hass: HomeAssistant, config_entry: MockConfigEntry, - reolink_connect: MagicMock, + reolink_host: MagicMock, ) -> None: """Test setup of host with no mac.""" - original = reolink_connect.mac_address - reolink_connect.mac_address = None + original = reolink_host.mac_address + reolink_host.mac_address = None assert not await hass.config_entries.async_setup(config_entry.entry_id) await hass.async_block_till_done() assert config_entry.state is ConfigEntryState.SETUP_RETRY - reolink_connect.mac_address = original + reolink_host.mac_address = original async def test_subscribe_error( hass: HomeAssistant, config_entry: MockConfigEntry, - reolink_connect: MagicMock, + reolink_host: MagicMock, ) -> None: """Test error when subscribing to ONVIF does not block startup.""" - reolink_connect.subscribe.side_effect = ReolinkError("Test Error") - reolink_connect.subscribed.return_value = False + reolink_host.subscribe.side_effect = ReolinkError("Test Error") + reolink_host.subscribed.return_value = False assert await hass.config_entries.async_setup(config_entry.entry_id) await hass.async_block_till_done() assert config_entry.state is ConfigEntryState.LOADED - reolink_connect.subscribe.reset_mock(side_effect=True) async def test_subscribe_unsuccesfull( hass: HomeAssistant, config_entry: MockConfigEntry, - reolink_connect: MagicMock, + reolink_host: MagicMock, ) -> None: """Test that a unsuccessful ONVIF subscription does not block startup.""" - reolink_connect.subscribed.return_value = False + reolink_host.subscribed.return_value = False assert await hass.config_entries.async_setup(config_entry.entry_id) await hass.async_block_till_done() assert config_entry.state is ConfigEntryState.LOADED @@ -218,7 +206,7 @@ async def test_subscribe_unsuccesfull( async def test_initial_ONVIF_not_supported( hass: HomeAssistant, config_entry: MockConfigEntry, - reolink_connect: MagicMock, + reolink_host: MagicMock, ) -> None: """Test setup when initial ONVIF is not supported.""" @@ -228,7 +216,7 @@ async def test_initial_ONVIF_not_supported( return False return True - reolink_connect.supported = test_supported + reolink_host.supported = test_supported assert await hass.config_entries.async_setup(config_entry.entry_id) await hass.async_block_till_done() @@ -238,7 +226,7 @@ async def test_initial_ONVIF_not_supported( async def test_ONVIF_not_supported( hass: HomeAssistant, config_entry: MockConfigEntry, - reolink_connect: MagicMock, + reolink_host: MagicMock, ) -> None: """Test setup is not blocked when ONVIF API returns NotSupportedError.""" @@ -248,26 +236,23 @@ async def test_ONVIF_not_supported( return False return True - reolink_connect.supported = test_supported - reolink_connect.subscribed.return_value = False - reolink_connect.subscribe.side_effect = NotSupportedError("Test error") + reolink_host.supported = test_supported + reolink_host.subscribed.return_value = False + reolink_host.subscribe.side_effect = NotSupportedError("Test error") assert await hass.config_entries.async_setup(config_entry.entry_id) await hass.async_block_till_done() assert config_entry.state is ConfigEntryState.LOADED - reolink_connect.subscribe.reset_mock(side_effect=True) - reolink_connect.subscribed.return_value = True - async def test_renew( hass: HomeAssistant, freezer: FrozenDateTimeFactory, config_entry: MockConfigEntry, - reolink_connect: MagicMock, + reolink_host: MagicMock, ) -> None: """Test renew of the ONVIF subscription.""" - reolink_connect.renewtimer.return_value = 1 + reolink_host.renewtimer.return_value = 1 assert await hass.config_entries.async_setup(config_entry.entry_id) await hass.async_block_till_done() @@ -277,56 +262,51 @@ async def test_renew( async_fire_time_changed(hass) await hass.async_block_till_done() - reolink_connect.renew.assert_called() + reolink_host.renew.assert_called() - reolink_connect.renew.side_effect = SubscriptionError("Test error") + reolink_host.renew.side_effect = SubscriptionError("Test error") freezer.tick(DEVICE_UPDATE_INTERVAL) async_fire_time_changed(hass) await hass.async_block_till_done() - reolink_connect.subscribe.assert_called() + reolink_host.subscribe.assert_called() - reolink_connect.subscribe.reset_mock() - reolink_connect.subscribe.side_effect = SubscriptionError("Test error") + reolink_host.subscribe.reset_mock() + reolink_host.subscribe.side_effect = SubscriptionError("Test error") freezer.tick(DEVICE_UPDATE_INTERVAL) async_fire_time_changed(hass) await hass.async_block_till_done() - reolink_connect.subscribe.assert_called() - - reolink_connect.renew.reset_mock(side_effect=True) - reolink_connect.subscribe.reset_mock(side_effect=True) + reolink_host.subscribe.assert_called() async def test_long_poll_renew_fail( hass: HomeAssistant, freezer: FrozenDateTimeFactory, config_entry: MockConfigEntry, - reolink_connect: MagicMock, + reolink_host: MagicMock, ) -> None: """Test ONVIF long polling errors while renewing.""" assert await hass.config_entries.async_setup(config_entry.entry_id) await hass.async_block_till_done() assert config_entry.state is ConfigEntryState.LOADED - reolink_connect.subscribe.side_effect = NotSupportedError("Test error") + reolink_host.subscribe.side_effect = NotSupportedError("Test error") freezer.tick(timedelta(seconds=FIRST_ONVIF_TIMEOUT)) async_fire_time_changed(hass) await hass.async_block_till_done() # ensure long polling continues - reolink_connect.pull_point_request.assert_called() - - reolink_connect.subscribe.reset_mock(side_effect=True) + reolink_host.pull_point_request.assert_called() async def test_register_webhook_errors( hass: HomeAssistant, config_entry: MockConfigEntry, - reolink_connect: MagicMock, + reolink_host: MagicMock, ) -> None: """Test errors while registering the webhook.""" with patch( @@ -343,7 +323,7 @@ async def test_long_poll_stop_when_push( hass_client_no_auth: ClientSessionGenerator, freezer: FrozenDateTimeFactory, config_entry: MockConfigEntry, - reolink_connect: MagicMock, + reolink_host: MagicMock, ) -> None: """Test ONVIF long polling stops when ONVIF push comes in.""" assert await hass.config_entries.async_setup(config_entry.entry_id) @@ -357,7 +337,7 @@ async def test_long_poll_stop_when_push( # simulate ONVIF push callback client = await hass_client_no_auth() - reolink_connect.ONVIF_event_callback.return_value = None + reolink_host.ONVIF_event_callback.return_value = None webhook_id = config_entry.runtime_data.host.webhook_id await client.post(f"/api/webhook/{webhook_id}") @@ -365,31 +345,29 @@ async def test_long_poll_stop_when_push( async_fire_time_changed(hass) await hass.async_block_till_done() - reolink_connect.unsubscribe.assert_called_with(sub_type=SubType.long_poll) + reolink_host.unsubscribe.assert_called_with(sub_type=SubType.long_poll) async def test_long_poll_errors( hass: HomeAssistant, freezer: FrozenDateTimeFactory, config_entry: MockConfigEntry, - reolink_connect: MagicMock, + reolink_host: MagicMock, ) -> None: """Test errors during ONVIF long polling.""" - reolink_connect.pull_point_request.reset_mock() - assert await hass.config_entries.async_setup(config_entry.entry_id) await hass.async_block_till_done() assert config_entry.state is ConfigEntryState.LOADED - reolink_connect.pull_point_request.side_effect = ReolinkError("Test error") + reolink_host.pull_point_request.side_effect = ReolinkError("Test error") # start ONVIF long polling because ONVIF push did not came in freezer.tick(timedelta(seconds=FIRST_ONVIF_TIMEOUT)) async_fire_time_changed(hass) await hass.async_block_till_done() - reolink_connect.pull_point_request.assert_called_once() - reolink_connect.pull_point_request.side_effect = Exception("Test error") + reolink_host.pull_point_request.assert_called_once() + reolink_host.pull_point_request.side_effect = Exception("Test error") freezer.tick(timedelta(seconds=LONG_POLL_ERROR_COOLDOWN)) async_fire_time_changed(hass) @@ -399,21 +377,18 @@ async def test_long_poll_errors( async_fire_time_changed(hass) await hass.async_block_till_done() - reolink_connect.unsubscribe.assert_called_with(sub_type=SubType.long_poll) - - reolink_connect.pull_point_request.reset_mock(side_effect=True) + reolink_host.unsubscribe.assert_called_with(sub_type=SubType.long_poll) async def test_fast_polling_errors( hass: HomeAssistant, freezer: FrozenDateTimeFactory, config_entry: MockConfigEntry, - reolink_connect: MagicMock, + reolink_host: MagicMock, ) -> None: """Test errors during ONVIF fast polling.""" - reolink_connect.get_motion_state_all_ch.reset_mock() - reolink_connect.get_motion_state_all_ch.side_effect = ReolinkError("Test error") - reolink_connect.pull_point_request.side_effect = ReolinkError("Test error") + reolink_host.get_motion_state_all_ch.side_effect = ReolinkError("Test error") + reolink_host.pull_point_request.side_effect = ReolinkError("Test error") assert await hass.config_entries.async_setup(config_entry.entry_id) await hass.async_block_till_done() @@ -429,17 +404,14 @@ async def test_fast_polling_errors( async_fire_time_changed(hass) await hass.async_block_till_done() - assert reolink_connect.get_motion_state_all_ch.call_count == 1 + assert reolink_host.get_motion_state_all_ch.call_count == 1 freezer.tick(timedelta(seconds=POLL_INTERVAL_NO_PUSH)) async_fire_time_changed(hass) await hass.async_block_till_done() # fast polling continues despite errors - assert reolink_connect.get_motion_state_all_ch.call_count == 2 - - reolink_connect.get_motion_state_all_ch.reset_mock(side_effect=True) - reolink_connect.pull_point_request.reset_mock(side_effect=True) + assert reolink_host.get_motion_state_all_ch.call_count == 2 async def test_diagnostics_event_connection( @@ -447,7 +419,7 @@ async def test_diagnostics_event_connection( hass_client: ClientSessionGenerator, hass_client_no_auth: ClientSessionGenerator, freezer: FrozenDateTimeFactory, - reolink_connect: MagicMock, + reolink_host: MagicMock, config_entry: MockConfigEntry, ) -> None: """Test Reolink diagnostics event connection return values.""" @@ -468,7 +440,7 @@ async def test_diagnostics_event_connection( # simulate ONVIF push callback client = await hass_client_no_auth() - reolink_connect.ONVIF_event_callback.return_value = None + reolink_host.ONVIF_event_callback.return_value = None webhook_id = config_entry.runtime_data.host.webhook_id await client.post(f"/api/webhook/{webhook_id}") @@ -476,6 +448,6 @@ async def test_diagnostics_event_connection( assert diag["event connection"] == "ONVIF push" # set TCP push as active - reolink_connect.baichuan.events_active = True + reolink_host.baichuan.events_active = True diag = await get_diagnostics_for_config_entry(hass, hass_client, config_entry) assert diag["event connection"] == "TCP push"