aboutsummaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorBenjamin Klimczak <benjamin.klimczak@arm.com>2024-03-21 17:33:17 +0000
committerBenjamin Klimczak <benjamin.klimczak@arm.com>2024-03-22 10:06:28 +0000
commitc7ee5b783f044d7ff641773aa385840f5ff944cc (patch)
tree297f308978b00282d8ebd3a1f71e1ae5e678a767 /tests
parent508281df31dc3c18f2e007f4dd505160342a681a (diff)
downloadmlia-c7ee5b783f044d7ff641773aa385840f5ff944cc.tar.gz
refactor: Backend dependencies and more
- Add backend dependencies: One backend can now depend on another backend. - Re-factor 'DownloadArtifact': - Rename 'DownloadArtifact' to 'DownloadConfig' - Remove attributes 'name' and 'version' not relevant for downloads - Add helper properties: - 'filename' parses the URL to extract the file name from the end - 'headers' calls the function to generate a HTML header for the download - Add OutputLogger helper class - Re-factor handling of backend configurations in the target profiles. Change-Id: Ifda6cf12c375d0c1747d7e4130a0370d22c3d33a Signed-off-by: Benjamin Klimczak <benjamin.klimczak@arm.com>
Diffstat (limited to 'tests')
-rw-r--r--tests/test_backend_install.py13
-rw-r--r--tests/test_backend_manager.py149
-rw-r--r--tests/test_utils_download.py35
3 files changed, 149 insertions, 48 deletions
diff --git a/tests/test_backend_install.py b/tests/test_backend_install.py
index 963766e..3636fb4 100644
--- a/tests/test_backend_install.py
+++ b/tests/test_backend_install.py
@@ -20,6 +20,7 @@ from mlia.backend.install import InstallFromPath
from mlia.backend.install import PackagePathChecker
from mlia.backend.install import StaticPathChecker
from mlia.backend.repo import BackendRepository
+from mlia.utils.download import DownloadConfig
@pytest.fixture(name="backend_repo")
@@ -104,11 +105,9 @@ def test_backend_installation_from_path(
def test_backend_installation_download_and_install(
- tmp_path: Path, backend_repo: MagicMock
+ tmp_path: Path, backend_repo: MagicMock, monkeypatch: pytest.MonkeyPatch
) -> None:
"""Test methods of backend installation."""
- download_artifact_mock = MagicMock()
-
tmp_archive = tmp_path.joinpath("sample.tgz")
sample_file = tmp_path.joinpath("sample.txt")
sample_file.touch()
@@ -116,13 +115,17 @@ def test_backend_installation_download_and_install(
with tarfile.open(tmp_archive, "w:gz") as archive:
archive.add(sample_file)
- download_artifact_mock.download_to.return_value = tmp_archive
+ monkeypatch.setattr("mlia.backend.install.download", MagicMock())
+ monkeypatch.setattr(
+ "mlia.utils.download.DownloadConfig.filename",
+ tmp_archive,
+ )
installation = BackendInstallation(
"sample_backend",
"Sample backend",
"sample_backend",
- download_artifact_mock,
+ DownloadConfig(url="NOT_USED", sha256_hash="NOT_USED"),
None,
lambda path: BackendInfo(path, copy_source=False),
lambda eula_agreement, path: path,
diff --git a/tests/test_backend_manager.py b/tests/test_backend_manager.py
index 879353e..63c11ee 100644
--- a/tests/test_backend_manager.py
+++ b/tests/test_backend_manager.py
@@ -3,6 +3,7 @@
"""Tests for installation manager."""
from __future__ import annotations
+from functools import partial
from pathlib import Path
from typing import Any
from unittest.mock import call
@@ -23,6 +24,7 @@ from mlia.core.errors import InternalError
def get_default_installation_manager_mock(
name: str,
already_installed: bool = False,
+ dependencies: list[str] | None = None,
) -> MagicMock:
"""Get mock instance for DefaultInstallationManager."""
mock = MagicMock(spec=DefaultInstallationManager)
@@ -30,6 +32,7 @@ def get_default_installation_manager_mock(
props = {
"name": name,
"already_installed": already_installed,
+ "dependencies": dependencies if dependencies else [],
}
for prop, value in props.items():
setattr(type(mock), prop, PropertyMock(return_value=value))
@@ -49,6 +52,7 @@ def get_installation_mock(
already_installed: bool = False,
could_be_installed: bool = False,
supported_install_type: type | tuple | None = None,
+ dependencies: list[str] | None = None,
) -> MagicMock:
"""Get mock instance for the installation."""
mock = MagicMock(spec=Installation)
@@ -65,6 +69,7 @@ def get_installation_mock(
"name": name,
"already_installed": already_installed,
"could_be_installed": could_be_installed,
+ "dependencies": dependencies if dependencies else [],
}
for prop, value in props.items():
setattr(type(mock), prop, PropertyMock(return_value=value))
@@ -72,38 +77,45 @@ def get_installation_mock(
return mock
-def _already_installed_mock() -> MagicMock:
- return get_installation_mock(
- name="already_installed",
- already_installed=True,
- supported_install_type=(DownloadAndInstall, InstallFromPath),
- )
+_already_installed_mock = partial(
+ get_installation_mock,
+ name="already_installed",
+ already_installed=True,
+ supported_install_type=(DownloadAndInstall, InstallFromPath),
+)
-def _ready_for_installation_mock() -> MagicMock:
- return get_installation_mock(
- name="ready_for_installation",
- already_installed=False,
- could_be_installed=True,
- )
+_ready_for_installation_mock = partial(
+ get_installation_mock,
+ name="ready_for_installation",
+ already_installed=False,
+ could_be_installed=True,
+)
-def _could_be_downloaded_and_installed_mock() -> MagicMock:
- return get_installation_mock(
- name="could_be_downloaded_and_installed",
- already_installed=False,
- could_be_installed=True,
- supported_install_type=DownloadAndInstall,
- )
+_could_be_downloaded_and_installed_mock = partial(
+ get_installation_mock,
+ name="could_be_downloaded_and_installed",
+ already_installed=False,
+ could_be_installed=True,
+ supported_install_type=DownloadAndInstall,
+)
-def _could_be_installed_from_mock() -> MagicMock:
- return get_installation_mock(
- name="could_be_installed_from",
- already_installed=False,
- could_be_installed=True,
- supported_install_type=InstallFromPath,
- )
+_could_be_installed_from_mock = partial(
+ get_installation_mock,
+ name="could_be_installed_from",
+ already_installed=False,
+ could_be_installed=True,
+ supported_install_type=InstallFromPath,
+)
+
+_already_installed_dep_mock = partial(
+ get_installation_mock,
+ name="already_installed_dep",
+ already_installed=True,
+ supported_install_type=(DownloadAndInstall, InstallFromPath),
+)
def get_installation_manager(
@@ -114,13 +126,23 @@ def get_installation_manager(
) -> DefaultInstallationManager:
"""Get installation manager instance."""
if not noninteractive:
- monkeypatch.setattr(
- "mlia.backend.manager.yes", MagicMock(return_value=yes_response)
+ return get_interactive_installation_manager(
+ installations, monkeypatch, MagicMock(return_value=yes_response)
)
return DefaultInstallationManager(installations, noninteractive=noninteractive)
+def get_interactive_installation_manager(
+ installations: list[Any],
+ monkeypatch: pytest.MonkeyPatch,
+ mock_interaction: MagicMock,
+) -> DefaultInstallationManager:
+ """Get and interactive installation manager instance using the given mock."""
+ monkeypatch.setattr("mlia.backend.manager.yes", mock_interaction)
+ return DefaultInstallationManager(installations, noninteractive=False)
+
+
def test_installation_manager_filtering() -> None:
"""Test default installation manager."""
already_installed = _already_installed_mock()
@@ -337,3 +359,74 @@ def test_show_env_details(monkeypatch: pytest.MonkeyPatch) -> None:
monkeypatch,
)
manager.show_env_details()
+
+
+@pytest.mark.parametrize(
+ "dependency",
+ (
+ _ready_for_installation_mock(),
+ _already_installed_mock(),
+ ),
+)
+@pytest.mark.parametrize("yes_response", (True, False))
+def test_could_be_installed_with_dep(
+ dependency: MagicMock,
+ yes_response: bool,
+ tmp_path: Path,
+ monkeypatch: pytest.MonkeyPatch,
+) -> None:
+ """Test installation with a dependency."""
+ install_mock = _could_be_installed_from_mock(dependencies=[dependency.name])
+
+ yes_mock = MagicMock(return_value=yes_response)
+ manager = get_interactive_installation_manager(
+ [install_mock, dependency], monkeypatch, yes_mock
+ )
+ manager.install_from(tmp_path, install_mock.name)
+
+ if yes_response:
+ install_mock.install.assert_called_once()
+ else:
+ install_mock.install.assert_not_called()
+ install_mock.uninstall.assert_not_called()
+
+ dependency.install.assert_not_called()
+ dependency.uninstall.assert_not_called()
+
+
+def test_install_with_unknown_dep(
+ tmp_path: Path,
+ monkeypatch: pytest.MonkeyPatch,
+) -> None:
+ """Test installation with an unknown dependency."""
+ install_mock = _could_be_installed_from_mock(dependencies=["UNKNOWN_BACKEND"])
+
+ manager = get_installation_manager(False, [install_mock], monkeypatch)
+ with pytest.raises(ValueError):
+ manager.install_from(tmp_path, install_mock.name)
+
+ install_mock.install.assert_not_called()
+ install_mock.uninstall.assert_not_called()
+
+
+@pytest.mark.parametrize("yes_response", (True, False))
+def test_uninstall_with_dep(
+ yes_response: bool, monkeypatch: pytest.MonkeyPatch
+) -> None:
+ """Test uninstalling a backend with a dependency."""
+ dependency = _already_installed_dep_mock()
+ install_mock = _already_installed_mock(dependencies=[dependency.name])
+ yes_mock = MagicMock(return_value=yes_response)
+ manager = get_interactive_installation_manager(
+ [install_mock, dependency], monkeypatch, yes_mock
+ )
+ manager.uninstall(install_mock.name)
+
+ install_mock.install.assert_not_called()
+ if yes_response:
+ install_mock.uninstall.assert_called_once()
+ else:
+ install_mock.uninstall.assert_not_called()
+
+ dependency.install.assert_not_called()
+ dependency.uninstall.assert_not_called()
diff --git a/tests/test_utils_download.py b/tests/test_utils_download.py
index 28af74f..7188c62 100644
--- a/tests/test_utils_download.py
+++ b/tests/test_utils_download.py
@@ -1,8 +1,9 @@
-# SPDX-FileCopyrightText: Copyright 2022, Arm Limited and/or its affiliates.
+# SPDX-FileCopyrightText: Copyright 2023, Arm Limited and/or its affiliates.
# SPDX-License-Identifier: Apache-2.0
"""Tests for download functionality."""
from __future__ import annotations
+import hashlib
from contextlib import ExitStack as does_not_raise
from pathlib import Path
from typing import Any
@@ -14,7 +15,7 @@ import pytest
import requests
from mlia.utils.download import download
-from mlia.utils.download import DownloadArtifact
+from mlia.utils.download import DownloadConfig
def response_mock(
@@ -69,9 +70,18 @@ def test_download(
"mlia.utils.download.requests.get",
MagicMock(return_value=response_mock(content_length, content_chunks)),
)
+ hash_obj = hashlib.sha256()
+ for chunk in content_chunks:
+ hash_obj.update(chunk)
+ sha256_hash = hash_obj.hexdigest()
dest = tmp_path / "sample.bin"
- download("some_url", dest, show_progress=show_progress, label=label)
+ download(
+ dest,
+ DownloadConfig("some_url", sha256_hash=sha256_hash),
+ show_progress=show_progress,
+ label=label,
+ )
assert dest.is_file()
assert dest.read_bytes() == bytes(
@@ -92,7 +102,7 @@ def test_download(
"10",
[bytes(range(10))],
"bad_hash",
- pytest.raises(ValueError, match="Digests do not match"),
+ pytest.raises(ValueError, match="Hashes do not match."),
],
],
)
@@ -111,15 +121,13 @@ def test_download_artifact_download_to(
)
with expected_error:
- artifact = DownloadArtifact(
- "test_artifact",
+ cfg = DownloadConfig(
"some_url",
- "artifact_filename",
- "1.0",
sha256_hash,
)
- dest = artifact.download_to(tmp_path)
+ dest = tmp_path / "artifact_filename"
+ download(dest, cfg)
assert isinstance(dest, Path)
assert dest.name == "artifact_filename"
@@ -133,16 +141,13 @@ def test_download_artifact_unable_to_overwrite(
MagicMock(return_value=response_mock("10", [bytes(range(10))])),
)
- artifact = DownloadArtifact(
- "test_artifact",
+ cfg = DownloadConfig(
"some_url",
- "artifact_filename",
- "1.0",
"sha256_hash",
)
existing_file = tmp_path / "artifact_filename"
existing_file.touch()
- with pytest.raises(ValueError, match=f"{existing_file} already exists"):
- artifact.download_to(tmp_path)
+ with pytest.raises(FileExistsError, match=f"{existing_file} already exists."):
+ download(existing_file, cfg)