Fix imap sensor in case of alternative empty search response (#132081)

pull/132195/head
Jan Bouwhuis 2024-12-03 13:06:54 +01:00 committed by Franck Nijhof
parent c6468aca2b
commit ab5165fdfa
No known key found for this signature in database
GPG Key ID: D62583BA8AB11CA3
3 changed files with 24 additions and 3 deletions

View File

@ -332,7 +332,17 @@ class ImapDataUpdateCoordinator(DataUpdateCoordinator[int | None]):
raise UpdateFailed(
f"Invalid response for search '{self.config_entry.data[CONF_SEARCH]}': {result} / {lines[0]}"
)
if not (count := len(message_ids := lines[0].split())):
# Check we do have returned items.
#
# In rare cases, when no UID's are returned,
# only the status line is returned, and not an empty line.
# See: https://github.com/home-assistant/core/issues/132042
#
# Strictly the RfC notes that 0 or more numbers should be returned
# delimited by a space.
#
# See: https://datatracker.ietf.org/doc/html/rfc3501#section-7.2.5
if len(lines) == 1 or not (count := len(message_ids := lines[0].split())):
self._last_message_uid = None
return 0
last_message_uid = (

View File

@ -141,6 +141,8 @@ TEST_CONTENT_MULTIPART_BASE64_INVALID = (
)
EMPTY_SEARCH_RESPONSE = ("OK", [b"", b"Search completed (0.0001 + 0.000 secs)."])
EMPTY_SEARCH_RESPONSE_ALT = ("OK", [b"Search completed (0.0001 + 0.000 secs)."])
BAD_RESPONSE = ("BAD", [b"", b"Unexpected error"])
TEST_SEARCH_RESPONSE = ("OK", [b"1", b"Search completed (0.0001 + 0.000 secs)."])

View File

@ -20,6 +20,7 @@ from homeassistant.util.dt import utcnow
from .const import (
BAD_RESPONSE,
EMPTY_SEARCH_RESPONSE,
EMPTY_SEARCH_RESPONSE_ALT,
TEST_BADLY_ENCODED_CONTENT,
TEST_FETCH_RESPONSE_BINARY,
TEST_FETCH_RESPONSE_HTML,
@ -517,6 +518,11 @@ async def test_fetch_number_of_messages(
assert state.state == STATE_UNAVAILABLE
@pytest.mark.parametrize(
"empty_search_reponse",
[EMPTY_SEARCH_RESPONSE, EMPTY_SEARCH_RESPONSE_ALT],
ids=["regular_empty_search_response", "alt_empty_search_response"],
)
@pytest.mark.parametrize("imap_search", [TEST_SEARCH_RESPONSE])
@pytest.mark.parametrize(
("imap_fetch", "valid_date"),
@ -525,7 +531,10 @@ async def test_fetch_number_of_messages(
)
@pytest.mark.parametrize("imap_has_capability", [True, False], ids=["push", "poll"])
async def test_reset_last_message(
hass: HomeAssistant, mock_imap_protocol: MagicMock, valid_date: bool
hass: HomeAssistant,
mock_imap_protocol: MagicMock,
valid_date: bool,
empty_search_reponse: tuple[str, list[bytes]],
) -> None:
"""Test receiving a message successfully."""
event = asyncio.Event() # needed for pushed coordinator to make a new loop
@ -580,7 +589,7 @@ async def test_reset_last_message(
)
# Simulate an update where no messages are found (needed for pushed coordinator)
mock_imap_protocol.search.return_value = Response(*EMPTY_SEARCH_RESPONSE)
mock_imap_protocol.search.return_value = Response(*empty_search_reponse)
# Make sure we have an update
async_fire_time_changed(hass, utcnow() + timedelta(seconds=30))