Improve type hints in hassio tests (#121221)

This commit is contained in:
epenet 2024-07-05 09:05:21 +02:00 committed by GitHub
parent dcef25c0fa
commit b054c037fe
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 135 additions and 97 deletions

View File

@ -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")

View File

@ -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."""

View File

@ -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",

View File

@ -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(

View File

@ -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):

View File

@ -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")

View File

@ -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()

View File

@ -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)

View File

@ -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(

View File

@ -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,