Repository: home-assistant/core
File: tests/components/duckdns/test_init.py (Python)

Code before:
    """Test setup works if update passes."""
    aioclient_mock.get(
        UPDATE_URL,
        params={"domains": TEST_SUBDOMAIN, "token": TEST_TOKEN},
        text="OK",
    )

    assert aioclient_mock.call_count == 1

    async_fire_time_changed(hass, utcnow() + timedelta(minutes=5))
    await hass.async_block_till_done()
    assert aioclient_mock.call_count == 2


@pytest.mark.parametrize(
    "side_effect",
    [
        [False] * len(BACKOFF_INTERVALS),
        [ClientError] * len(BACKOFF_INTERVALS),
    ],
)
@pytest.mark.freeze_time
async def test_setup_backoff(
    hass: HomeAssistant,
    config_entry: MockConfigEntry,
    side_effect: list[Exception | bool],
) -> None:
    """Test update fails with backoffs and recovers."""

    with patch(
        "homeassistant.components.duckdns.coordinator.update_duckdns",
        side_effect=side_effect,
    ) as client_mock:
        config_entry.add_to_hass(hass)
        await hass.config_entries.async_setup(config_entry.entry_id)
        await hass.async_block_till_done()

        assert config_entry.state is ConfigEntryState.SETUP_RETRY
        assert client_mock.call_count == 1

        tme = utcnow()
        await hass.async_block_till_done()

        _LOGGER.debug("Backoff")
        for idx in range(1, len(BACKOFF_INTERVALS)):
            tme += BACKOFF_INTERVALS[idx]
            async_fire_time_changed(hass, tme)
            await hass.async_block_till_done()

            assert client_mock.call_count == idx + 1


Review comment (suggestion):
```suggestion
    side_effect: Exception | bool,
```

Code after:
    """Test setup works if update passes."""
    aioclient_mock.get(
        UPDATE_URL,
        params={"domains": TEST_SUBDOMAIN, "token": TEST_TOKEN},
        text="OK",
    )

    assert aioclient_mock.call_count == 1

    async_fire_time_changed(hass, utcnow() + timedelta(minutes=5))
    await hass.async_block_till_done()
    assert aioclient_mock.call_count == 2


@pytest.mark.parametrize(
    "side_effect",
    [False, ClientError],
)
@pytest.mark.freeze_time
async def test_setup_backoff(
    hass: HomeAssistant,
    config_entry: MockConfigEntry,
    side_effect: Exception | bool,
) -> None:
    """Test update fails with backoffs and recovers."""

    with patch(
        "homeassistant.components.duckdns.coordinator.update_duckdns",
        side_effect=[side_effect] * len(BACKOFF_INTERVALS),
    ) as client_mock:
        config_entry.add_to_hass(hass)
        await hass.config_entries.async_setup(config_entry.entry_id)
        await hass.async_block_till_done()

        assert config_entry.state is ConfigEntryState.SETUP_RETRY
        assert client_mock.call_count == 1

        tme = utcnow()
        await hass.async_block_till_done()

        _LOGGER.debug("Backoff")
        for idx in range(1, len(BACKOFF_INTERVALS)):
            tme += BACKOFF_INTERVALS[idx]
            async_fire_time_changed(hass, tme)
            await hass.async_block_till_done()

            assert client_mock.call_count == idx + 1

        client_mock.side_effect = None
        async_fire_time_changed(hass, tme)
        await hass.async_block_till_done()