From b054c037fe9429f6b08a974f8c82cb62b0ce3a0d Mon Sep 17 00:00:00 2001 From: epenet <6771947+epenet@users.noreply.github.com> Date: Fri, 5 Jul 2024 09:05:21 +0200 Subject: [PATCH] Improve type hints in hassio tests (#121221) --- tests/components/hassio/conftest.py | 24 ++++++--- tests/components/hassio/test_addon_panel.py | 5 +- tests/components/hassio/test_auth.py | 29 +++++------ tests/components/hassio/test_discovery.py | 21 ++++++-- tests/components/hassio/test_handler.py | 18 ++++--- tests/components/hassio/test_http.py | 51 ++++++++++--------- tests/components/hassio/test_init.py | 9 ++-- tests/components/hassio/test_issues.py | 43 ++++++++-------- tests/components/hassio/test_repairs.py | 21 ++++---- tests/components/hassio/test_websocket_api.py | 11 ++-- 10 files changed, 135 insertions(+), 97 deletions(-) diff --git a/tests/components/hassio/conftest.py b/tests/components/hassio/conftest.py index 7b79dfe6179..db1a07c4df3 100644 --- a/tests/components/hassio/conftest.py +++ b/tests/components/hassio/conftest.py @@ -1,5 +1,6 @@ """Fixtures for Hass.io.""" +from collections.abc import Generator import os import re from unittest.mock import Mock, patch @@ -7,6 +8,7 @@ from unittest.mock import Mock, patch from aiohttp.test_utils import TestClient import pytest +from homeassistant.auth.models import RefreshToken from homeassistant.components.hassio.handler import HassIO, HassioAPIError from homeassistant.core import CoreState, HomeAssistant from homeassistant.helpers.aiohttp_client import async_get_clientsession @@ -19,7 +21,7 @@ from tests.typing import ClientSessionGenerator @pytest.fixture(autouse=True) -def disable_security_filter(): +def disable_security_filter() -> Generator[None]: """Disable the security filter to ensure the integration is secure.""" with patch( "homeassistant.components.http.security_filter.FILTERS", @@ -29,7 +31,7 @@ def disable_security_filter(): @pytest.fixture -def hassio_env(): +def hassio_env() -> Generator[None]: """Fixture to inject hassio env.""" with ( patch.dict(os.environ, {"SUPERVISOR": "127.0.0.1"}), @@ -48,11 +50,11 @@ def hassio_env(): @pytest.fixture def hassio_stubs( - hassio_env, + hassio_env: None, hass: HomeAssistant, hass_client: ClientSessionGenerator, aioclient_mock: AiohttpClientMocker, -): +) -> RefreshToken: """Create mock hassio http client.""" with ( patch( @@ -86,7 +88,7 @@ def hassio_stubs( @pytest.fixture def hassio_client( - hassio_stubs, hass: HomeAssistant, hass_client: ClientSessionGenerator + hassio_stubs: RefreshToken, hass: HomeAssistant, hass_client: ClientSessionGenerator ) -> TestClient: """Return a Hass.io HTTP client.""" return hass.loop.run_until_complete(hass_client()) @@ -94,7 +96,9 @@ def hassio_client( @pytest.fixture def hassio_noauth_client( - hassio_stubs, hass: HomeAssistant, aiohttp_client: ClientSessionGenerator + hassio_stubs: RefreshToken, + hass: HomeAssistant, + aiohttp_client: ClientSessionGenerator, ) -> TestClient: """Return a Hass.io HTTP client without auth.""" return hass.loop.run_until_complete(aiohttp_client(hass.http.app)) @@ -102,7 +106,9 @@ def hassio_noauth_client( @pytest.fixture async def hassio_client_supervisor( - hass: HomeAssistant, aiohttp_client: ClientSessionGenerator, hassio_stubs + hass: HomeAssistant, + aiohttp_client: ClientSessionGenerator, + hassio_stubs: RefreshToken, ) -> TestClient: """Return an authenticated HTTP client.""" access_token = hass.auth.async_create_access_token(hassio_stubs) @@ -113,7 +119,9 @@ async def hassio_client_supervisor( @pytest.fixture -async def hassio_handler(hass: HomeAssistant, aioclient_mock: AiohttpClientMocker): +def hassio_handler( + hass: HomeAssistant, aioclient_mock: AiohttpClientMocker +) -> Generator[HassIO]: """Create mock hassio handler.""" with patch.dict(os.environ, {"SUPERVISOR_TOKEN": SUPERVISOR_TOKEN}): yield HassIO(hass.loop, async_get_clientsession(hass), "127.0.0.1") diff --git a/tests/components/hassio/test_addon_panel.py b/tests/components/hassio/test_addon_panel.py index 8436b3393b9..f7407152f7e 100644 --- a/tests/components/hassio/test_addon_panel.py +++ b/tests/components/hassio/test_addon_panel.py @@ -24,8 +24,9 @@ def mock_all(aioclient_mock: AiohttpClientMocker) -> None: ) +@pytest.mark.usefixtures("hassio_env") async def test_hassio_addon_panel_startup( - hass: HomeAssistant, aioclient_mock: AiohttpClientMocker, hassio_env + hass: HomeAssistant, aioclient_mock: AiohttpClientMocker ) -> None: """Test startup and panel setup after event.""" aioclient_mock.get( @@ -68,10 +69,10 @@ async def test_hassio_addon_panel_startup( ) +@pytest.mark.usefixtures("hassio_env") async def test_hassio_addon_panel_api( hass: HomeAssistant, aioclient_mock: AiohttpClientMocker, - hassio_env, hass_client: ClientSessionGenerator, ) -> None: """Test panel api after event.""" diff --git a/tests/components/hassio/test_auth.py b/tests/components/hassio/test_auth.py index 175d9061d56..ad96b58e99d 100644 --- a/tests/components/hassio/test_auth.py +++ b/tests/components/hassio/test_auth.py @@ -3,11 +3,12 @@ from http import HTTPStatus from unittest.mock import Mock, patch +from aiohttp.test_utils import TestClient + from homeassistant.auth.providers.homeassistant import InvalidAuth -from homeassistant.core import HomeAssistant -async def test_auth_success(hass: HomeAssistant, hassio_client_supervisor) -> None: +async def test_auth_success(hassio_client_supervisor: TestClient) -> None: """Test no auth needed for .""" with patch( "homeassistant.auth.providers.homeassistant." @@ -23,7 +24,7 @@ async def test_auth_success(hass: HomeAssistant, hassio_client_supervisor) -> No mock_login.assert_called_with("test", "123456") -async def test_auth_fails_no_supervisor(hass: HomeAssistant, hassio_client) -> None: +async def test_auth_fails_no_supervisor(hassio_client: TestClient) -> None: """Test if only supervisor can access.""" with patch( "homeassistant.auth.providers.homeassistant." @@ -39,7 +40,7 @@ async def test_auth_fails_no_supervisor(hass: HomeAssistant, hassio_client) -> N assert not mock_login.called -async def test_auth_fails_no_auth(hass: HomeAssistant, hassio_noauth_client) -> None: +async def test_auth_fails_no_auth(hassio_noauth_client: TestClient) -> None: """Test if only supervisor can access.""" with patch( "homeassistant.auth.providers.homeassistant." @@ -55,7 +56,7 @@ async def test_auth_fails_no_auth(hass: HomeAssistant, hassio_noauth_client) -> assert not mock_login.called -async def test_login_error(hass: HomeAssistant, hassio_client_supervisor) -> None: +async def test_login_error(hassio_client_supervisor: TestClient) -> None: """Test no auth needed for error.""" with patch( "homeassistant.auth.providers.homeassistant." @@ -72,7 +73,7 @@ async def test_login_error(hass: HomeAssistant, hassio_client_supervisor) -> Non mock_login.assert_called_with("test", "123456") -async def test_login_no_data(hass: HomeAssistant, hassio_client_supervisor) -> None: +async def test_login_no_data(hassio_client_supervisor: TestClient) -> None: """Test auth with no data -> error.""" with patch( "homeassistant.auth.providers.homeassistant." @@ -86,7 +87,7 @@ async def test_login_no_data(hass: HomeAssistant, hassio_client_supervisor) -> N assert not mock_login.called -async def test_login_no_username(hass: HomeAssistant, hassio_client_supervisor) -> None: +async def test_login_no_username(hassio_client_supervisor: TestClient) -> None: """Test auth with no username in data -> error.""" with patch( "homeassistant.auth.providers.homeassistant." @@ -102,9 +103,7 @@ async def test_login_no_username(hass: HomeAssistant, hassio_client_supervisor) assert not mock_login.called -async def test_login_success_extra( - hass: HomeAssistant, hassio_client_supervisor -) -> None: +async def test_login_success_extra(hassio_client_supervisor: TestClient) -> None: """Test auth with extra data.""" with patch( "homeassistant.auth.providers.homeassistant." @@ -125,7 +124,7 @@ async def test_login_success_extra( mock_login.assert_called_with("test", "123456") -async def test_password_success(hass: HomeAssistant, hassio_client_supervisor) -> None: +async def test_password_success(hassio_client_supervisor: TestClient) -> None: """Test no auth needed for .""" with patch( "homeassistant.auth.providers.homeassistant." @@ -141,7 +140,7 @@ async def test_password_success(hass: HomeAssistant, hassio_client_supervisor) - mock_change.assert_called_with("test", "123456") -async def test_password_fails_no_supervisor(hass: HomeAssistant, hassio_client) -> None: +async def test_password_fails_no_supervisor(hassio_client: TestClient) -> None: """Test if only supervisor can access.""" resp = await hassio_client.post( "/api/hassio_auth/password_reset", @@ -152,9 +151,7 @@ async def test_password_fails_no_supervisor(hass: HomeAssistant, hassio_client) assert resp.status == HTTPStatus.UNAUTHORIZED -async def test_password_fails_no_auth( - hass: HomeAssistant, hassio_noauth_client -) -> None: +async def test_password_fails_no_auth(hassio_noauth_client: TestClient) -> None: """Test if only supervisor can access.""" resp = await hassio_noauth_client.post( "/api/hassio_auth/password_reset", @@ -165,7 +162,7 @@ async def test_password_fails_no_auth( assert resp.status == HTTPStatus.UNAUTHORIZED -async def test_password_no_user(hass: HomeAssistant, hassio_client_supervisor) -> None: +async def test_password_no_user(hassio_client_supervisor: TestClient) -> None: """Test changing password for invalid user.""" resp = await hassio_client_supervisor.post( "/api/hassio_auth/password_reset", diff --git a/tests/components/hassio/test_discovery.py b/tests/components/hassio/test_discovery.py index 0783ee77932..305b863b3af 100644 --- a/tests/components/hassio/test_discovery.py +++ b/tests/components/hassio/test_discovery.py @@ -1,8 +1,10 @@ """Test config flow.""" +from collections.abc import Generator from http import HTTPStatus from unittest.mock import AsyncMock, Mock, patch +from aiohttp.test_utils import TestClient import pytest from homeassistant import config_entries @@ -18,7 +20,9 @@ from tests.test_util.aiohttp import AiohttpClientMocker @pytest.fixture(name="mock_mqtt") -async def mock_mqtt_fixture(hass): +def mock_mqtt_fixture( + hass: HomeAssistant, +) -> Generator[type[config_entries.ConfigFlow]]: """Mock the MQTT integration's config flow.""" mock_integration(hass, MockModule(MQTT_DOMAIN)) mock_platform(hass, f"{MQTT_DOMAIN}.config_flow", None) @@ -34,8 +38,11 @@ async def mock_mqtt_fixture(hass): yield MqttFlow +@pytest.mark.usefixtures("hassio_client") async def test_hassio_discovery_startup( - hass: HomeAssistant, aioclient_mock: AiohttpClientMocker, hassio_client, mock_mqtt + hass: HomeAssistant, + aioclient_mock: AiohttpClientMocker, + mock_mqtt: type[config_entries.ConfigFlow], ) -> None: """Test startup and discovery after event.""" aioclient_mock.get( @@ -90,8 +97,11 @@ async def test_hassio_discovery_startup( ) +@pytest.mark.usefixtures("hassio_client") async def test_hassio_discovery_startup_done( - hass: HomeAssistant, aioclient_mock: AiohttpClientMocker, hassio_client, mock_mqtt + hass: HomeAssistant, + aioclient_mock: AiohttpClientMocker, + mock_mqtt: type[config_entries.ConfigFlow], ) -> None: """Test startup and discovery with hass discovery.""" aioclient_mock.post( @@ -159,7 +169,10 @@ async def test_hassio_discovery_startup_done( async def test_hassio_discovery_webhook( - hass: HomeAssistant, aioclient_mock: AiohttpClientMocker, hassio_client, mock_mqtt + hass: HomeAssistant, + aioclient_mock: AiohttpClientMocker, + hassio_client: TestClient, + mock_mqtt: type[config_entries.ConfigFlow], ) -> None: """Test discovery webhook.""" aioclient_mock.get( diff --git a/tests/components/hassio/test_handler.py b/tests/components/hassio/test_handler.py index c418576a802..c5fa6ff8254 100644 --- a/tests/components/hassio/test_handler.py +++ b/tests/components/hassio/test_handler.py @@ -365,8 +365,9 @@ async def test_api_headers( assert received_request.headers[hdrs.CONTENT_TYPE] == "application/octet-stream" +@pytest.mark.usefixtures("hassio_stubs") async def test_api_get_green_settings( - hass: HomeAssistant, hassio_stubs, aioclient_mock: AiohttpClientMocker + hass: HomeAssistant, aioclient_mock: AiohttpClientMocker ) -> None: """Test setup with API ping.""" aioclient_mock.get( @@ -389,8 +390,9 @@ async def test_api_get_green_settings( assert aioclient_mock.call_count == 1 +@pytest.mark.usefixtures("hassio_stubs") async def test_api_set_green_settings( - hass: HomeAssistant, hassio_stubs, aioclient_mock: AiohttpClientMocker + hass: HomeAssistant, aioclient_mock: AiohttpClientMocker ) -> None: """Test setup with API ping.""" aioclient_mock.post( @@ -407,8 +409,9 @@ async def test_api_set_green_settings( assert aioclient_mock.call_count == 1 +@pytest.mark.usefixtures("hassio_stubs") async def test_api_get_yellow_settings( - hass: HomeAssistant, hassio_stubs, aioclient_mock: AiohttpClientMocker + hass: HomeAssistant, aioclient_mock: AiohttpClientMocker ) -> None: """Test setup with API ping.""" aioclient_mock.get( @@ -427,8 +430,9 @@ async def test_api_get_yellow_settings( assert aioclient_mock.call_count == 1 +@pytest.mark.usefixtures("hassio_stubs") async def test_api_set_yellow_settings( - hass: HomeAssistant, hassio_stubs, aioclient_mock: AiohttpClientMocker + hass: HomeAssistant, aioclient_mock: AiohttpClientMocker ) -> None: """Test setup with API ping.""" aioclient_mock.post( @@ -445,8 +449,9 @@ async def test_api_set_yellow_settings( assert aioclient_mock.call_count == 1 +@pytest.mark.usefixtures("hassio_stubs") async def test_api_reboot_host( - hass: HomeAssistant, hassio_stubs, aioclient_mock: AiohttpClientMocker + hass: HomeAssistant, aioclient_mock: AiohttpClientMocker ) -> None: """Test setup with API ping.""" aioclient_mock.post( @@ -458,7 +463,8 @@ async def test_api_reboot_host( assert aioclient_mock.call_count == 1 -async def test_send_command_invalid_command(hass: HomeAssistant, hassio_stubs) -> None: +@pytest.mark.usefixtures("hassio_stubs") +async def test_send_command_invalid_command(hass: HomeAssistant) -> None: """Test send command fails when command is invalid.""" hassio: HassIO = hass.data["hassio"] with pytest.raises(HassioAPIError): diff --git a/tests/components/hassio/test_http.py b/tests/components/hassio/test_http.py index a5ffb4f0d83..404c047a56c 100644 --- a/tests/components/hassio/test_http.py +++ b/tests/components/hassio/test_http.py @@ -1,9 +1,11 @@ """The tests for the hassio component.""" +from collections.abc import Generator from http import HTTPStatus from unittest.mock import patch from aiohttp import StreamReader +from aiohttp.test_utils import TestClient import pytest from tests.common import MockUser @@ -11,7 +13,7 @@ from tests.test_util.aiohttp import AiohttpClientMocker @pytest.fixture -def mock_not_onboarded(): +def mock_not_onboarded() -> Generator[None]: """Mock that we're not onboarded.""" with patch( "homeassistant.components.hassio.http.async_is_onboarded", return_value=False @@ -20,7 +22,9 @@ def mock_not_onboarded(): @pytest.fixture -def hassio_user_client(hassio_client, hass_admin_user: MockUser): +def hassio_user_client( + hassio_client: TestClient, hass_admin_user: MockUser +) -> TestClient: """Return a Hass.io HTTP client tied to a non-admin user.""" hass_admin_user.groups = [] return hassio_client @@ -35,7 +39,7 @@ def hassio_user_client(hassio_client, hass_admin_user: MockUser): ], ) async def test_forward_request_onboarded_user_get( - hassio_user_client, aioclient_mock: AiohttpClientMocker, path: str + hassio_user_client: TestClient, aioclient_mock: AiohttpClientMocker, path: str ) -> None: """Test fetching normal path.""" aioclient_mock.get(f"http://127.0.0.1/{path}", text="response") @@ -55,7 +59,7 @@ async def test_forward_request_onboarded_user_get( @pytest.mark.parametrize("method", ["POST", "PUT", "DELETE", "RANDOM"]) async def test_forward_request_onboarded_user_unallowed_methods( - hassio_user_client, aioclient_mock: AiohttpClientMocker, method: str + hassio_user_client: TestClient, aioclient_mock: AiohttpClientMocker, method: str ) -> None: """Test fetching normal path.""" resp = await hassio_user_client.post("/api/hassio/app/entrypoint.js") @@ -82,7 +86,7 @@ async def test_forward_request_onboarded_user_unallowed_methods( ], ) async def test_forward_request_onboarded_user_unallowed_paths( - hassio_user_client, + hassio_user_client: TestClient, aioclient_mock: AiohttpClientMocker, bad_path: str, expected_status: int, @@ -105,7 +109,7 @@ async def test_forward_request_onboarded_user_unallowed_paths( ], ) async def test_forward_request_onboarded_noauth_get( - hassio_noauth_client, aioclient_mock: AiohttpClientMocker, path: str + hassio_noauth_client: TestClient, aioclient_mock: AiohttpClientMocker, path: str ) -> None: """Test fetching normal path.""" aioclient_mock.get(f"http://127.0.0.1/{path}", text="response") @@ -125,7 +129,7 @@ async def test_forward_request_onboarded_noauth_get( @pytest.mark.parametrize("method", ["POST", "PUT", "DELETE", "RANDOM"]) async def test_forward_request_onboarded_noauth_unallowed_methods( - hassio_noauth_client, aioclient_mock: AiohttpClientMocker, method: str + hassio_noauth_client: TestClient, aioclient_mock: AiohttpClientMocker, method: str ) -> None: """Test fetching normal path.""" resp = await hassio_noauth_client.post("/api/hassio/app/entrypoint.js") @@ -152,7 +156,7 @@ async def test_forward_request_onboarded_noauth_unallowed_methods( ], ) async def test_forward_request_onboarded_noauth_unallowed_paths( - hassio_noauth_client, + hassio_noauth_client: TestClient, aioclient_mock: AiohttpClientMocker, bad_path: str, expected_status: int, @@ -176,7 +180,7 @@ async def test_forward_request_onboarded_noauth_unallowed_paths( ], ) async def test_forward_request_not_onboarded_get( - hassio_noauth_client, + hassio_noauth_client: TestClient, aioclient_mock: AiohttpClientMocker, path: str, authenticated: bool, @@ -212,7 +216,7 @@ async def test_forward_request_not_onboarded_get( ], ) async def test_forward_request_not_onboarded_post( - hassio_noauth_client, + hassio_noauth_client: TestClient, aioclient_mock: AiohttpClientMocker, path: str, mock_not_onboarded, @@ -238,7 +242,7 @@ async def test_forward_request_not_onboarded_post( @pytest.mark.parametrize("method", ["POST", "PUT", "DELETE", "RANDOM"]) async def test_forward_request_not_onboarded_unallowed_methods( - hassio_noauth_client, aioclient_mock: AiohttpClientMocker, method: str + hassio_noauth_client: TestClient, aioclient_mock: AiohttpClientMocker, method: str ) -> None: """Test fetching normal path.""" resp = await hassio_noauth_client.post("/api/hassio/app/entrypoint.js") @@ -265,7 +269,7 @@ async def test_forward_request_not_onboarded_unallowed_methods( ], ) async def test_forward_request_not_onboarded_unallowed_paths( - hassio_noauth_client, + hassio_noauth_client: TestClient, aioclient_mock: AiohttpClientMocker, bad_path: str, expected_status: int, @@ -294,7 +298,7 @@ async def test_forward_request_not_onboarded_unallowed_paths( ], ) async def test_forward_request_admin_get( - hassio_client, + hassio_client: TestClient, aioclient_mock: AiohttpClientMocker, path: str, authenticated: bool, @@ -329,7 +333,7 @@ async def test_forward_request_admin_get( ], ) async def test_forward_request_admin_post( - hassio_client, + hassio_client: TestClient, aioclient_mock: AiohttpClientMocker, path: str, ) -> None: @@ -354,7 +358,7 @@ async def test_forward_request_admin_post( @pytest.mark.parametrize("method", ["POST", "PUT", "DELETE", "RANDOM"]) async def test_forward_request_admin_unallowed_methods( - hassio_client, aioclient_mock: AiohttpClientMocker, method: str + hassio_client: TestClient, aioclient_mock: AiohttpClientMocker, method: str ) -> None: """Test fetching normal path.""" resp = await hassio_client.post("/api/hassio/app/entrypoint.js") @@ -379,7 +383,7 @@ async def test_forward_request_admin_unallowed_methods( ], ) async def test_forward_request_admin_unallowed_paths( - hassio_client, + hassio_client: TestClient, aioclient_mock: AiohttpClientMocker, bad_path: str, expected_status: int, @@ -394,7 +398,7 @@ async def test_forward_request_admin_unallowed_paths( async def test_bad_gateway_when_cannot_find_supervisor( - hassio_client, aioclient_mock: AiohttpClientMocker + hassio_client: TestClient, aioclient_mock: AiohttpClientMocker ) -> None: """Test we get a bad gateway error if we can't find supervisor.""" aioclient_mock.get("http://127.0.0.1/app/entrypoint.js", exc=TimeoutError) @@ -404,9 +408,8 @@ async def test_bad_gateway_when_cannot_find_supervisor( async def test_backup_upload_headers( - hassio_client, + hassio_client: TestClient, aioclient_mock: AiohttpClientMocker, - caplog: pytest.LogCaptureFixture, mock_not_onboarded, ) -> None: """Test that we forward the full header for backup upload.""" @@ -427,7 +430,7 @@ async def test_backup_upload_headers( async def test_backup_download_headers( - hassio_client, aioclient_mock: AiohttpClientMocker, mock_not_onboarded + hassio_client: TestClient, aioclient_mock: AiohttpClientMocker, mock_not_onboarded ) -> None: """Test that we forward the full header for backup download.""" content_disposition = "attachment; filename=test.tar" @@ -449,7 +452,9 @@ async def test_backup_download_headers( assert resp.headers["Content-Disposition"] == content_disposition -async def test_stream(hassio_client, aioclient_mock: AiohttpClientMocker) -> None: +async def test_stream( + hassio_client: TestClient, aioclient_mock: AiohttpClientMocker +) -> None: """Verify that the request is a stream.""" content_type = "multipart/form-data; boundary='--webkit'" aioclient_mock.post("http://127.0.0.1/backups/new/upload") @@ -462,7 +467,7 @@ async def test_stream(hassio_client, aioclient_mock: AiohttpClientMocker) -> Non async def test_simple_get_no_stream( - hassio_client, aioclient_mock: AiohttpClientMocker + hassio_client: TestClient, aioclient_mock: AiohttpClientMocker ) -> None: """Verify that a simple GET request is not a stream.""" aioclient_mock.get("http://127.0.0.1/app/entrypoint.js") @@ -472,7 +477,7 @@ async def test_simple_get_no_stream( async def test_entrypoint_cache_control( - hassio_client, aioclient_mock: AiohttpClientMocker + hassio_client: TestClient, aioclient_mock: AiohttpClientMocker ) -> None: """Test that we return cache control for requests to the entrypoint only.""" aioclient_mock.get("http://127.0.0.1/app/entrypoint.js") diff --git a/tests/components/hassio/test_init.py b/tests/components/hassio/test_init.py index 0246b557ee4..d71e8acfbe0 100644 --- a/tests/components/hassio/test_init.py +++ b/tests/components/hassio/test_init.py @@ -486,7 +486,8 @@ async def test_warn_when_cannot_connect( assert "Not connected with the supervisor / system too busy!" in caplog.text -async def test_service_register(hassio_env, hass: HomeAssistant) -> None: +@pytest.mark.usefixtures("hassio_env") +async def test_service_register(hass: HomeAssistant) -> None: """Check if service will be setup.""" assert await async_setup_component(hass, "hassio", {}) assert hass.services.has_service("hassio", "addon_start") @@ -717,8 +718,9 @@ async def test_addon_service_call_with_complex_slug( await hass.services.async_call("hassio", "addon_start", {"addon": "test.a_1-2"}) +@pytest.mark.usefixtures("hassio_env") async def test_service_calls_core( - hassio_env, hass: HomeAssistant, aioclient_mock: AiohttpClientMocker + hass: HomeAssistant, aioclient_mock: AiohttpClientMocker ) -> None: """Call core service and check the API calls behind that.""" assert await async_setup_component(hass, "homeassistant", {}) @@ -1116,8 +1118,9 @@ async def test_setup_hardware_integration( assert len(mock_setup_entry.mock_calls) == 1 +@pytest.mark.usefixtures("hassio_stubs") async def test_get_store_addon_info( - hass: HomeAssistant, hassio_stubs, aioclient_mock: AiohttpClientMocker + hass: HomeAssistant, aioclient_mock: AiohttpClientMocker ) -> None: """Test get store add-on info from Supervisor API.""" aioclient_mock.clear_requests() diff --git a/tests/components/hassio/test_issues.py b/tests/components/hassio/test_issues.py index ff0e4a8dd92..1a3d3d83f95 100644 --- a/tests/components/hassio/test_issues.py +++ b/tests/components/hassio/test_issues.py @@ -2,6 +2,7 @@ from __future__ import annotations +from collections.abc import Generator from datetime import timedelta from http import HTTPStatus import os @@ -22,13 +23,13 @@ from tests.typing import WebSocketGenerator @pytest.fixture(autouse=True) -async def setup_repairs(hass): +async def setup_repairs(hass: HomeAssistant) -> None: """Set up the repairs integration.""" assert await async_setup_component(hass, REPAIRS_DOMAIN, {REPAIRS_DOMAIN: {}}) @pytest.fixture(autouse=True) -async def fixture_supervisor_environ(): +def fixture_supervisor_environ() -> Generator[None]: """Mock os environ for supervisor.""" with patch.dict(os.environ, MOCK_ENVIRON): yield @@ -40,7 +41,7 @@ def mock_resolution_info( unhealthy: list[str] | None = None, issues: list[dict[str, str]] | None = None, suggestion_result: str = "ok", -): +) -> None: """Mock resolution/info endpoint with unsupported/unhealthy reasons and/or issues.""" aioclient_mock.get( "http://127.0.0.1/resolution/info", @@ -80,7 +81,9 @@ def mock_resolution_info( ) -def assert_repair_in_list(issues: list[dict[str, Any]], unhealthy: bool, reason: str): +def assert_repair_in_list( + issues: list[dict[str, Any]], unhealthy: bool, reason: str +) -> None: """Assert repair for unhealthy/unsupported in list.""" repair_type = "unhealthy" if unhealthy else "unsupported" assert { @@ -108,7 +111,7 @@ def assert_issue_repair_in_list( *, reference: str | None = None, placeholders: dict[str, str] | None = None, -): +) -> None: """Assert repair for unhealthy/unsupported in list.""" if reference: placeholders = (placeholders or {}) | {"reference": reference} @@ -128,11 +131,11 @@ def assert_issue_repair_in_list( } in issues +@pytest.mark.usefixtures("all_setup_requests") async def test_unhealthy_issues( hass: HomeAssistant, aioclient_mock: AiohttpClientMocker, hass_ws_client: WebSocketGenerator, - all_setup_requests, ) -> None: """Test issues added for unhealthy systems.""" mock_resolution_info(aioclient_mock, unhealthy=["docker", "setup"]) @@ -150,11 +153,11 @@ async def test_unhealthy_issues( assert_repair_in_list(msg["result"]["issues"], unhealthy=True, reason="setup") +@pytest.mark.usefixtures("all_setup_requests") async def test_unsupported_issues( hass: HomeAssistant, aioclient_mock: AiohttpClientMocker, hass_ws_client: WebSocketGenerator, - all_setup_requests, ) -> None: """Test issues added for unsupported systems.""" mock_resolution_info(aioclient_mock, unsupported=["content_trust", "os"]) @@ -174,11 +177,11 @@ async def test_unsupported_issues( assert_repair_in_list(msg["result"]["issues"], unhealthy=False, reason="os") +@pytest.mark.usefixtures("all_setup_requests") async def test_unhealthy_issues_add_remove( hass: HomeAssistant, aioclient_mock: AiohttpClientMocker, hass_ws_client: WebSocketGenerator, - all_setup_requests, ) -> None: """Test unhealthy issues added and removed from dispatches.""" mock_resolution_info(aioclient_mock) @@ -231,11 +234,11 @@ async def test_unhealthy_issues_add_remove( assert msg["result"] == {"issues": []} +@pytest.mark.usefixtures("all_setup_requests") async def test_unsupported_issues_add_remove( hass: HomeAssistant, aioclient_mock: AiohttpClientMocker, hass_ws_client: WebSocketGenerator, - all_setup_requests, ) -> None: """Test unsupported issues added and removed from dispatches.""" mock_resolution_info(aioclient_mock) @@ -288,11 +291,11 @@ async def test_unsupported_issues_add_remove( assert msg["result"] == {"issues": []} +@pytest.mark.usefixtures("all_setup_requests") async def test_reset_issues_supervisor_restart( hass: HomeAssistant, aioclient_mock: AiohttpClientMocker, hass_ws_client: WebSocketGenerator, - all_setup_requests, ) -> None: """All issues reset on supervisor restart.""" mock_resolution_info( @@ -352,11 +355,11 @@ async def test_reset_issues_supervisor_restart( assert msg["result"] == {"issues": []} +@pytest.mark.usefixtures("all_setup_requests") async def test_reasons_added_and_removed( hass: HomeAssistant, aioclient_mock: AiohttpClientMocker, hass_ws_client: WebSocketGenerator, - all_setup_requests, ) -> None: """Test an unsupported/unhealthy reasons being added and removed at same time.""" mock_resolution_info(aioclient_mock, unsupported=["os"], unhealthy=["docker"]) @@ -402,11 +405,11 @@ async def test_reasons_added_and_removed( ) +@pytest.mark.usefixtures("all_setup_requests") async def test_ignored_unsupported_skipped( hass: HomeAssistant, aioclient_mock: AiohttpClientMocker, hass_ws_client: WebSocketGenerator, - all_setup_requests, ) -> None: """Unsupported reasons which have an identical unhealthy reason are ignored.""" mock_resolution_info( @@ -425,11 +428,11 @@ async def test_ignored_unsupported_skipped( assert_repair_in_list(msg["result"]["issues"], unhealthy=True, reason="privileged") +@pytest.mark.usefixtures("all_setup_requests") async def test_new_unsupported_unhealthy_reason( hass: HomeAssistant, aioclient_mock: AiohttpClientMocker, hass_ws_client: WebSocketGenerator, - all_setup_requests, ) -> None: """New unsupported/unhealthy reasons result in a generic repair until next core update.""" mock_resolution_info( @@ -475,11 +478,11 @@ async def test_new_unsupported_unhealthy_reason( } in msg["result"]["issues"] +@pytest.mark.usefixtures("all_setup_requests") async def test_supervisor_issues( hass: HomeAssistant, aioclient_mock: AiohttpClientMocker, hass_ws_client: WebSocketGenerator, - all_setup_requests, ) -> None: """Test repairs added for supervisor issue.""" mock_resolution_info( @@ -541,12 +544,12 @@ async def test_supervisor_issues( ) +@pytest.mark.usefixtures("all_setup_requests") async def test_supervisor_issues_initial_failure( hass: HomeAssistant, aioclient_mock: AiohttpClientMocker, hass_ws_client: WebSocketGenerator, freezer: FrozenDateTimeFactory, - all_setup_requests, ) -> None: """Test issues manager retries after initial update failure.""" responses = [ @@ -619,11 +622,11 @@ async def test_supervisor_issues_initial_failure( assert len(msg["result"]["issues"]) == 1 +@pytest.mark.usefixtures("all_setup_requests") async def test_supervisor_issues_add_remove( hass: HomeAssistant, aioclient_mock: AiohttpClientMocker, hass_ws_client: WebSocketGenerator, - all_setup_requests, ) -> None: """Test supervisor issues added and removed from dispatches.""" mock_resolution_info(aioclient_mock) @@ -730,11 +733,11 @@ async def test_supervisor_issues_add_remove( assert msg["result"] == {"issues": []} +@pytest.mark.usefixtures("all_setup_requests") async def test_supervisor_issues_suggestions_fail( hass: HomeAssistant, aioclient_mock: AiohttpClientMocker, hass_ws_client: WebSocketGenerator, - all_setup_requests, ) -> None: """Test failing to get suggestions for issue skips it.""" aioclient_mock.get( @@ -776,11 +779,11 @@ async def test_supervisor_issues_suggestions_fail( assert len(msg["result"]["issues"]) == 0 +@pytest.mark.usefixtures("all_setup_requests") async def test_supervisor_remove_missing_issue_without_error( hass: HomeAssistant, aioclient_mock: AiohttpClientMocker, hass_ws_client: WebSocketGenerator, - all_setup_requests, ) -> None: """Test HA skips message to remove issue that it didn't know about (sync issue).""" mock_resolution_info(aioclient_mock) @@ -810,11 +813,11 @@ async def test_supervisor_remove_missing_issue_without_error( await hass.async_block_till_done() +@pytest.mark.usefixtures("all_setup_requests") async def test_system_is_not_ready( hass: HomeAssistant, aioclient_mock: AiohttpClientMocker, caplog: pytest.LogCaptureFixture, - all_setup_requests, ) -> None: """Ensure hassio starts despite error.""" aioclient_mock.get( @@ -832,11 +835,11 @@ async def test_system_is_not_ready( @pytest.mark.parametrize( "all_setup_requests", [{"include_addons": True}], indirect=True ) +@pytest.mark.usefixtures("all_setup_requests") async def test_supervisor_issues_detached_addon_missing( hass: HomeAssistant, aioclient_mock: AiohttpClientMocker, hass_ws_client: WebSocketGenerator, - all_setup_requests, ) -> None: """Test supervisor issue for detached addon due to missing repository.""" mock_resolution_info(aioclient_mock) diff --git a/tests/components/hassio/test_repairs.py b/tests/components/hassio/test_repairs.py index 8d0bbfac87c..907529ec9c4 100644 --- a/tests/components/hassio/test_repairs.py +++ b/tests/components/hassio/test_repairs.py @@ -1,5 +1,6 @@ """Test supervisor repairs.""" +from collections.abc import Generator from http import HTTPStatus import os from unittest.mock import patch @@ -18,18 +19,18 @@ from tests.typing import ClientSessionGenerator @pytest.fixture(autouse=True) -async def fixture_supervisor_environ(): +def fixture_supervisor_environ() -> Generator[None]: """Mock os environ for supervisor.""" with patch.dict(os.environ, MOCK_ENVIRON): yield +@pytest.mark.usefixtures("all_setup_requests") async def test_supervisor_issue_repair_flow( hass: HomeAssistant, aioclient_mock: AiohttpClientMocker, hass_client: ClientSessionGenerator, issue_registry: ir.IssueRegistry, - all_setup_requests, ) -> None: """Test fix flow for supervisor issue.""" mock_resolution_info( @@ -103,12 +104,12 @@ async def test_supervisor_issue_repair_flow( ) +@pytest.mark.usefixtures("all_setup_requests") async def test_supervisor_issue_repair_flow_with_multiple_suggestions( hass: HomeAssistant, aioclient_mock: AiohttpClientMocker, hass_client: ClientSessionGenerator, issue_registry: ir.IssueRegistry, - all_setup_requests, ) -> None: """Test fix flow for supervisor issue with multiple suggestions.""" mock_resolution_info( @@ -197,12 +198,12 @@ async def test_supervisor_issue_repair_flow_with_multiple_suggestions( ) +@pytest.mark.usefixtures("all_setup_requests") async def test_supervisor_issue_repair_flow_with_multiple_suggestions_and_confirmation( hass: HomeAssistant, aioclient_mock: AiohttpClientMocker, hass_client: ClientSessionGenerator, issue_registry: ir.IssueRegistry, - all_setup_requests, ) -> None: """Test fix flow for supervisor issue with multiple suggestions and choice requires confirmation.""" mock_resolution_info( @@ -310,12 +311,12 @@ async def test_supervisor_issue_repair_flow_with_multiple_suggestions_and_confir ) +@pytest.mark.usefixtures("all_setup_requests") async def test_supervisor_issue_repair_flow_skip_confirmation( hass: HomeAssistant, aioclient_mock: AiohttpClientMocker, hass_client: ClientSessionGenerator, issue_registry: ir.IssueRegistry, - all_setup_requests, ) -> None: """Test confirmation skipped for fix flow for supervisor issue with one suggestion.""" mock_resolution_info( @@ -389,12 +390,12 @@ async def test_supervisor_issue_repair_flow_skip_confirmation( ) +@pytest.mark.usefixtures("all_setup_requests") async def test_mount_failed_repair_flow_error( hass: HomeAssistant, aioclient_mock: AiohttpClientMocker, hass_client: ClientSessionGenerator, issue_registry: ir.IssueRegistry, - all_setup_requests, ) -> None: """Test repair flow fails when repair fails to apply.""" mock_resolution_info( @@ -461,12 +462,12 @@ async def test_mount_failed_repair_flow_error( assert issue_registry.async_get_issue(domain="hassio", issue_id="1234") +@pytest.mark.usefixtures("all_setup_requests") async def test_mount_failed_repair_flow( hass: HomeAssistant, aioclient_mock: AiohttpClientMocker, hass_client: ClientSessionGenerator, issue_registry: ir.IssueRegistry, - all_setup_requests, ) -> None: """Test repair flow for mount_failed issue.""" mock_resolution_info( @@ -562,12 +563,12 @@ async def test_mount_failed_repair_flow( @pytest.mark.parametrize( "all_setup_requests", [{"include_addons": True}], indirect=True ) +@pytest.mark.usefixtures("all_setup_requests") async def test_supervisor_issue_docker_config_repair_flow( hass: HomeAssistant, aioclient_mock: AiohttpClientMocker, hass_client: ClientSessionGenerator, issue_registry: ir.IssueRegistry, - all_setup_requests, ) -> None: """Test fix flow for supervisor issue.""" mock_resolution_info( @@ -669,12 +670,12 @@ async def test_supervisor_issue_docker_config_repair_flow( ) +@pytest.mark.usefixtures("all_setup_requests") async def test_supervisor_issue_repair_flow_multiple_data_disks( hass: HomeAssistant, aioclient_mock: AiohttpClientMocker, hass_client: ClientSessionGenerator, issue_registry: ir.IssueRegistry, - all_setup_requests, ) -> None: """Test fix flow for multiple data disks supervisor issue.""" mock_resolution_info( @@ -785,12 +786,12 @@ async def test_supervisor_issue_repair_flow_multiple_data_disks( @pytest.mark.parametrize( "all_setup_requests", [{"include_addons": True}], indirect=True ) +@pytest.mark.usefixtures("all_setup_requests") async def test_supervisor_issue_detached_addon_removed( hass: HomeAssistant, aioclient_mock: AiohttpClientMocker, hass_client: ClientSessionGenerator, issue_registry: ir.IssueRegistry, - all_setup_requests, ) -> None: """Test fix flow for supervisor issue.""" mock_resolution_info( diff --git a/tests/components/hassio/test_websocket_api.py b/tests/components/hassio/test_websocket_api.py index f3be391d9b7..7d8f07bfaec 100644 --- a/tests/components/hassio/test_websocket_api.py +++ b/tests/components/hassio/test_websocket_api.py @@ -79,8 +79,9 @@ def mock_all(aioclient_mock: AiohttpClientMocker) -> None: ) +@pytest.mark.usefixtures("hassio_env") async def test_ws_subscription( - hassio_env, hass: HomeAssistant, hass_ws_client: WebSocketGenerator + hass: HomeAssistant, hass_ws_client: WebSocketGenerator ) -> None: """Test websocket subscription.""" assert await async_setup_component(hass, "hassio", {}) @@ -116,8 +117,8 @@ async def test_ws_subscription( assert response["success"] +@pytest.mark.usefixtures("hassio_env") async def test_websocket_supervisor_api( - hassio_env, hass: HomeAssistant, hass_ws_client: WebSocketGenerator, aioclient_mock: AiohttpClientMocker, @@ -160,8 +161,8 @@ async def test_websocket_supervisor_api( } +@pytest.mark.usefixtures("hassio_env") async def test_websocket_supervisor_api_error( - hassio_env, hass: HomeAssistant, hass_ws_client: WebSocketGenerator, aioclient_mock: AiohttpClientMocker, @@ -189,8 +190,8 @@ async def test_websocket_supervisor_api_error( assert msg["error"]["message"] == "example error" +@pytest.mark.usefixtures("hassio_env") async def test_websocket_supervisor_api_error_without_msg( - hassio_env, hass: HomeAssistant, hass_ws_client: WebSocketGenerator, aioclient_mock: AiohttpClientMocker, @@ -218,8 +219,8 @@ async def test_websocket_supervisor_api_error_without_msg( assert msg["error"]["message"] == "" +@pytest.mark.usefixtures("hassio_env") async def test_websocket_non_admin_user( - hassio_env, hass: HomeAssistant, hass_ws_client: WebSocketGenerator, aioclient_mock: AiohttpClientMocker,