diff --git a/tests/components/mqtt/conftest.py b/tests/components/mqtt/conftest.py index ebe86c1f1df..91ece381f6d 100644 --- a/tests/components/mqtt/conftest.py +++ b/tests/components/mqtt/conftest.py @@ -1,5 +1,9 @@ """Test fixtures for mqtt component.""" +from collections.abc import Generator +from random import getrandbits +from unittest.mock import patch + import pytest from tests.components.light.conftest import mock_light_profiles # noqa: F401 @@ -8,3 +12,20 @@ from tests.components.light.conftest import mock_light_profiles # noqa: F401 @pytest.fixture(autouse=True) def patch_hass_config(mock_hass_config: None) -> None: """Patch configuration.yaml.""" + + +@pytest.fixture +def temp_dir_prefix() -> str: + """Set an alternate temp dir prefix.""" + return "test" + + +@pytest.fixture +def mock_temp_dir(temp_dir_prefix: str) -> Generator[None, None, str]: + """Mock the certificate temp directory.""" + with patch( + # Patch temp dir name to avoid tests fail running in parallel + "homeassistant.components.mqtt.util.TEMP_DIR_NAME", + f"home-assistant-mqtt-{temp_dir_prefix}-{getrandbits(10):03x}", + ) as mocked_temp_dir: + yield mocked_temp_dir diff --git a/tests/components/mqtt/test_config_flow.py b/tests/components/mqtt/test_config_flow.py index f0681a537da..c2a7e0065ce 100644 --- a/tests/components/mqtt/test_config_flow.py +++ b/tests/components/mqtt/test_config_flow.py @@ -2,7 +2,6 @@ from collections.abc import Generator, Iterator from contextlib import contextmanager from pathlib import Path -from random import getrandbits from ssl import SSLError from typing import Any from unittest.mock import AsyncMock, MagicMock, patch @@ -131,7 +130,9 @@ def mock_try_connection_time_out() -> Generator[MagicMock, None, None]: @pytest.fixture -def mock_process_uploaded_file(tmp_path: Path) -> Generator[MagicMock, None, None]: +def mock_process_uploaded_file( + tmp_path: Path, mock_temp_dir: str +) -> Generator[MagicMock, None, None]: """Mock upload certificate files.""" file_id_ca = str(uuid4()) file_id_cert = str(uuid4()) @@ -159,11 +160,7 @@ def mock_process_uploaded_file(tmp_path: Path) -> Generator[MagicMock, None, Non with patch( "homeassistant.components.mqtt.config_flow.process_uploaded_file", side_effect=_mock_process_uploaded_file, - ) as mock_upload, patch( - # Patch temp dir name to avoid tests fail running in parallel - "homeassistant.components.mqtt.util.TEMP_DIR_NAME", - "home-assistant-mqtt" + f"-{getrandbits(10):03x}", - ): + ) as mock_upload: mock_upload.file_id = { mqtt.CONF_CERTIFICATE: file_id_ca, mqtt.CONF_CLIENT_CERT: file_id_cert, diff --git a/tests/components/mqtt/test_util.py b/tests/components/mqtt/test_util.py index e93a5e376bb..941072bc224 100644 --- a/tests/components/mqtt/test_util.py +++ b/tests/components/mqtt/test_util.py @@ -1,7 +1,9 @@ """Test MQTT utils.""" from collections.abc import Callable +from pathlib import Path from random import getrandbits +import tempfile from unittest.mock import patch import pytest @@ -14,17 +16,6 @@ from tests.common import MockConfigEntry from tests.typing import MqttMockHAClient, MqttMockPahoClient -@pytest.fixture(autouse=True) -def mock_temp_dir(): - """Mock the certificate temp directory.""" - with patch( - # Patch temp dir name to avoid tests fail running in parallel - "homeassistant.components.mqtt.util.TEMP_DIR_NAME", - "home-assistant-mqtt" + f"-{getrandbits(10):03x}", - ) as mocked_temp_dir: - yield mocked_temp_dir - - @pytest.mark.parametrize( ("option", "content", "file_created"), [ @@ -34,31 +25,50 @@ def mock_temp_dir(): (mqtt.CONF_CLIENT_KEY, "### PRIVATE KEY ###", True), ], ) +@pytest.mark.parametrize("temp_dir_prefix", ["create-test"]) async def test_async_create_certificate_temp_files( - hass: HomeAssistant, mock_temp_dir, option, content, file_created + hass: HomeAssistant, + mock_temp_dir: str, + option: str, + content: str, + file_created: bool, ) -> None: """Test creating and reading and recovery certificate files.""" config = {option: content} - await mqtt.util.async_create_certificate_temp_files(hass, config) - file_path = mqtt.util.get_file_path(option) + temp_dir = Path(tempfile.gettempdir()) / mock_temp_dir + + # Create old file to be able to assert it is removed with auto option + def _ensure_old_file_exists() -> None: + if not temp_dir.exists(): + temp_dir.mkdir(0o700) + temp_file = temp_dir / option + with open(temp_file, "wb") as old_file: + old_file.write(b"old content") + old_file.close() + + await hass.async_add_executor_job(_ensure_old_file_exists) + await mqtt.util.async_create_certificate_temp_files(hass, config) + file_path = await hass.async_add_executor_job(mqtt.util.get_file_path, option) assert bool(file_path) is file_created assert ( - mqtt.util.migrate_certificate_file_to_content(file_path or content) == content + await hass.async_add_executor_job( + mqtt.util.migrate_certificate_file_to_content, file_path or content + ) + == content ) # Make sure certificate temp files are recovered - if file_path: - # Overwrite content of file (except for auto option) - file = open(file_path, "wb") - file.write(b"invalid") - file.close() + await hass.async_add_executor_job(_ensure_old_file_exists) await mqtt.util.async_create_certificate_temp_files(hass, config) - file_path2 = mqtt.util.get_file_path(option) + file_path2 = await hass.async_add_executor_job(mqtt.util.get_file_path, option) assert bool(file_path2) is file_created assert ( - mqtt.util.migrate_certificate_file_to_content(file_path2 or content) == content + await hass.async_add_executor_job( + mqtt.util.migrate_certificate_file_to_content, file_path2 or content + ) + == content ) assert file_path == file_path2 @@ -71,6 +81,26 @@ async def test_reading_non_exitisting_certificate_file() -> None: ) +@pytest.mark.parametrize("temp_dir_prefix", "unknown") +async def test_return_default_get_file_path( + hass: HomeAssistant, mock_temp_dir: str +) -> None: + """Test get_file_path returns default.""" + + def _get_file_path(file_path: Path) -> bool: + return ( + not file_path.exists() + and mqtt.util.get_file_path("some_option", "mydefault") == "mydefault" + ) + + with patch( + "homeassistant.components.mqtt.util.TEMP_DIR_NAME", + f"home-assistant-mqtt-other-{getrandbits(10):03x}", + ) as mock_temp_dir: + tempdir = Path(tempfile.gettempdir()) / mock_temp_dir + assert await hass.async_add_executor_job(_get_file_path, tempdir) + + @patch("homeassistant.components.mqtt.PLATFORMS", []) async def test_waiting_for_client_not_loaded( hass: HomeAssistant,