Upgrade pytest-aiohttp (#82475)
* Upgrade pytest-aiohttp * Make sure executors, tasks and timers are closed Some test will trigger warnings on garbage collect, these warnings spills over into next test. Some test trigger tasks that raise errors on shutdown, these spill over into next test. This is to mimic older pytest-aiohttp and it's behaviour on test cleanup. Discussions on similar changes for pytest-aiohttp are here: https://github.com/pytest-dev/pytest-asyncio/pull/309 * Replace loop with event_loop * Make sure time is frozen for tests * Make sure the ConditionType is not async /home-assistant/homeassistant/helpers/template.py:2082: RuntimeWarning: coroutine 'AsyncMockMixin._execute_mock_call' was never awaited def wrapper(*args, **kwargs): Enable tracemalloc to get traceback where the object was allocated. See https://docs.pytest.org/en/stable/how-to/capture-warnings.html#resource-warnings for more info. * Increase litejet press tests with a factor 10 The times are simulated anyway, and we can't stop the normal event from occuring. * Use async handlers for aiohttp tests/components/motioneye/test_camera.py::test_get_still_image_from_camera tests/components/motioneye/test_camera.py::test_get_still_image_from_camera tests/components/motioneye/test_camera.py::test_get_stream_from_camera tests/components/motioneye/test_camera.py::test_get_stream_from_camera tests/components/motioneye/test_camera.py::test_camera_option_stream_url_template tests/components/motioneye/test_camera.py::test_camera_option_stream_url_template /Users/joakim/src/hass/home-assistant/venv/lib/python3.9/site-packages/aiohttp/web_urldispatcher.py:189: DeprecationWarning: Bare functions are deprecated, use async ones warnings.warn( * Switch to freezegun in modbus tests The tests allowed clock to tick in between steps * Make sure skybell object are fully mocked Old tests would trigger attempts to post to could services: ``` DEBUG:aioskybell:HTTP post https://cloud.myskybell.com/api/v3/login/ Request with headers: {'content-type': 'application/json', 'accept': '*/*', 'x-skybell-app-id': 'd2b542c7-a7e4-4e1e-b77d-2b76911c7c46', 'x-skybell-client-id': '1f36a3c0-6dee-4997-a6db-4e1c67338e57'} ``` * Fix sorting that broke after rebase
This commit is contained in:
parent
b7652c78ee
commit
c576a68d33
42 changed files with 263 additions and 226 deletions
|
@ -98,9 +98,6 @@ hyperframe>=5.2.0
|
|||
# Ensure we run compatible with musllinux build env
|
||||
numpy==1.23.2
|
||||
|
||||
# pytest_asyncio breaks our test suite. We rely on pytest-aiohttp instead
|
||||
pytest_asyncio==1000000000.0.0
|
||||
|
||||
# Prevent dependency conflicts between sisyphus-control and aioambient
|
||||
# until upper bounds for sisyphus-control have been updated
|
||||
# https://github.com/jkeljo/sisyphus-control/issues/6
|
||||
|
|
|
@ -227,3 +227,4 @@ norecursedirs = [
|
|||
]
|
||||
log_format = "%(asctime)s.%(msecs)03d %(levelname)-8s %(threadName)s %(name)s:%(filename)s:%(lineno)s %(message)s"
|
||||
log_date_format = "%Y-%m-%d %H:%M:%S"
|
||||
asyncio_mode = "auto"
|
||||
|
|
|
@ -16,7 +16,8 @@ mypy==0.991
|
|||
pre-commit==2.20.0
|
||||
pylint==2.15.6
|
||||
pipdeptree==2.3.1
|
||||
pytest-aiohttp==0.3.0
|
||||
pytest-asyncio==0.20.2
|
||||
pytest-aiohttp==1.0.4
|
||||
pytest-cov==3.0.0
|
||||
pytest-freezegun==0.4.2
|
||||
pytest-socket==0.5.1
|
||||
|
|
|
@ -110,9 +110,6 @@ hyperframe>=5.2.0
|
|||
# Ensure we run compatible with musllinux build env
|
||||
numpy==1.23.2
|
||||
|
||||
# pytest_asyncio breaks our test suite. We rely on pytest-aiohttp instead
|
||||
pytest_asyncio==1000000000.0.0
|
||||
|
||||
# Prevent dependency conflicts between sisyphus-control and aioambient
|
||||
# until upper bounds for sisyphus-control have been updated
|
||||
# https://github.com/jkeljo/sisyphus-control/issues/6
|
||||
|
|
|
@ -28,7 +28,7 @@ from tests.common import (
|
|||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_hass(loop):
|
||||
def mock_hass(event_loop):
|
||||
"""Home Assistant mock with minimum amount of data set to make it work with auth."""
|
||||
hass = Mock()
|
||||
hass.config.skip_pip = True
|
||||
|
|
|
@ -160,7 +160,7 @@ def get_test_home_assistant():
|
|||
|
||||
|
||||
# pylint: disable=protected-access
|
||||
async def async_test_home_assistant(loop, load_registries=True):
|
||||
async def async_test_home_assistant(event_loop, load_registries=True):
|
||||
"""Return a Home Assistant object pointing at test config dir."""
|
||||
hass = ha.HomeAssistant()
|
||||
store = auth_store.AuthStore(hass)
|
||||
|
|
|
@ -21,8 +21,9 @@ NPR_NEWS_MP3_URL = "https://pd.npr.org/anon.npr-mp3/npr/news/newscast.mp3"
|
|||
|
||||
|
||||
@pytest.fixture
|
||||
def alexa_client(loop, hass, hass_client):
|
||||
def alexa_client(event_loop, hass, hass_client):
|
||||
"""Initialize a Home Assistant server for testing this module."""
|
||||
loop = event_loop
|
||||
|
||||
@callback
|
||||
def mock_service(call):
|
||||
|
|
|
@ -27,8 +27,9 @@ NPR_NEWS_MP3_URL = "https://pd.npr.org/anon.npr-mp3/npr/news/newscast.mp3"
|
|||
|
||||
|
||||
@pytest.fixture
|
||||
def alexa_client(loop, hass, hass_client):
|
||||
def alexa_client(event_loop, hass, hass_client):
|
||||
"""Initialize a Home Assistant server for testing this module."""
|
||||
loop = event_loop
|
||||
|
||||
@callback
|
||||
def mock_service(call):
|
||||
|
|
|
@ -3,6 +3,6 @@ import pytest
|
|||
|
||||
|
||||
@pytest.fixture
|
||||
def aiohttp_client(loop, aiohttp_client, socket_enabled):
|
||||
def aiohttp_client(event_loop, aiohttp_client, socket_enabled):
|
||||
"""Return aiohttp_client and allow opening sockets."""
|
||||
return aiohttp_client
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
from homeassistant.setup import async_setup_component
|
||||
|
||||
|
||||
async def test_config_setup(hass, loop):
|
||||
async def test_config_setup(hass, event_loop):
|
||||
"""Test it sets up hassbian."""
|
||||
await async_setup_component(hass, "config", {})
|
||||
assert "config" in hass.config.components
|
||||
|
|
|
@ -31,7 +31,7 @@ class MockTransport:
|
|||
|
||||
|
||||
@pytest.fixture
|
||||
def aiohttp_client(loop, aiohttp_client, socket_enabled):
|
||||
def aiohttp_client(event_loop, aiohttp_client, socket_enabled):
|
||||
"""Return aiohttp_client and allow opening sockets."""
|
||||
return aiohttp_client
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@ async def test_events_fired_properly(hass):
|
|||
roku_event_handler = None
|
||||
|
||||
def instantiate(
|
||||
loop,
|
||||
event_loop,
|
||||
handler,
|
||||
roku_usn,
|
||||
host_ip,
|
||||
|
|
|
@ -3,6 +3,7 @@ import copy
|
|||
from datetime import timedelta
|
||||
from unittest.mock import patch
|
||||
|
||||
from freezegun import freeze_time
|
||||
import pytest
|
||||
|
||||
from homeassistant.components.energy import data
|
||||
|
@ -41,6 +42,13 @@ async def setup_integration(recorder_mock):
|
|||
return setup_integration
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
@freeze_time("2022-04-19 07:53:05")
|
||||
def frozen_time():
|
||||
"""Freeze clock for tests."""
|
||||
yield
|
||||
|
||||
|
||||
def get_statistics_for_entity(statistics_results, entity_id):
|
||||
"""Get statistics for a certain entity, or None if there is none."""
|
||||
for statistics_result in statistics_results:
|
||||
|
|
|
@ -38,7 +38,7 @@ class FidoClientMockError(FidoClientMock):
|
|||
raise PyFidoError("Fake Error")
|
||||
|
||||
|
||||
async def test_fido_sensor(loop, hass):
|
||||
async def test_fido_sensor(event_loop, hass):
|
||||
"""Test the Fido number sensor."""
|
||||
with patch("homeassistant.components.fido.sensor.FidoClient", new=FidoClientMock):
|
||||
config = {
|
||||
|
|
|
@ -80,7 +80,7 @@ async def frontend_themes(hass):
|
|||
|
||||
|
||||
@pytest.fixture
|
||||
def aiohttp_client(loop, aiohttp_client, socket_enabled):
|
||||
def aiohttp_client(event_loop, aiohttp_client, socket_enabled):
|
||||
"""Return aiohttp_client and allow opening sockets."""
|
||||
return aiohttp_client
|
||||
|
||||
|
|
|
@ -117,7 +117,7 @@ def mock_dev_track(mock_device_tracker_conf):
|
|||
|
||||
|
||||
@pytest.fixture
|
||||
async def geofency_client(loop, hass, hass_client_no_auth):
|
||||
async def geofency_client(event_loop, hass, hass_client_no_auth):
|
||||
"""Geofency mock client (unauthenticated)."""
|
||||
|
||||
assert await async_setup_component(
|
||||
|
@ -130,7 +130,7 @@ async def geofency_client(loop, hass, hass_client_no_auth):
|
|||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
async def setup_zones(loop, hass):
|
||||
async def setup_zones(event_loop, hass):
|
||||
"""Set up Zone config in HA."""
|
||||
assert await async_setup_component(
|
||||
hass,
|
||||
|
|
|
@ -42,8 +42,9 @@ def auth_header(hass_access_token):
|
|||
|
||||
|
||||
@pytest.fixture
|
||||
def assistant_client(loop, hass, hass_client_no_auth):
|
||||
def assistant_client(event_loop, hass, hass_client_no_auth):
|
||||
"""Create web client for the Google Assistant API."""
|
||||
loop = event_loop
|
||||
loop.run_until_complete(
|
||||
setup.async_setup_component(
|
||||
hass,
|
||||
|
@ -66,8 +67,10 @@ def assistant_client(loop, hass, hass_client_no_auth):
|
|||
|
||||
|
||||
@pytest.fixture
|
||||
def hass_fixture(loop, hass):
|
||||
def hass_fixture(event_loop, hass):
|
||||
"""Set up a Home Assistant instance for these tests."""
|
||||
loop = event_loop
|
||||
|
||||
# We need to do this to get access to homeassistant/turn_(on,off)
|
||||
loop.run_until_complete(setup.async_setup_component(hass, core.DOMAIN, {}))
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ def mock_dev_track(mock_device_tracker_conf):
|
|||
|
||||
|
||||
@pytest.fixture
|
||||
async def gpslogger_client(loop, hass, hass_client_no_auth):
|
||||
async def gpslogger_client(event_loop, hass, hass_client_no_auth):
|
||||
"""Mock client for GPSLogger (unauthenticated)."""
|
||||
|
||||
assert await async_setup_component(hass, DOMAIN, {DOMAIN: {}})
|
||||
|
@ -38,7 +38,7 @@ async def gpslogger_client(loop, hass, hass_client_no_auth):
|
|||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
async def setup_zones(loop, hass):
|
||||
async def setup_zones(event_loop, hass):
|
||||
"""Set up Zone config in HA."""
|
||||
assert await async_setup_component(
|
||||
hass,
|
||||
|
|
|
@ -21,7 +21,7 @@ def iid_storage(hass):
|
|||
|
||||
|
||||
@pytest.fixture()
|
||||
def run_driver(hass, loop, iid_storage):
|
||||
def run_driver(hass, event_loop, iid_storage):
|
||||
"""Return a custom AccessoryDriver instance for HomeKit accessory init.
|
||||
|
||||
This mock does not mock async_stop, so the driver will not be stopped
|
||||
|
@ -41,12 +41,12 @@ def run_driver(hass, loop, iid_storage):
|
|||
bridge_name=BRIDGE_NAME,
|
||||
iid_storage=iid_storage,
|
||||
address="127.0.0.1",
|
||||
loop=loop,
|
||||
loop=event_loop,
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def hk_driver(hass, loop, iid_storage):
|
||||
def hk_driver(hass, event_loop, iid_storage):
|
||||
"""Return a custom AccessoryDriver instance for HomeKit accessory init."""
|
||||
with patch("pyhap.accessory_driver.AsyncZeroconf"), patch(
|
||||
"pyhap.accessory_driver.AccessoryEncoder"
|
||||
|
@ -65,12 +65,12 @@ def hk_driver(hass, loop, iid_storage):
|
|||
bridge_name=BRIDGE_NAME,
|
||||
iid_storage=iid_storage,
|
||||
address="127.0.0.1",
|
||||
loop=loop,
|
||||
loop=event_loop,
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_hap(hass, loop, iid_storage, mock_zeroconf):
|
||||
def mock_hap(hass, event_loop, iid_storage, mock_zeroconf):
|
||||
"""Return a custom AccessoryDriver instance for HomeKit accessory init."""
|
||||
with patch("pyhap.accessory_driver.AsyncZeroconf"), patch(
|
||||
"pyhap.accessory_driver.AccessoryEncoder"
|
||||
|
@ -93,7 +93,7 @@ def mock_hap(hass, loop, iid_storage, mock_zeroconf):
|
|||
bridge_name=BRIDGE_NAME,
|
||||
iid_storage=iid_storage,
|
||||
address="127.0.0.1",
|
||||
loop=loop,
|
||||
loop=event_loop,
|
||||
)
|
||||
|
||||
|
||||
|
|
|
@ -3,6 +3,6 @@ import pytest
|
|||
|
||||
|
||||
@pytest.fixture
|
||||
def aiohttp_client(loop, aiohttp_client, socket_enabled):
|
||||
def aiohttp_client(event_loop, aiohttp_client, socket_enabled):
|
||||
"""Return aiohttp_client and allow opening sockets."""
|
||||
return aiohttp_client
|
||||
|
|
|
@ -49,12 +49,12 @@ async def mock_handler(request):
|
|||
|
||||
|
||||
@pytest.fixture
|
||||
def client(loop, aiohttp_client):
|
||||
def client(event_loop, aiohttp_client):
|
||||
"""Fixture to set up a web.Application."""
|
||||
app = web.Application()
|
||||
setup_cors(app, [TRUSTED_ORIGIN])
|
||||
app["allow_configured_cors"](app.router.add_get("/", mock_handler))
|
||||
return loop.run_until_complete(aiohttp_client(app))
|
||||
return event_loop.run_until_complete(aiohttp_client(app))
|
||||
|
||||
|
||||
async def test_cors_requests(client):
|
||||
|
|
|
@ -15,7 +15,7 @@ from tests.common import assert_setup_component, async_capture_events
|
|||
|
||||
|
||||
@pytest.fixture
|
||||
def aiohttp_unused_port(loop, aiohttp_unused_port, socket_enabled):
|
||||
def aiohttp_unused_port(event_loop, aiohttp_unused_port, socket_enabled):
|
||||
"""Return aiohttp_unused_port and allow opening sockets."""
|
||||
return aiohttp_unused_port
|
||||
|
||||
|
|
|
@ -113,12 +113,12 @@ async def test_held_more_than_short(hass, calls, mock_litejet):
|
|||
{
|
||||
"platform": "litejet",
|
||||
"number": ENTITY_OTHER_SWITCH_NUMBER,
|
||||
"held_more_than": {"milliseconds": "200"},
|
||||
"held_more_than": {"milliseconds": "2000"},
|
||||
},
|
||||
)
|
||||
|
||||
await simulate_press(hass, mock_litejet, ENTITY_OTHER_SWITCH_NUMBER)
|
||||
await simulate_time(hass, mock_litejet, timedelta(seconds=0.1))
|
||||
await simulate_time(hass, mock_litejet, timedelta(seconds=1))
|
||||
await simulate_release(hass, mock_litejet, ENTITY_OTHER_SWITCH_NUMBER)
|
||||
assert len(calls) == 0
|
||||
|
||||
|
@ -130,13 +130,13 @@ async def test_held_more_than_long(hass, calls, mock_litejet):
|
|||
{
|
||||
"platform": "litejet",
|
||||
"number": ENTITY_OTHER_SWITCH_NUMBER,
|
||||
"held_more_than": {"milliseconds": "200"},
|
||||
"held_more_than": {"milliseconds": "2000"},
|
||||
},
|
||||
)
|
||||
|
||||
await simulate_press(hass, mock_litejet, ENTITY_OTHER_SWITCH_NUMBER)
|
||||
assert len(calls) == 0
|
||||
await simulate_time(hass, mock_litejet, timedelta(seconds=0.3))
|
||||
await simulate_time(hass, mock_litejet, timedelta(seconds=3))
|
||||
assert len(calls) == 1
|
||||
assert calls[0].data["id"] == 0
|
||||
await simulate_release(hass, mock_litejet, ENTITY_OTHER_SWITCH_NUMBER)
|
||||
|
@ -150,12 +150,12 @@ async def test_held_less_than_short(hass, calls, mock_litejet):
|
|||
{
|
||||
"platform": "litejet",
|
||||
"number": ENTITY_OTHER_SWITCH_NUMBER,
|
||||
"held_less_than": {"milliseconds": "200"},
|
||||
"held_less_than": {"milliseconds": "2000"},
|
||||
},
|
||||
)
|
||||
|
||||
await simulate_press(hass, mock_litejet, ENTITY_OTHER_SWITCH_NUMBER)
|
||||
await simulate_time(hass, mock_litejet, timedelta(seconds=0.1))
|
||||
await simulate_time(hass, mock_litejet, timedelta(seconds=1))
|
||||
assert len(calls) == 0
|
||||
await simulate_release(hass, mock_litejet, ENTITY_OTHER_SWITCH_NUMBER)
|
||||
assert len(calls) == 1
|
||||
|
@ -169,13 +169,13 @@ async def test_held_less_than_long(hass, calls, mock_litejet):
|
|||
{
|
||||
"platform": "litejet",
|
||||
"number": ENTITY_OTHER_SWITCH_NUMBER,
|
||||
"held_less_than": {"milliseconds": "200"},
|
||||
"held_less_than": {"milliseconds": "2000"},
|
||||
},
|
||||
)
|
||||
|
||||
await simulate_press(hass, mock_litejet, ENTITY_OTHER_SWITCH_NUMBER)
|
||||
assert len(calls) == 0
|
||||
await simulate_time(hass, mock_litejet, timedelta(seconds=0.3))
|
||||
await simulate_time(hass, mock_litejet, timedelta(seconds=3))
|
||||
assert len(calls) == 0
|
||||
await simulate_release(hass, mock_litejet, ENTITY_OTHER_SWITCH_NUMBER)
|
||||
assert len(calls) == 0
|
||||
|
@ -188,13 +188,13 @@ async def test_held_in_range_short(hass, calls, mock_litejet):
|
|||
{
|
||||
"platform": "litejet",
|
||||
"number": ENTITY_OTHER_SWITCH_NUMBER,
|
||||
"held_more_than": {"milliseconds": "100"},
|
||||
"held_less_than": {"milliseconds": "300"},
|
||||
"held_more_than": {"milliseconds": "1000"},
|
||||
"held_less_than": {"milliseconds": "3000"},
|
||||
},
|
||||
)
|
||||
|
||||
await simulate_press(hass, mock_litejet, ENTITY_OTHER_SWITCH_NUMBER)
|
||||
await simulate_time(hass, mock_litejet, timedelta(seconds=0.05))
|
||||
await simulate_time(hass, mock_litejet, timedelta(seconds=0.5))
|
||||
await simulate_release(hass, mock_litejet, ENTITY_OTHER_SWITCH_NUMBER)
|
||||
assert len(calls) == 0
|
||||
|
||||
|
@ -206,14 +206,14 @@ async def test_held_in_range_just_right(hass, calls, mock_litejet):
|
|||
{
|
||||
"platform": "litejet",
|
||||
"number": ENTITY_OTHER_SWITCH_NUMBER,
|
||||
"held_more_than": {"milliseconds": "100"},
|
||||
"held_less_than": {"milliseconds": "300"},
|
||||
"held_more_than": {"milliseconds": "1000"},
|
||||
"held_less_than": {"milliseconds": "3000"},
|
||||
},
|
||||
)
|
||||
|
||||
await simulate_press(hass, mock_litejet, ENTITY_OTHER_SWITCH_NUMBER)
|
||||
assert len(calls) == 0
|
||||
await simulate_time(hass, mock_litejet, timedelta(seconds=0.2))
|
||||
await simulate_time(hass, mock_litejet, timedelta(seconds=2))
|
||||
assert len(calls) == 0
|
||||
await simulate_release(hass, mock_litejet, ENTITY_OTHER_SWITCH_NUMBER)
|
||||
assert len(calls) == 1
|
||||
|
@ -227,14 +227,14 @@ async def test_held_in_range_long(hass, calls, mock_litejet):
|
|||
{
|
||||
"platform": "litejet",
|
||||
"number": ENTITY_OTHER_SWITCH_NUMBER,
|
||||
"held_more_than": {"milliseconds": "100"},
|
||||
"held_less_than": {"milliseconds": "300"},
|
||||
"held_more_than": {"milliseconds": "1000"},
|
||||
"held_less_than": {"milliseconds": "3000"},
|
||||
},
|
||||
)
|
||||
|
||||
await simulate_press(hass, mock_litejet, ENTITY_OTHER_SWITCH_NUMBER)
|
||||
assert len(calls) == 0
|
||||
await simulate_time(hass, mock_litejet, timedelta(seconds=0.4))
|
||||
await simulate_time(hass, mock_litejet, timedelta(seconds=4))
|
||||
assert len(calls) == 0
|
||||
await simulate_release(hass, mock_litejet, ENTITY_OTHER_SWITCH_NUMBER)
|
||||
assert len(calls) == 0
|
||||
|
@ -247,8 +247,8 @@ async def test_reload(hass, calls, mock_litejet):
|
|||
{
|
||||
"platform": "litejet",
|
||||
"number": ENTITY_OTHER_SWITCH_NUMBER,
|
||||
"held_more_than": {"milliseconds": "100"},
|
||||
"held_less_than": {"milliseconds": "300"},
|
||||
"held_more_than": {"milliseconds": "1000"},
|
||||
"held_less_than": {"milliseconds": "3000"},
|
||||
},
|
||||
)
|
||||
|
||||
|
@ -260,7 +260,7 @@ async def test_reload(hass, calls, mock_litejet):
|
|||
"trigger": {
|
||||
"platform": "litejet",
|
||||
"number": ENTITY_OTHER_SWITCH_NUMBER,
|
||||
"held_more_than": {"milliseconds": "1000"},
|
||||
"held_more_than": {"milliseconds": "10000"},
|
||||
},
|
||||
"action": {"service": "test.automation"},
|
||||
}
|
||||
|
@ -275,7 +275,7 @@ async def test_reload(hass, calls, mock_litejet):
|
|||
|
||||
await simulate_press(hass, mock_litejet, ENTITY_OTHER_SWITCH_NUMBER)
|
||||
assert len(calls) == 0
|
||||
await simulate_time(hass, mock_litejet, timedelta(seconds=0.5))
|
||||
await simulate_time(hass, mock_litejet, timedelta(seconds=5))
|
||||
assert len(calls) == 0
|
||||
await simulate_time(hass, mock_litejet, timedelta(seconds=1.25))
|
||||
await simulate_time(hass, mock_litejet, timedelta(seconds=12.5))
|
||||
assert len(calls) == 1
|
||||
|
|
|
@ -21,7 +21,7 @@ def mock_dev_track(mock_device_tracker_conf):
|
|||
|
||||
|
||||
@pytest.fixture
|
||||
async def locative_client(loop, hass, hass_client):
|
||||
async def locative_client(event_loop, hass, hass_client):
|
||||
"""Locative mock client."""
|
||||
assert await async_setup_component(hass, DOMAIN, {DOMAIN: {}})
|
||||
await hass.async_block_till_done()
|
||||
|
|
|
@ -15,8 +15,9 @@ from homeassistant.setup import async_setup_component
|
|||
|
||||
|
||||
@pytest.fixture
|
||||
def meraki_client(loop, hass, hass_client):
|
||||
def meraki_client(event_loop, hass, hass_client):
|
||||
"""Meraki mock client."""
|
||||
loop = event_loop
|
||||
assert loop.run_until_complete(
|
||||
async_setup_component(
|
||||
hass,
|
||||
|
|
|
@ -16,6 +16,7 @@ from datetime import timedelta
|
|||
import logging
|
||||
from unittest import mock
|
||||
|
||||
from freezegun.api import FrozenDateTimeFactory
|
||||
from pymodbus.exceptions import ModbusException
|
||||
from pymodbus.pdu import ExceptionResponse, IllegalFunctionRequest
|
||||
import pytest
|
||||
|
@ -542,6 +543,7 @@ async def mock_modbus_read_pymodbus_fixture(
|
|||
do_exception,
|
||||
caplog,
|
||||
mock_pymodbus,
|
||||
freezer: FrozenDateTimeFactory,
|
||||
):
|
||||
"""Load integration modbus using mocked pymodbus."""
|
||||
caplog.clear()
|
||||
|
@ -573,16 +575,13 @@ async def mock_modbus_read_pymodbus_fixture(
|
|||
}
|
||||
],
|
||||
}
|
||||
now = dt_util.utcnow()
|
||||
with mock.patch("homeassistant.helpers.event.dt_util.utcnow", return_value=now):
|
||||
assert await async_setup_component(hass, DOMAIN, config) is True
|
||||
await hass.async_block_till_done()
|
||||
assert await async_setup_component(hass, DOMAIN, config) is True
|
||||
await hass.async_block_till_done()
|
||||
assert DOMAIN in hass.config.components
|
||||
assert caplog.text == ""
|
||||
now = now + timedelta(seconds=DEFAULT_SCAN_INTERVAL + 60)
|
||||
with mock.patch("homeassistant.helpers.event.dt_util.utcnow", return_value=now):
|
||||
async_fire_time_changed(hass, now)
|
||||
await hass.async_block_till_done()
|
||||
freezer.tick(timedelta(seconds=DEFAULT_SCAN_INTERVAL + 60))
|
||||
async_fire_time_changed(hass)
|
||||
await hass.async_block_till_done()
|
||||
yield mock_pymodbus
|
||||
|
||||
|
||||
|
@ -690,7 +689,7 @@ async def test_pymodbus_connect_fail(hass, caplog, mock_pymodbus):
|
|||
assert ExceptionMessage in caplog.text
|
||||
|
||||
|
||||
async def test_delay(hass, mock_pymodbus):
|
||||
async def test_delay(hass, mock_pymodbus, freezer: FrozenDateTimeFactory):
|
||||
"""Run test for startup delay."""
|
||||
|
||||
# the purpose of this test is to test startup delay
|
||||
|
@ -720,11 +719,8 @@ async def test_delay(hass, mock_pymodbus):
|
|||
}
|
||||
mock_pymodbus.read_coils.return_value = ReadResult([0x01])
|
||||
start_time = dt_util.utcnow()
|
||||
with mock.patch(
|
||||
"homeassistant.helpers.event.dt_util.utcnow", return_value=start_time
|
||||
):
|
||||
assert await async_setup_component(hass, DOMAIN, config) is True
|
||||
await hass.async_block_till_done()
|
||||
assert await async_setup_component(hass, DOMAIN, config) is True
|
||||
await hass.async_block_till_done()
|
||||
assert hass.states.get(entity_id).state == STATE_UNKNOWN
|
||||
|
||||
time_sensor_active = start_time + timedelta(seconds=2)
|
||||
|
@ -736,19 +732,15 @@ async def test_delay(hass, mock_pymodbus):
|
|||
# This test assumed listeners are always fired at 0
|
||||
# microseconds which is impossible in production so
|
||||
# we use 999999 microseconds to simulate the real world.
|
||||
now += timedelta(seconds=1, microseconds=999999)
|
||||
with mock.patch(
|
||||
"homeassistant.helpers.event.dt_util.utcnow",
|
||||
return_value=now,
|
||||
autospec=True,
|
||||
):
|
||||
async_fire_time_changed(hass, now)
|
||||
await hass.async_block_till_done()
|
||||
if now > time_sensor_active:
|
||||
if now <= time_after_delay:
|
||||
assert hass.states.get(entity_id).state == STATE_UNAVAILABLE
|
||||
elif now > time_after_scan:
|
||||
assert hass.states.get(entity_id).state == STATE_ON
|
||||
freezer.tick(timedelta(seconds=1, microseconds=999999))
|
||||
now = dt_util.utcnow()
|
||||
async_fire_time_changed(hass, now)
|
||||
await hass.async_block_till_done()
|
||||
if now > time_sensor_active:
|
||||
if now <= time_after_delay:
|
||||
assert hass.states.get(entity_id).state == STATE_UNAVAILABLE
|
||||
elif now > time_after_scan:
|
||||
assert hass.states.get(entity_id).state == STATE_ON
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
|
@ -853,19 +845,20 @@ async def test_write_no_client(hass, mock_modbus):
|
|||
|
||||
|
||||
@pytest.mark.parametrize("do_config", [{}])
|
||||
async def test_integration_reload(hass, caplog, mock_modbus):
|
||||
async def test_integration_reload(
|
||||
hass, caplog, mock_modbus, freezer: FrozenDateTimeFactory
|
||||
):
|
||||
"""Run test for integration reload."""
|
||||
|
||||
caplog.set_level(logging.INFO)
|
||||
caplog.clear()
|
||||
|
||||
yaml_path = get_fixture_path("configuration.yaml", "modbus")
|
||||
now = dt_util.utcnow()
|
||||
with mock.patch.object(hass_config, "YAML_CONFIG_FILE", yaml_path):
|
||||
await hass.services.async_call(DOMAIN, SERVICE_RELOAD, blocking=True)
|
||||
await hass.async_block_till_done()
|
||||
for i in range(4):
|
||||
now = now + timedelta(seconds=1)
|
||||
async_fire_time_changed(hass, now)
|
||||
freezer.tick(timedelta(seconds=1))
|
||||
async_fire_time_changed(hass)
|
||||
await hass.async_block_till_done()
|
||||
assert "Modbus reloading" in caplog.text
|
||||
|
|
|
@ -62,7 +62,7 @@ from tests.common import async_fire_time_changed
|
|||
|
||||
|
||||
@pytest.fixture
|
||||
def aiohttp_server(loop, aiohttp_server, socket_enabled):
|
||||
def aiohttp_server(event_loop, aiohttp_server, socket_enabled):
|
||||
"""Return aiohttp_server and allow opening sockets."""
|
||||
return aiohttp_server
|
||||
|
||||
|
@ -218,7 +218,7 @@ async def test_get_still_image_from_camera(
|
|||
) -> None:
|
||||
"""Test getting a still image."""
|
||||
|
||||
image_handler = Mock(return_value="")
|
||||
image_handler = AsyncMock(return_value="")
|
||||
|
||||
app = web.Application()
|
||||
app.add_routes(
|
||||
|
@ -258,7 +258,7 @@ async def test_get_still_image_from_camera(
|
|||
async def test_get_stream_from_camera(aiohttp_server: Any, hass: HomeAssistant) -> None:
|
||||
"""Test getting a stream."""
|
||||
|
||||
stream_handler = Mock(return_value="")
|
||||
stream_handler = AsyncMock(return_value="")
|
||||
app = web.Application()
|
||||
app.add_routes([web.get("/", stream_handler)])
|
||||
stream_server = await aiohttp_server(app)
|
||||
|
@ -341,7 +341,7 @@ async def test_camera_option_stream_url_template(
|
|||
"""Verify camera with a stream URL template option."""
|
||||
client = create_mock_motioneye_client()
|
||||
|
||||
stream_handler = Mock(return_value="")
|
||||
stream_handler = AsyncMock(return_value="")
|
||||
app = web.Application()
|
||||
app.add_routes([web.get(f"/{TEST_CAMERA_NAME}/{TEST_CAMERA_ID}", stream_handler)])
|
||||
stream_server = await aiohttp_server(app)
|
||||
|
@ -371,7 +371,7 @@ async def test_camera_option_stream_url_template(
|
|||
# the expected exception, then verify the right handler was called.
|
||||
with pytest.raises(HTTPBadGateway):
|
||||
await async_get_mjpeg_stream(hass, Mock(), TEST_CAMERA_ENTITY_ID)
|
||||
assert stream_handler.called
|
||||
assert AsyncMock.called
|
||||
assert not client.get_camera_stream_url.called
|
||||
|
||||
|
||||
|
|
|
@ -82,7 +82,7 @@ class FakeAuth(AbstractAuth):
|
|||
|
||||
|
||||
@pytest.fixture
|
||||
def aiohttp_client(loop, aiohttp_client, socket_enabled):
|
||||
def aiohttp_client(event_loop, aiohttp_client, socket_enabled):
|
||||
"""Return aiohttp_client and allow opening sockets."""
|
||||
return aiohttp_client
|
||||
|
||||
|
|
|
@ -53,7 +53,9 @@ async def test_auth(hass, aioclient_mock):
|
|||
# Prepare to capture credentials for Subscriber
|
||||
captured_creds = None
|
||||
|
||||
async def async_new_subscriber(creds, subscription_name, loop, async_callback):
|
||||
async def async_new_subscriber(
|
||||
creds, subscription_name, event_loop, async_callback
|
||||
):
|
||||
"""Capture credentials for tests."""
|
||||
nonlocal captured_creds
|
||||
captured_creds = creds
|
||||
|
@ -112,7 +114,9 @@ async def test_auth_expired_token(hass, aioclient_mock):
|
|||
# Prepare to capture credentials for Subscriber
|
||||
captured_creds = None
|
||||
|
||||
async def async_new_subscriber(creds, subscription_name, loop, async_callback):
|
||||
async def async_new_subscriber(
|
||||
creds, subscription_name, event_loop, async_callback
|
||||
):
|
||||
"""Capture credentials for tests."""
|
||||
nonlocal captured_creds
|
||||
captured_creds = creds
|
||||
|
|
|
@ -110,7 +110,7 @@ def test_validate_or_move_away_sqlite_database(hass, tmpdir, caplog):
|
|||
|
||||
|
||||
async def test_last_run_was_recently_clean(
|
||||
loop, async_setup_recorder_instance: SetupRecorderInstanceT, tmp_path
|
||||
event_loop, async_setup_recorder_instance: SetupRecorderInstanceT, tmp_path
|
||||
):
|
||||
"""Test we can check if the last recorder run was recently clean."""
|
||||
config = {
|
||||
|
|
|
@ -8,8 +8,9 @@ from homeassistant.setup import async_setup_component
|
|||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_http_client(loop, hass, hass_client):
|
||||
def mock_http_client(event_loop, hass, hass_client):
|
||||
"""Set up test fixture."""
|
||||
loop = event_loop
|
||||
config = {
|
||||
"rss_feed_template": {
|
||||
"testfeed": {
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
"""Tests for the SkyBell integration."""
|
||||
|
||||
from unittest.mock import AsyncMock, patch
|
||||
|
||||
from homeassistant.const import CONF_EMAIL, CONF_PASSWORD
|
||||
|
||||
USERNAME = "user"
|
||||
|
@ -12,19 +10,3 @@ CONF_CONFIG_FLOW = {
|
|||
CONF_EMAIL: USERNAME,
|
||||
CONF_PASSWORD: PASSWORD,
|
||||
}
|
||||
|
||||
|
||||
def _patch_skybell_devices() -> None:
|
||||
mocked_skybell = AsyncMock()
|
||||
mocked_skybell.user_id = USER_ID
|
||||
return patch(
|
||||
"homeassistant.components.skybell.config_flow.Skybell.async_get_devices",
|
||||
return_value=[mocked_skybell],
|
||||
)
|
||||
|
||||
|
||||
def _patch_skybell() -> None:
|
||||
return patch(
|
||||
"homeassistant.components.skybell.config_flow.Skybell.async_send_request",
|
||||
return_value={"id": USER_ID},
|
||||
)
|
||||
|
|
25
tests/components/skybell/conftest.py
Normal file
25
tests/components/skybell/conftest.py
Normal file
|
@ -0,0 +1,25 @@
|
|||
"""Test setup for the SkyBell integration."""
|
||||
|
||||
from unittest.mock import AsyncMock, patch
|
||||
|
||||
from aioskybell import Skybell, SkybellDevice
|
||||
from pytest import fixture
|
||||
|
||||
from . import USER_ID
|
||||
|
||||
|
||||
@fixture(autouse=True)
|
||||
def skybell_mock():
|
||||
"""Fixture for our skybell tests."""
|
||||
mocked_skybell_device = AsyncMock(spec=SkybellDevice)
|
||||
|
||||
mocked_skybell = AsyncMock(spec=Skybell)
|
||||
mocked_skybell.async_get_devices.return_value = [mocked_skybell_device]
|
||||
mocked_skybell.async_send_request.return_value = {"id": USER_ID}
|
||||
mocked_skybell.user_id = USER_ID
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.skybell.config_flow.Skybell",
|
||||
return_value=mocked_skybell,
|
||||
), patch("homeassistant.components.skybell.Skybell", return_value=mocked_skybell):
|
||||
yield mocked_skybell
|
|
@ -2,6 +2,7 @@
|
|||
from unittest.mock import patch
|
||||
|
||||
from aioskybell import exceptions
|
||||
from pytest import fixture
|
||||
|
||||
from homeassistant import config_entries
|
||||
from homeassistant.components.skybell.const import DOMAIN
|
||||
|
@ -10,43 +11,39 @@ from homeassistant.const import CONF_PASSWORD, CONF_SOURCE
|
|||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.data_entry_flow import FlowResultType
|
||||
|
||||
from . import (
|
||||
CONF_CONFIG_FLOW,
|
||||
PASSWORD,
|
||||
USER_ID,
|
||||
_patch_skybell,
|
||||
_patch_skybell_devices,
|
||||
)
|
||||
from . import CONF_CONFIG_FLOW, PASSWORD, USER_ID
|
||||
|
||||
from tests.common import MockConfigEntry
|
||||
|
||||
|
||||
def _patch_setup_entry() -> None:
|
||||
return patch(
|
||||
@fixture(autouse=True)
|
||||
def setup_entry() -> None:
|
||||
"""Make sure component doesn't initialize."""
|
||||
with patch(
|
||||
"homeassistant.components.skybell.async_setup_entry",
|
||||
return_value=True,
|
||||
)
|
||||
):
|
||||
yield
|
||||
|
||||
|
||||
async def test_flow_user(hass: HomeAssistant) -> None:
|
||||
"""Test that the user step works."""
|
||||
with _patch_skybell(), _patch_skybell_devices(), _patch_setup_entry():
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN, context={"source": SOURCE_USER}
|
||||
)
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN, context={"source": SOURCE_USER}
|
||||
)
|
||||
|
||||
assert result["type"] == FlowResultType.FORM
|
||||
assert result["step_id"] == "user"
|
||||
assert result["type"] == FlowResultType.FORM
|
||||
assert result["step_id"] == "user"
|
||||
|
||||
result = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"],
|
||||
user_input=CONF_CONFIG_FLOW,
|
||||
)
|
||||
result = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"],
|
||||
user_input=CONF_CONFIG_FLOW,
|
||||
)
|
||||
|
||||
assert result["type"] == FlowResultType.CREATE_ENTRY
|
||||
assert result["title"] == "user"
|
||||
assert result["data"] == CONF_CONFIG_FLOW
|
||||
assert result["result"].unique_id == USER_ID
|
||||
assert result["type"] == FlowResultType.CREATE_ENTRY
|
||||
assert result["title"] == "user"
|
||||
assert result["data"] == CONF_CONFIG_FLOW
|
||||
assert result["result"].unique_id == USER_ID
|
||||
|
||||
|
||||
async def test_flow_user_already_configured(hass: HomeAssistant) -> None:
|
||||
|
@ -57,50 +54,48 @@ async def test_flow_user_already_configured(hass: HomeAssistant) -> None:
|
|||
)
|
||||
|
||||
entry.add_to_hass(hass)
|
||||
with _patch_skybell(), _patch_skybell_devices():
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN, context={"source": SOURCE_USER}, data=CONF_CONFIG_FLOW
|
||||
)
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN, context={"source": SOURCE_USER}, data=CONF_CONFIG_FLOW
|
||||
)
|
||||
|
||||
assert result["type"] == FlowResultType.ABORT
|
||||
assert result["reason"] == "already_configured"
|
||||
|
||||
|
||||
async def test_flow_user_cannot_connect(hass: HomeAssistant) -> None:
|
||||
async def test_flow_user_cannot_connect(hass: HomeAssistant, skybell_mock) -> None:
|
||||
"""Test user initialized flow with unreachable server."""
|
||||
with _patch_skybell() as skybell_mock:
|
||||
skybell_mock.side_effect = exceptions.SkybellException(hass)
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN, context={"source": SOURCE_USER}, data=CONF_CONFIG_FLOW
|
||||
)
|
||||
assert result["type"] == FlowResultType.FORM
|
||||
assert result["step_id"] == "user"
|
||||
assert result["errors"] == {"base": "cannot_connect"}
|
||||
skybell_mock.async_initialize.side_effect = exceptions.SkybellException(hass)
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN, context={"source": SOURCE_USER}, data=CONF_CONFIG_FLOW
|
||||
)
|
||||
assert result["type"] == FlowResultType.FORM
|
||||
assert result["step_id"] == "user"
|
||||
assert result["errors"] == {"base": "cannot_connect"}
|
||||
|
||||
|
||||
async def test_invalid_credentials(hass: HomeAssistant) -> None:
|
||||
async def test_invalid_credentials(hass: HomeAssistant, skybell_mock) -> None:
|
||||
"""Test that invalid credentials throws an error."""
|
||||
with patch("homeassistant.components.skybell.Skybell.async_login") as skybell_mock:
|
||||
skybell_mock.side_effect = exceptions.SkybellAuthenticationException(hass)
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN, context={"source": SOURCE_USER}, data=CONF_CONFIG_FLOW
|
||||
)
|
||||
skybell_mock.async_initialize.side_effect = (
|
||||
exceptions.SkybellAuthenticationException(hass)
|
||||
)
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN, context={"source": SOURCE_USER}, data=CONF_CONFIG_FLOW
|
||||
)
|
||||
|
||||
assert result["type"] == FlowResultType.FORM
|
||||
assert result["step_id"] == "user"
|
||||
assert result["errors"] == {"base": "invalid_auth"}
|
||||
assert result["type"] == FlowResultType.FORM
|
||||
assert result["step_id"] == "user"
|
||||
assert result["errors"] == {"base": "invalid_auth"}
|
||||
|
||||
|
||||
async def test_flow_user_unknown_error(hass: HomeAssistant) -> None:
|
||||
async def test_flow_user_unknown_error(hass: HomeAssistant, skybell_mock) -> None:
|
||||
"""Test user initialized flow with unreachable server."""
|
||||
with _patch_skybell_devices() as skybell_mock:
|
||||
skybell_mock.side_effect = Exception
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN, context={"source": SOURCE_USER}, data=CONF_CONFIG_FLOW
|
||||
)
|
||||
assert result["type"] == FlowResultType.FORM
|
||||
assert result["step_id"] == "user"
|
||||
assert result["errors"] == {"base": "unknown"}
|
||||
skybell_mock.async_initialize.side_effect = Exception
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN, context={"source": SOURCE_USER}, data=CONF_CONFIG_FLOW
|
||||
)
|
||||
assert result["type"] == FlowResultType.FORM
|
||||
assert result["step_id"] == "user"
|
||||
assert result["errors"] == {"base": "unknown"}
|
||||
|
||||
|
||||
async def test_step_reauth(hass: HomeAssistant) -> None:
|
||||
|
@ -121,17 +116,15 @@ async def test_step_reauth(hass: HomeAssistant) -> None:
|
|||
assert result["type"] == FlowResultType.FORM
|
||||
assert result["step_id"] == "reauth_confirm"
|
||||
|
||||
with _patch_skybell(), _patch_skybell_devices(), _patch_setup_entry():
|
||||
|
||||
result = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"],
|
||||
user_input={CONF_PASSWORD: PASSWORD},
|
||||
)
|
||||
assert result["type"] == FlowResultType.ABORT
|
||||
assert result["reason"] == "reauth_successful"
|
||||
result = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"],
|
||||
user_input={CONF_PASSWORD: PASSWORD},
|
||||
)
|
||||
assert result["type"] == FlowResultType.ABORT
|
||||
assert result["reason"] == "reauth_successful"
|
||||
|
||||
|
||||
async def test_step_reauth_failed(hass: HomeAssistant) -> None:
|
||||
async def test_step_reauth_failed(hass: HomeAssistant, skybell_mock) -> None:
|
||||
"""Test the reauth flow fails and recovers."""
|
||||
entry = MockConfigEntry(domain=DOMAIN, unique_id=USER_ID, data=CONF_CONFIG_FLOW)
|
||||
entry.add_to_hass(hass)
|
||||
|
@ -149,21 +142,22 @@ async def test_step_reauth_failed(hass: HomeAssistant) -> None:
|
|||
assert result["type"] == FlowResultType.FORM
|
||||
assert result["step_id"] == "reauth_confirm"
|
||||
|
||||
with patch("homeassistant.components.skybell.Skybell.async_login") as skybell_mock:
|
||||
skybell_mock.side_effect = exceptions.SkybellAuthenticationException(hass)
|
||||
result = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"],
|
||||
user_input={CONF_PASSWORD: PASSWORD},
|
||||
)
|
||||
skybell_mock.async_initialize.side_effect = (
|
||||
exceptions.SkybellAuthenticationException(hass)
|
||||
)
|
||||
result = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"],
|
||||
user_input={CONF_PASSWORD: PASSWORD},
|
||||
)
|
||||
|
||||
assert result["type"] == FlowResultType.FORM
|
||||
assert result["errors"] == {"base": "invalid_auth"}
|
||||
assert result["type"] == FlowResultType.FORM
|
||||
assert result["errors"] == {"base": "invalid_auth"}
|
||||
|
||||
with _patch_skybell(), _patch_skybell_devices(), _patch_setup_entry():
|
||||
skybell_mock.async_initialize.side_effect = None
|
||||
|
||||
result = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"],
|
||||
user_input={CONF_PASSWORD: PASSWORD},
|
||||
)
|
||||
assert result["type"] == FlowResultType.ABORT
|
||||
assert result["reason"] == "reauth_successful"
|
||||
result = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"],
|
||||
user_input={CONF_PASSWORD: PASSWORD},
|
||||
)
|
||||
assert result["type"] == FlowResultType.ABORT
|
||||
assert result["reason"] == "reauth_successful"
|
||||
|
|
|
@ -24,7 +24,7 @@ def mock_dev_track(mock_device_tracker_conf):
|
|||
|
||||
|
||||
@pytest.fixture(name="client")
|
||||
async def traccar_client(loop, hass, hass_client_no_auth):
|
||||
async def traccar_client(event_loop, hass, hass_client_no_auth):
|
||||
"""Mock client for Traccar (unauthenticated)."""
|
||||
|
||||
assert await async_setup_component(hass, DOMAIN, {DOMAIN: {}})
|
||||
|
@ -36,7 +36,7 @@ async def traccar_client(loop, hass, hass_client_no_auth):
|
|||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
async def setup_zones(loop, hass):
|
||||
async def setup_zones(event_loop, hass):
|
||||
"""Set up Zone config in HA."""
|
||||
assert await async_setup_component(
|
||||
hass,
|
||||
|
|
|
@ -5,6 +5,7 @@ import asyncio
|
|||
from collections.abc import AsyncGenerator, Callable, Generator
|
||||
from contextlib import asynccontextmanager
|
||||
import functools
|
||||
import gc
|
||||
import itertools
|
||||
from json import JSONDecoder, loads
|
||||
import logging
|
||||
|
@ -13,6 +14,7 @@ import ssl
|
|||
import threading
|
||||
from typing import Any
|
||||
from unittest.mock import AsyncMock, MagicMock, Mock, patch
|
||||
import warnings
|
||||
|
||||
from aiohttp import client
|
||||
from aiohttp.pytest_plugin import AiohttpClient
|
||||
|
@ -188,12 +190,14 @@ util.get_local_ip = lambda: "127.0.0.1"
|
|||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def verify_cleanup():
|
||||
def verify_cleanup(event_loop: asyncio.AbstractEventLoop):
|
||||
"""Verify that the test has cleaned up resources correctly."""
|
||||
threads_before = frozenset(threading.enumerate())
|
||||
|
||||
tasks_before = asyncio.all_tasks(event_loop)
|
||||
yield
|
||||
|
||||
event_loop.run_until_complete(event_loop.shutdown_default_executor())
|
||||
|
||||
if len(INSTANCES) >= 2:
|
||||
count = len(INSTANCES)
|
||||
for inst in INSTANCES:
|
||||
|
@ -204,6 +208,26 @@ def verify_cleanup():
|
|||
for thread in threads:
|
||||
assert isinstance(thread, threading._DummyThread)
|
||||
|
||||
# Warn and clean-up lingering tasks and timers
|
||||
# before moving on to the next test.
|
||||
tasks = asyncio.all_tasks(event_loop) - tasks_before
|
||||
for task in tasks:
|
||||
warnings.warn(f"Linger task after test {task}")
|
||||
task.cancel()
|
||||
if tasks:
|
||||
event_loop.run_until_complete(asyncio.wait(tasks))
|
||||
|
||||
for handle in event_loop._scheduled: # pylint: disable=protected-access
|
||||
if not handle.cancelled():
|
||||
warnings.warn(f"Lingering timer after test {handle}")
|
||||
handle.cancel()
|
||||
|
||||
# Make sure garbage collect run in same test as allocation
|
||||
# this is to mimic the behavior of pytest-aiohttp, and is
|
||||
# required to avoid warnings from spilling over into next
|
||||
# test case.
|
||||
gc.collect()
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def bcrypt_cost():
|
||||
|
@ -278,7 +302,7 @@ def aiohttp_client_cls():
|
|||
|
||||
@pytest.fixture
|
||||
def aiohttp_client(
|
||||
loop: asyncio.AbstractEventLoop,
|
||||
event_loop: asyncio.AbstractEventLoop,
|
||||
) -> Generator[AiohttpClient, None, None]:
|
||||
"""Override the default aiohttp_client since 3.x does not support aiohttp_client_cls.
|
||||
|
||||
|
@ -289,6 +313,7 @@ def aiohttp_client(
|
|||
aiohttp_client(server, **kwargs)
|
||||
aiohttp_client(raw_server, **kwargs)
|
||||
"""
|
||||
loop = event_loop
|
||||
clients = []
|
||||
|
||||
async def go(
|
||||
|
@ -335,9 +360,10 @@ def hass_fixture_setup():
|
|||
|
||||
|
||||
@pytest.fixture
|
||||
def hass(hass_fixture_setup, loop, load_registries, hass_storage, request):
|
||||
def hass(hass_fixture_setup, event_loop, load_registries, hass_storage, request):
|
||||
"""Fixture to provide a test instance of Home Assistant."""
|
||||
|
||||
loop = event_loop
|
||||
hass_fixture_setup.append(True)
|
||||
|
||||
orig_tz = dt_util.DEFAULT_TIME_ZONE
|
||||
|
@ -382,7 +408,7 @@ def hass(hass_fixture_setup, loop, load_registries, hass_storage, request):
|
|||
|
||||
|
||||
@pytest.fixture
|
||||
async def stop_hass():
|
||||
async def stop_hass(event_loop):
|
||||
"""Make sure all hass are stopped."""
|
||||
orig_hass = ha.HomeAssistant
|
||||
|
||||
|
@ -403,6 +429,7 @@ async def stop_hass():
|
|||
with patch.object(hass_inst.loop, "stop"):
|
||||
await hass_inst.async_block_till_done()
|
||||
await hass_inst.async_stop(force=True)
|
||||
await event_loop.shutdown_default_executor()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
|
|
|
@ -8,7 +8,7 @@ import logging
|
|||
import operator
|
||||
from types import MappingProxyType
|
||||
from unittest import mock
|
||||
from unittest.mock import AsyncMock, patch
|
||||
from unittest.mock import AsyncMock, MagicMock, patch
|
||||
|
||||
from async_timeout import timeout
|
||||
import pytest
|
||||
|
@ -1734,6 +1734,7 @@ async def test_condition_created_once(async_from_config, hass):
|
|||
)
|
||||
|
||||
async_from_config.reset_mock()
|
||||
async_from_config.return_value = MagicMock()
|
||||
|
||||
hass.states.async_set("test.entity", "hello")
|
||||
await script_obj.async_run(context=Context())
|
||||
|
|
|
@ -108,7 +108,7 @@ async def test_change_password_invalid_user(hass, provider, capsys, hass_storage
|
|||
data.validate_login("invalid-user", "new-pass")
|
||||
|
||||
|
||||
def test_parsing_args(loop):
|
||||
def test_parsing_args(event_loop):
|
||||
"""Test we parse args correctly."""
|
||||
called = False
|
||||
|
||||
|
|
|
@ -43,7 +43,7 @@ def normalize_yaml_files(check_dict):
|
|||
return [key.replace(root, "...") for key in sorted(check_dict["yaml_files"].keys())]
|
||||
|
||||
|
||||
def test_bad_core_config(mock_is_file, loop):
|
||||
def test_bad_core_config(mock_is_file, event_loop):
|
||||
"""Test a bad core config setup."""
|
||||
files = {YAML_CONFIG_FILE: BAD_CORE_CONFIG}
|
||||
with patch_yaml_files(files):
|
||||
|
@ -52,7 +52,7 @@ def test_bad_core_config(mock_is_file, loop):
|
|||
assert res["except"]["homeassistant"][1] == {"unit_system": "bad"}
|
||||
|
||||
|
||||
def test_config_platform_valid(mock_is_file, loop):
|
||||
def test_config_platform_valid(mock_is_file, event_loop):
|
||||
"""Test a valid platform setup."""
|
||||
files = {YAML_CONFIG_FILE: BASE_CONFIG + "light:\n platform: demo"}
|
||||
with patch_yaml_files(files):
|
||||
|
@ -65,7 +65,7 @@ def test_config_platform_valid(mock_is_file, loop):
|
|||
assert len(res["yaml_files"]) == 1
|
||||
|
||||
|
||||
def test_component_platform_not_found(mock_is_file, loop):
|
||||
def test_component_platform_not_found(mock_is_file, event_loop):
|
||||
"""Test errors if component or platform not found."""
|
||||
# Make sure they don't exist
|
||||
files = {YAML_CONFIG_FILE: BASE_CONFIG + "beer:"}
|
||||
|
@ -96,7 +96,7 @@ def test_component_platform_not_found(mock_is_file, loop):
|
|||
assert len(res["yaml_files"]) == 1
|
||||
|
||||
|
||||
def test_secrets(mock_is_file, loop):
|
||||
def test_secrets(mock_is_file, event_loop):
|
||||
"""Test secrets config checking method."""
|
||||
secrets_path = get_test_config_dir("secrets.yaml")
|
||||
|
||||
|
@ -127,7 +127,7 @@ def test_secrets(mock_is_file, loop):
|
|||
]
|
||||
|
||||
|
||||
def test_package_invalid(mock_is_file, loop):
|
||||
def test_package_invalid(mock_is_file, event_loop):
|
||||
"""Test an invalid package."""
|
||||
files = {
|
||||
YAML_CONFIG_FILE: BASE_CONFIG + (" packages:\n p1:\n" ' group: ["a"]')
|
||||
|
@ -145,7 +145,7 @@ def test_package_invalid(mock_is_file, loop):
|
|||
assert len(res["yaml_files"]) == 1
|
||||
|
||||
|
||||
def test_bootstrap_error(loop):
|
||||
def test_bootstrap_error(event_loop):
|
||||
"""Test a valid platform setup."""
|
||||
files = {YAML_CONFIG_FILE: BASE_CONFIG + "automation: !include no.yaml"}
|
||||
with patch_yaml_files(files):
|
||||
|
|
|
@ -460,7 +460,7 @@ async def test_setup_hass(
|
|||
mock_ensure_config_exists,
|
||||
mock_process_ha_config_upgrade,
|
||||
caplog,
|
||||
loop,
|
||||
event_loop,
|
||||
):
|
||||
"""Test it works."""
|
||||
verbose = Mock()
|
||||
|
@ -511,7 +511,7 @@ async def test_setup_hass_takes_longer_than_log_slow_startup(
|
|||
mock_ensure_config_exists,
|
||||
mock_process_ha_config_upgrade,
|
||||
caplog,
|
||||
loop,
|
||||
event_loop,
|
||||
):
|
||||
"""Test it works."""
|
||||
verbose = Mock()
|
||||
|
@ -553,7 +553,7 @@ async def test_setup_hass_invalid_yaml(
|
|||
mock_mount_local_lib_path,
|
||||
mock_ensure_config_exists,
|
||||
mock_process_ha_config_upgrade,
|
||||
loop,
|
||||
event_loop,
|
||||
):
|
||||
"""Test it works."""
|
||||
with patch(
|
||||
|
@ -581,7 +581,7 @@ async def test_setup_hass_config_dir_nonexistent(
|
|||
mock_mount_local_lib_path,
|
||||
mock_ensure_config_exists,
|
||||
mock_process_ha_config_upgrade,
|
||||
loop,
|
||||
event_loop,
|
||||
):
|
||||
"""Test it works."""
|
||||
mock_ensure_config_exists.return_value = False
|
||||
|
@ -608,7 +608,7 @@ async def test_setup_hass_safe_mode(
|
|||
mock_mount_local_lib_path,
|
||||
mock_ensure_config_exists,
|
||||
mock_process_ha_config_upgrade,
|
||||
loop,
|
||||
event_loop,
|
||||
):
|
||||
"""Test it works."""
|
||||
with patch("homeassistant.components.browser.setup") as browser_setup, patch(
|
||||
|
@ -641,7 +641,7 @@ async def test_setup_hass_invalid_core_config(
|
|||
mock_mount_local_lib_path,
|
||||
mock_ensure_config_exists,
|
||||
mock_process_ha_config_upgrade,
|
||||
loop,
|
||||
event_loop,
|
||||
):
|
||||
"""Test it works."""
|
||||
with patch(
|
||||
|
@ -669,7 +669,7 @@ async def test_setup_safe_mode_if_no_frontend(
|
|||
mock_mount_local_lib_path,
|
||||
mock_ensure_config_exists,
|
||||
mock_process_ha_config_upgrade,
|
||||
loop,
|
||||
event_loop,
|
||||
):
|
||||
"""Test we setup safe mode if frontend didn't load."""
|
||||
verbose = Mock()
|
||||
|
|
|
@ -87,9 +87,9 @@ def test_async_add_hass_job_schedule_partial_callback():
|
|||
assert len(hass.add_job.mock_calls) == 0
|
||||
|
||||
|
||||
def test_async_add_hass_job_schedule_coroutinefunction(loop):
|
||||
def test_async_add_hass_job_schedule_coroutinefunction(event_loop):
|
||||
"""Test that we schedule coroutines and add jobs to the job pool."""
|
||||
hass = MagicMock(loop=MagicMock(wraps=loop))
|
||||
hass = MagicMock(loop=MagicMock(wraps=event_loop))
|
||||
|
||||
async def job():
|
||||
pass
|
||||
|
@ -100,9 +100,9 @@ def test_async_add_hass_job_schedule_coroutinefunction(loop):
|
|||
assert len(hass.add_job.mock_calls) == 0
|
||||
|
||||
|
||||
def test_async_add_hass_job_schedule_partial_coroutinefunction(loop):
|
||||
def test_async_add_hass_job_schedule_partial_coroutinefunction(event_loop):
|
||||
"""Test that we schedule partial coros and add jobs to the job pool."""
|
||||
hass = MagicMock(loop=MagicMock(wraps=loop))
|
||||
hass = MagicMock(loop=MagicMock(wraps=event_loop))
|
||||
|
||||
async def job():
|
||||
pass
|
||||
|
@ -128,9 +128,9 @@ def test_async_add_job_add_hass_threaded_job_to_pool():
|
|||
assert len(hass.loop.run_in_executor.mock_calls) == 1
|
||||
|
||||
|
||||
def test_async_create_task_schedule_coroutine(loop):
|
||||
def test_async_create_task_schedule_coroutine(event_loop):
|
||||
"""Test that we schedule coroutines and add jobs to the job pool."""
|
||||
hass = MagicMock(loop=MagicMock(wraps=loop))
|
||||
hass = MagicMock(loop=MagicMock(wraps=event_loop))
|
||||
|
||||
async def job():
|
||||
pass
|
||||
|
@ -1079,7 +1079,7 @@ async def test_bad_timezone_raises_value_error(hass):
|
|||
await hass.config.async_update(time_zone="not_a_timezone")
|
||||
|
||||
|
||||
async def test_start_taking_too_long(loop, caplog):
|
||||
async def test_start_taking_too_long(event_loop, caplog):
|
||||
"""Test when async_start takes too long."""
|
||||
hass = ha.HomeAssistant()
|
||||
caplog.set_level(logging.WARNING)
|
||||
|
@ -1098,7 +1098,7 @@ async def test_start_taking_too_long(loop, caplog):
|
|||
assert hass.state == ha.CoreState.stopped
|
||||
|
||||
|
||||
async def test_track_task_functions(loop):
|
||||
async def test_track_task_functions(event_loop):
|
||||
"""Test function to start/stop track task and initial state."""
|
||||
hass = ha.HomeAssistant()
|
||||
try:
|
||||
|
|
|
@ -32,7 +32,7 @@ async def session(hass):
|
|||
|
||||
|
||||
@pytest.fixture
|
||||
async def raising_session(loop):
|
||||
async def raising_session(event_loop):
|
||||
"""Return an aioclient session that only fails."""
|
||||
return Mock(get=Mock(side_effect=aiohttp.ClientError))
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue