Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Add support for the DataUpdateCoordinator to not automatically update (
  • Loading branch information
rohankapoorcom authored and balloob committed Jul 14, 2020
1 parent 6eca0b2 commit d0e26c3
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 5 deletions.
5 changes: 4 additions & 1 deletion homeassistant/helpers/update_coordinator.py
Expand Up @@ -30,7 +30,7 @@ def __init__(
logger: logging.Logger,
*,
name: str,
update_interval: timedelta,
update_interval: Optional[timedelta] = None,
update_method: Optional[Callable[[], Awaitable]] = None,
request_refresh_debouncer: Optional[Debouncer] = None,
):
Expand Down Expand Up @@ -91,6 +91,9 @@ def async_remove_listener(self, update_callback: CALLBACK_TYPE) -> None:
@callback
def _schedule_refresh(self) -> None:
"""Schedule a refresh."""
if self.update_interval is None:
return

if self._unsub_refresh:
self._unsub_refresh()
self._unsub_refresh = None
Expand Down
67 changes: 63 additions & 4 deletions tests/helpers/test_update_coordinator.py
Expand Up @@ -15,9 +15,8 @@
LOGGER = logging.getLogger(__name__)


@pytest.fixture
def crd(hass):
"""Coordinator mock."""
def get_crd(hass, update_interval):
"""Make coordinator mocks."""
calls = 0

async def refresh():
Expand All @@ -30,11 +29,26 @@ async def refresh():
LOGGER,
name="test",
update_method=refresh,
update_interval=timedelta(seconds=10),
update_interval=update_interval,
)
return crd


DEFAULT_UPDATE_INTERVAL = timedelta(seconds=10)


@pytest.fixture
def crd(hass):
"""Coordinator mock with default update interval."""
return get_crd(hass, DEFAULT_UPDATE_INTERVAL)


@pytest.fixture
def crd_without_update_interval(hass):
"""Coordinator mock that never automatically updates."""
return get_crd(hass, None)


async def test_async_refresh(crd):
"""Test async_refresh for update coordinator."""
assert crd.data is None
Expand Down Expand Up @@ -79,6 +93,20 @@ async def test_request_refresh(crd):
assert crd.last_update_success is True


async def test_request_refresh_no_auto_update(crd_without_update_interval):
"""Test request refresh for update coordinator without automatic update."""
crd = crd_without_update_interval
assert crd.data is None
await crd.async_request_refresh()
assert crd.data == 1
assert crd.last_update_success is True

# Second time we hit the debonuce
await crd.async_request_refresh()
assert crd.data == 1
assert crd.last_update_success is True


@pytest.mark.parametrize(
"err_msg",
[
Expand Down Expand Up @@ -151,6 +179,37 @@ async def test_update_interval(hass, crd):
assert crd.data == 2


async def test_update_interval_not_present(hass, crd_without_update_interval):
"""Test update never happens with no update interval."""
crd = crd_without_update_interval
# Test we don't update without subscriber with no update interval
async_fire_time_changed(hass, utcnow() + DEFAULT_UPDATE_INTERVAL)
await hass.async_block_till_done()
assert crd.data is None

# Add subscriber
update_callback = Mock()
crd.async_add_listener(update_callback)

# Test twice we don't update with subscriber with no update interval
async_fire_time_changed(hass, utcnow() + DEFAULT_UPDATE_INTERVAL)
await hass.async_block_till_done()
assert crd.data is None

async_fire_time_changed(hass, utcnow() + DEFAULT_UPDATE_INTERVAL)
await hass.async_block_till_done()
assert crd.data is None

# Test removing listener
crd.async_remove_listener(update_callback)

async_fire_time_changed(hass, utcnow() + DEFAULT_UPDATE_INTERVAL)
await hass.async_block_till_done()

# Test we stop don't update after we lose last subscriber
assert crd.data is None


async def test_refresh_recover(crd, caplog):
"""Test recovery of freshing data."""
crd.last_update_success = False
Expand Down

0 comments on commit d0e26c3

Please sign in to comment.