22
33from __future__ import annotations
44
5+ import logging
6+ from unittest .mock import patch
7+
8+ import pytest
9+
10+ from homeassistant .components .coolmaster .const import MAX_RETRIES
511from homeassistant .config_entries import ConfigEntry
612from homeassistant .core import HomeAssistant
13+ from homeassistant .helpers .entity_component import async_update_entity
714
815
916async def test_sensor (
@@ -13,3 +20,119 @@ async def test_sensor(
1320 """Test the Coolmaster sensor."""
1421 assert hass .states .get ("sensor.l1_100_error_code" ).state == "OK"
1522 assert hass .states .get ("sensor.l1_101_error_code" ).state == "Err1"
23+
24+
25+ async def test_retry_with_no_error (
26+ hass : HomeAssistant ,
27+ config_entry_with_errors : ConfigEntry ,
28+ caplog : pytest .LogCaptureFixture ,
29+ ) -> None :
30+ """Test without errors."""
31+
32+ caplog .set_level (logging .DEBUG , logger = "homeassistant.components.coolmaster" )
33+
34+ with patch (
35+ "tests.components.coolmaster.conftest.CoolMasterNetErrorMock.status" ,
36+ wraps = config_entry_with_errors .runtime_data ._coolmaster .status ,
37+ ) as mock_status :
38+ config_entry_with_errors .runtime_data ._coolmaster ._fail_count = 0
39+ await async_update_entity (hass , "sensor.l1_101_error_code" )
40+ await hass .async_block_till_done ()
41+
42+ assert mock_status .call_count == 1
43+ debugs , errors = count_logs (caplog .records )
44+ assert debugs == 0
45+ assert errors == 0
46+
47+
48+ @patch ("homeassistant.components.coolmaster.coordinator.BACKOFF_BASE_DELAY" , new = 0 )
49+ async def test_retry_with_less_than_max_errors (
50+ hass : HomeAssistant ,
51+ config_entry_with_errors : ConfigEntry ,
52+ caplog : pytest .LogCaptureFixture ,
53+ ) -> None :
54+ """Test MAX_RETRIES-1 errors."""
55+
56+ caplog .set_level (logging .DEBUG , logger = "homeassistant.components.coolmaster" )
57+
58+ with patch (
59+ "tests.components.coolmaster.conftest.CoolMasterNetErrorMock.status" ,
60+ wraps = config_entry_with_errors .runtime_data ._coolmaster .status ,
61+ ) as mock_status :
62+ config_entry_with_errors .runtime_data ._coolmaster ._fail_count = MAX_RETRIES - 1
63+ await async_update_entity (hass , "sensor.l1_101_error_code" )
64+ await hass .async_block_till_done ()
65+
66+ assert mock_status .call_count == MAX_RETRIES # The last try succeeds
67+ debugs , errors = count_logs (caplog .records )
68+ assert errors == 0
69+ assert debugs == MAX_RETRIES - 1
70+
71+
72+ @patch ("homeassistant.components.coolmaster.coordinator.BACKOFF_BASE_DELAY" , new = 0 )
73+ async def test_retry_with_more_than_max_errors (
74+ hass : HomeAssistant ,
75+ config_entry_with_errors : ConfigEntry ,
76+ caplog : pytest .LogCaptureFixture ,
77+ ) -> None :
78+ """Test MAX_RETRIES+1 errors."""
79+
80+ caplog .set_level (logging .DEBUG , logger = "homeassistant.components.coolmaster" )
81+
82+ with patch (
83+ "tests.components.coolmaster.conftest.CoolMasterNetErrorMock.status" ,
84+ wraps = config_entry_with_errors .runtime_data ._coolmaster .status ,
85+ ) as mock_status :
86+ config_entry_with_errors .runtime_data ._coolmaster ._fail_count = MAX_RETRIES + 1
87+ await async_update_entity (hass , "sensor.l1_101_error_code" )
88+ await hass .async_block_till_done ()
89+
90+ assert (
91+ mock_status .call_count == MAX_RETRIES
92+ ) # The retries are capped at MAX_RETRIES
93+ debugs , errors = count_logs (caplog .records )
94+ assert errors == 1
95+ assert debugs == MAX_RETRIES - 1
96+
97+
98+ @patch ("homeassistant.components.coolmaster.coordinator.BACKOFF_BASE_DELAY" , new = 0 )
99+ async def test_retry_with_empty_status (
100+ hass : HomeAssistant ,
101+ config_entry_with_empty_status : ConfigEntry ,
102+ caplog : pytest .LogCaptureFixture ,
103+ ) -> None :
104+ """Test empty status response."""
105+
106+ caplog .set_level (logging .DEBUG , logger = "homeassistant.components.coolmaster" )
107+
108+ with patch (
109+ "tests.components.coolmaster.conftest.CoolMasterNetEmptyStatusMock.status" ,
110+ wraps = config_entry_with_empty_status .runtime_data ._coolmaster .status ,
111+ ) as mock_status :
112+ await async_update_entity (hass , "sensor.l1_101_error_code" )
113+ await hass .async_block_till_done ()
114+
115+ assert (
116+ mock_status .call_count == MAX_RETRIES
117+ ) # The retries are capped at MAX_RETRIES
118+ debugs , errors = count_logs (caplog .records )
119+ assert errors == 1
120+ assert debugs == MAX_RETRIES
121+
122+
123+ def count_logs (log_records : list [logging .LogRecord ]) -> tuple [int , int ]:
124+ """Count the number of log records."""
125+ debug_logs = [
126+ rec
127+ for rec in log_records
128+ if rec .levelno == logging .DEBUG
129+ and "Error communicating with coolmaster" in rec .getMessage ()
130+ ]
131+
132+ error_logs = [
133+ rec
134+ for rec in log_records
135+ if rec .levelno == logging .ERROR
136+ and "Error fetching coolmaster data" in rec .getMessage ()
137+ ]
138+ return len (debug_logs ), len (error_logs )
0 commit comments