Fix last imap message is not reset on empty search (#93119)

pull/93422/head
Jan Bouwhuis 2023-05-15 21:15:10 +02:00 committed by Franck Nijhof
parent fa6834347a
commit 397864c497
No known key found for this signature in database
GPG Key ID: D62583BA8AB11CA3
2 changed files with 102 additions and 1 deletions

View File

@ -201,7 +201,9 @@ class ImapDataUpdateCoordinator(DataUpdateCoordinator[int | None]):
raise UpdateFailed( raise UpdateFailed(
f"Invalid response for search '{self.config_entry.data[CONF_SEARCH]}': {result} / {lines[0]}" f"Invalid response for search '{self.config_entry.data[CONF_SEARCH]}': {result} / {lines[0]}"
) )
count: int = len(message_ids := lines[0].split()) if not (count := len(message_ids := lines[0].split())):
self._last_message_id = None
return 0
last_message_id = ( last_message_id = (
str(message_ids[-1:][0], encoding=self.config_entry.data[CONF_CHARSET]) str(message_ids[-1:][0], encoding=self.config_entry.data[CONF_CHARSET])
if count if count

View File

@ -15,6 +15,7 @@ from homeassistant.util.dt import utcnow
from .const import ( from .const import (
BAD_RESPONSE, BAD_RESPONSE,
EMPTY_SEARCH_RESPONSE,
TEST_FETCH_RESPONSE_BINARY, TEST_FETCH_RESPONSE_BINARY,
TEST_FETCH_RESPONSE_HTML, TEST_FETCH_RESPONSE_HTML,
TEST_FETCH_RESPONSE_INVALID_DATE, TEST_FETCH_RESPONSE_INVALID_DATE,
@ -347,3 +348,101 @@ async def test_fetch_number_of_messages(
# we should have an entity with an unavailable state # we should have an entity with an unavailable state
assert state is not None assert state is not None
assert state.state == STATE_UNAVAILABLE assert state.state == STATE_UNAVAILABLE
@pytest.mark.parametrize("imap_search", [TEST_SEARCH_RESPONSE])
@pytest.mark.parametrize(
("imap_fetch", "valid_date"),
[(TEST_FETCH_RESPONSE_TEXT_PLAIN, True)],
ids=["plain"],
)
@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
) -> None:
"""Test receiving a message successfully."""
event = asyncio.Event() # needed for pushed coordinator to make a new loop
async def _sleep_till_event() -> None:
"""Simulate imap server waiting for pushes message and keep the push loop going.
Needed for pushed coordinator only.
"""
nonlocal event
await event.wait()
event.clear()
mock_imap_protocol.idle_start.return_value = AsyncMock()()
# Make sure we make another cycle (needed for pushed coordinator)
mock_imap_protocol.idle_start.return_value = AsyncMock()()
# Mock we wait till we push an update (needed for pushed coordinator)
mock_imap_protocol.wait_server_push.side_effect = _sleep_till_event
event_called = async_capture_events(hass, "imap_content")
config_entry = MockConfigEntry(domain=DOMAIN, data=MOCK_CONFIG)
config_entry.add_to_hass(hass)
assert await hass.config_entries.async_setup(config_entry.entry_id)
await hass.async_block_till_done()
# Make sure we have had one update (when polling)
async_fire_time_changed(hass, utcnow() + timedelta(seconds=5))
await hass.async_block_till_done()
state = hass.states.get("sensor.imap_email_email_com")
# We should have received one message
assert state is not None
assert state.state == "1"
# We should have received one event
assert len(event_called) == 1
data: dict[str, Any] = event_called[0].data
assert data["server"] == "imap.server.com"
assert data["username"] == "email@email.com"
assert data["search"] == "UnSeen UnDeleted"
assert data["folder"] == "INBOX"
assert data["sender"] == "john.doe@example.com"
assert data["subject"] == "Test subject"
assert data["text"]
assert (
valid_date
and isinstance(data["date"], datetime)
or not valid_date
and data["date"] is None
)
# Simulate an update where no messages are found (needed for pushed coordinator)
mock_imap_protocol.search.return_value = Response(*EMPTY_SEARCH_RESPONSE)
# Make sure we have an update
async_fire_time_changed(hass, utcnow() + timedelta(seconds=30))
# Awake loop (needed for pushed coordinator)
event.set()
await hass.async_block_till_done()
state = hass.states.get("sensor.imap_email_email_com")
# We should have message
assert state is not None
assert state.state == "0"
# No new events should be called
assert len(event_called) == 1
# Simulate an update where with the original message
mock_imap_protocol.search.return_value = Response(*TEST_SEARCH_RESPONSE)
# Make sure we have an update again with the same UID
async_fire_time_changed(hass, utcnow() + timedelta(seconds=30))
# Awake loop (needed for pushed coordinator)
event.set()
await hass.async_block_till_done()
state = hass.states.get("sensor.imap_email_email_com")
# We should have received one message
assert state is not None
assert state.state == "1"
await hass.async_block_till_done()
await hass.async_block_till_done()
# One new event
assert len(event_called) == 2