diff --git a/dem/cli/command/clone_cmd.py b/dem/cli/command/clone_cmd.py index ed7d0e2..8ffe32a 100644 --- a/dem/cli/command/clone_cmd.py +++ b/dem/cli/command/clone_cmd.py @@ -21,7 +21,8 @@ def handle_existing_local_dev_env(platform: Platform, local_dev_env: DevEnv) -> typer.confirm("The Dev Env to overwrite is installed. Do you want to uninstall it?", abort=True) try: - platform.uninstall_dev_env(local_dev_env) + for status in platform.uninstall_dev_env(local_dev_env): + stdout.print(status) except PlatformError as e: stderr.print(f"[red]{str(e)}[/]") raise typer.Abort() diff --git a/dem/cli/command/create_cmd.py b/dem/cli/command/create_cmd.py index 0ac2a76..ca7ec55 100644 --- a/dem/cli/command/create_cmd.py +++ b/dem/cli/command/create_cmd.py @@ -92,7 +92,8 @@ def create_dev_env(platform: Platform, dev_env_name: str) -> None: typer.confirm("The Development Environment is installed, so it can't be overwritten. " + \ "Uninstall it first?", abort=True) try: - platform.uninstall_dev_env(dev_env_original) + for status in platform.uninstall_dev_env(dev_env_original): + stdout.print(status) except PlatformError as e: stderr.print(f"[red]{str(e)}[/]") raise typer.Abort() diff --git a/dem/cli/command/delete_cmd.py b/dem/cli/command/delete_cmd.py index be24e1c..3eaea92 100644 --- a/dem/cli/command/delete_cmd.py +++ b/dem/cli/command/delete_cmd.py @@ -20,12 +20,13 @@ def execute(platform: Platform, dev_env_name: str) -> None: abort=True) try: - platform.uninstall_dev_env(dev_env_to_delete) + for status in platform.uninstall_dev_env(dev_env_to_delete): + stdout.print(status) except PlatformError as e: stderr.print(f"[red]{str(e)}[/]") return - stdout.print("Deleting the Development Environment...") + stdout.print("Deleting the Development Environment descriptor...") platform.local_dev_envs.remove(dev_env_to_delete) platform.flush_dev_env_properties() stdout.print(f"[green]Successfully deleted the {dev_env_name}![/]") \ No newline at end of file diff --git a/dem/cli/command/init_cmd.py b/dem/cli/command/init_cmd.py index fa7855a..6653b06 100644 --- a/dem/cli/command/init_cmd.py +++ b/dem/cli/command/init_cmd.py @@ -34,7 +34,8 @@ def execute(platform: Platform, project_path: str) -> None: abort=True) try: - platform.uninstall_dev_env(local_dev_env) + for status in platform.uninstall_dev_env(local_dev_env): + stdout.print(status) except PlatformError as e: stderr.print(f"[red]{str(e)}[/]") return diff --git a/dem/cli/command/modify_cmd.py b/dem/cli/command/modify_cmd.py index 2a1c865..6eed69a 100644 --- a/dem/cli/command/modify_cmd.py +++ b/dem/cli/command/modify_cmd.py @@ -177,7 +177,8 @@ def execute(platform: Platform, dev_env_name: str) -> None: stdout.print("[yellow]The Development Environment is installed, so it can't be modified.[/]") typer.confirm("Do you want to uninstall it first?", abort=True) try: - platform.uninstall_dev_env(dev_env) + for status in platform.uninstall_dev_env(dev_env): + stdout.print(status) except PlatformError as e: stderr.print(f"[red]{str(e)}[/]") return diff --git a/dem/cli/command/uninstall_cmd.py b/dem/cli/command/uninstall_cmd.py index 04567fd..f9847fc 100644 --- a/dem/cli/command/uninstall_cmd.py +++ b/dem/cli/command/uninstall_cmd.py @@ -23,7 +23,8 @@ def execute(platform: Platform, dev_env_name: str) -> None: stderr.print(f"[red]Error: The {dev_env_name} Development Environment is not installed.[/]") else: try: - platform.uninstall_dev_env(dev_env_to_uninstall) + for status in platform.uninstall_dev_env(dev_env_to_uninstall): + stdout.print(status) except PlatformError as e: stderr.print(f"[red]{str(e)}[/]") else: diff --git a/dem/core/container_engine.py b/dem/core/container_engine.py index c21389a..c52cf9b 100644 --- a/dem/core/container_engine.py +++ b/dem/core/container_engine.py @@ -104,10 +104,11 @@ def run(self, container_arguments: list[str]) -> None: def remove(self, image: str) -> None: """ Remove a tool image. - If the removal was successful return with True, otherwise return with False. - Args: image -- the tool image to remove + + Raises: + ContainerEngineError -- if the image is used by a container """ try: self._docker_client.images.remove(image) @@ -115,8 +116,6 @@ def remove(self, image: str) -> None: self.user_output.msg(f"[yellow]The {image} doesn't exist. Unable to remove it.[/]\n") except docker.errors.APIError: raise ContainerEngineError(f"The {image} is used by a container. Unable to remove it.\n") - else: - self.user_output.msg(f"[green]Successfully removed the {image}![/]\n") def search(self, registry: str) -> list[str]: """ Search repository in the axemsolutions registry. diff --git a/dem/core/platform.py b/dem/core/platform.py index 72a78d2..7110506 100644 --- a/dem/core/platform.py +++ b/dem/core/platform.py @@ -2,7 +2,7 @@ """ import os -from typing import Any +from typing import Any, Generator from dem.core.core import Core from dem.core.properties import __supported_dev_env_major_version__ from dem.core.exceptions import DataStorageError, PlatformError, ContainerEngineError @@ -40,6 +40,7 @@ def __init__(self) -> None: self._hosts = None self.default_dev_env_name: str = "" self.local_dev_envs: list[DevEnv] = [] + self.are_tool_images_assigned: bool = False # Set this to true in the platform instance to work with the local tool images only self.local_only = False @@ -64,6 +65,7 @@ def assign_tool_image_instances_to_all_dev_envs(self) -> None: """ Assign the ToolImage instances to all Development Environments.""" for dev_env in self.local_dev_envs: dev_env.assign_tool_image_instances(self.tool_images) + self.are_tool_images_assigned = True @property def tool_images(self) -> ToolImages: @@ -172,34 +174,47 @@ def install_dev_env(self, dev_env_to_install: DevEnv) -> None: dev_env_to_install.is_installed = True self.flush_dev_env_properties() - def uninstall_dev_env(self, dev_env_to_uninstall: DevEnv) -> None: + def uninstall_dev_env(self, dev_env_to_uninstall: DevEnv) -> Generator: """ Uninstall the Dev Env by removing the images not required anymore. Args: dev_env_to_uninstall -- the Development Environment to uninstall - Exceptions: + Returns: + Generator -- the status messages + + Raises: PlatformError -- if the uninstall fails """ + if not self.are_tool_images_assigned: + self.assign_tool_image_instances_to_all_dev_envs() + all_required_tool_images = set() for dev_env in self.local_dev_envs: if (dev_env is not dev_env_to_uninstall) and dev_env.is_installed: - for tool_image_descriptor in dev_env.tool_image_descriptors: - all_required_tool_images.add(tool_image_descriptor["image_name"] + ":" + tool_image_descriptor["image_version"]) + for tool_image in dev_env.tool_images: + all_required_tool_images.add(tool_image.name) tool_images_to_remove = set() - for tool_image_descriptor in dev_env_to_uninstall.tool_image_descriptors: - tool_image_name = tool_image_descriptor["image_name"] + ":" + tool_image_descriptor["image_version"] - if tool_image_name not in all_required_tool_images: - tool_images_to_remove.add(tool_image_name) + for tool_image in dev_env_to_uninstall.tool_images: + if tool_image.availability == ToolImage.NOT_AVAILABLE or tool_image.availability == ToolImage.REGISTRY_ONLY: + yield f"[yellow]Warning: The {tool_image.name} image could not be removed, because it is not available locally.[/]" + continue + + if tool_image.name not in all_required_tool_images: + tool_images_to_remove.add(tool_image.name) for tool_image_name in tool_images_to_remove: try: self.container_engine.remove(tool_image_name) except ContainerEngineError as e: raise PlatformError(f"Dev Env uninstall failed. --> {str(e)}") + else: + yield f"The {tool_image_name} image has been removed." dev_env_to_uninstall.is_installed = False + if self.default_dev_env_name == dev_env_to_uninstall.name: + self.default_dev_env_name = "" self.flush_dev_env_properties() def flush_dev_env_properties(self) -> None: diff --git a/tests/cli/test_clone_cmd.py b/tests/cli/test_clone_cmd.py index 61996e9..4b4140f 100644 --- a/tests/cli/test_clone_cmd.py +++ b/tests/cli/test_clone_cmd.py @@ -20,11 +20,17 @@ def test_handle_existing_local_dev_env(mock_stdout_print: MagicMock, mock_typer_ mock_platform = MagicMock() mock_local_dev_env = MagicMock() + test_uninstall_dev_env_status = ["test_uninstall_dev_env_status", + "test_uninstall_dev_env_status2"] + mock_platform.uninstall_dev_env.return_value = test_uninstall_dev_env_status + # Run unit under test clone_cmd.handle_existing_local_dev_env(mock_platform, mock_local_dev_env) # Check expectations - mock_stdout_print.assert_called_once_with("[yellow]The Dev Env already exists.[/]") + mock_stdout_print.assert_has_calls([call("[yellow]The Dev Env already exists.[/]"), + call(test_uninstall_dev_env_status[0]), + call(test_uninstall_dev_env_status[1])]) mock_typer_confirm.assert_has_calls([call("Continue with overwrite?", abort=True), call("The Dev Env to overwrite is installed. Do you want to uninstall it?", abort=True)]) diff --git a/tests/cli/test_create_cmd.py b/tests/cli/test_create_cmd.py index 3ecd8f8..2cd3fc0 100644 --- a/tests/cli/test_create_cmd.py +++ b/tests/cli/test_create_cmd.py @@ -145,8 +145,9 @@ def test_create_dev_env_new(mock_open_dev_env_settings_panel: MagicMock, @patch("dem.cli.command.create_cmd.create_new_dev_env_descriptor") @patch("dem.cli.command.create_cmd.open_dev_env_settings_panel") +@patch("dem.cli.command.create_cmd.stdout.print") @patch("dem.cli.command.create_cmd.typer.confirm") -def test_create_dev_env_overwrite_installed(mock_confirm: MagicMock, +def test_create_dev_env_overwrite_installed(mock_confirm: MagicMock, mock_stdout_print: MagicMock, mock_open_dev_env_settings_panel: MagicMock, mock_create_new_dev_env_descriptor: MagicMock) -> None: # Test setup @@ -163,6 +164,9 @@ def test_create_dev_env_overwrite_installed(mock_confirm: MagicMock, mock_selected_tool_images = MagicMock() mock_open_dev_env_settings_panel.return_value = mock_selected_tool_images + test_uninstall_dev_env_status = ["status1", "status2"] + mock_platform.uninstall_dev_env.return_value = test_uninstall_dev_env_status + test_dev_env_name = "test_dev_env" # Run unit under test @@ -179,6 +183,10 @@ def test_create_dev_env_overwrite_installed(mock_confirm: MagicMock, "Uninstall it first?", abort=True) ]) mock_platform.uninstall_dev_env.assert_called_once_with(mock_dev_env_original) + mock_stdout_print.assert_has_calls([ + call("status1"), + call("status2") + ]) mock_open_dev_env_settings_panel.assert_called_once_with(mock_platform.tool_images.all_tool_images) mock_create_new_dev_env_descriptor.assert_called_once_with(test_dev_env_name, mock_selected_tool_images) diff --git a/tests/cli/test_delete_cmd.py b/tests/cli/test_delete_cmd.py index efdd2b9..5c57a26 100644 --- a/tests/cli/test_delete_cmd.py +++ b/tests/cli/test_delete_cmd.py @@ -25,6 +25,10 @@ def test_delete(mock_stdout_print: MagicMock, mock_config: MagicMock) -> None: mock_platform.get_dev_env_by_name.return_value = test_dev_env mock_platform.local_dev_envs = [test_dev_env] + test_uninstall_dev_env_status = ["test_uninstall_dev_env_status", + "test_uninstall_dev_env_status2"] + mock_platform.uninstall_dev_env.return_value = test_uninstall_dev_env_status + # Run unit under test runner_result = runner.invoke(main.typer_cli, ["delete", test_dev_env_name]) @@ -37,7 +41,8 @@ def test_delete(mock_stdout_print: MagicMock, mock_config: MagicMock) -> None: abort=True) mock_platform.uninstall_dev_env.assert_called_once_with(test_dev_env) mock_stdout_print.assert_has_calls([ - call("Deleting the Development Environment..."), + call(test_uninstall_dev_env_status[0]), call(test_uninstall_dev_env_status[1]), + call("Deleting the Development Environment descriptor..."), call(f"[green]Successfully deleted the {test_dev_env_name}![/]") ]) mock_platform.flush_dev_env_properties.assert_called_once() diff --git a/tests/cli/test_init_cmd.py b/tests/cli/test_init_cmd.py index 459be98..4b807b3 100644 --- a/tests/cli/test_init_cmd.py +++ b/tests/cli/test_init_cmd.py @@ -87,6 +87,10 @@ def test_execute_reinit_installed(mock_DevEnv, mock_confirm, mock_stdout_print, mock_local_dev_env.is_installed = True mock_platform.local_dev_envs = [mock_local_dev_env] + test_uninstall_dev_env_status = ["test_uninstall_dev_env_status", + "test_uninstall_dev_env_status2"] + mock_platform.uninstall_dev_env.return_value = test_uninstall_dev_env_status + # Run unit under test init_cmd.execute(mock_platform, mock_project_path) @@ -100,8 +104,10 @@ def test_execute_reinit_installed(mock_DevEnv, mock_confirm, mock_stdout_print, call("The Development Environment is installed, so it can't be deleted. Do you want to uninstall it first?", abort=True)]) mock_platform.uninstall_dev_env.assert_called_once_with(mock_local_dev_env) mock_platform.flush_dev_env_properties.assert_called_once() - mock_stdout_print.assert_has_calls([call(f"[green]Successfully initialized the {mock_dev_env_name} Dev Env for the project at {mock_project_path}![/]"), - call(f"\nNow you can install the Dev Env with the `dem install {mock_dev_env_name}` command.")]) + mock_stdout_print.assert_has_calls([ + call(test_uninstall_dev_env_status[0]), call(test_uninstall_dev_env_status[1]), + call(f"[green]Successfully initialized the {mock_dev_env_name} Dev Env for the project at {mock_project_path}![/]"), + call(f"\nNow you can install the Dev Env with the `dem install {mock_dev_env_name}` command.")]) @patch("dem.cli.command.init_cmd.os.path.isdir") @patch("dem.cli.command.init_cmd.stderr.print") diff --git a/tests/cli/test_modify_cmd.py b/tests/cli/test_modify_cmd.py index d34b41f..b347320 100644 --- a/tests/cli/test_modify_cmd.py +++ b/tests/cli/test_modify_cmd.py @@ -8,7 +8,7 @@ # Test framework import pytest from typer.testing import CliRunner -from unittest.mock import patch, MagicMock +from unittest.mock import patch, MagicMock, call from rich.console import Console import io, typer @@ -241,6 +241,7 @@ def test_execute_invalid_name(): # Check expectations assert 0 == runner_result.exit_code + mock_platform.assign_tool_image_instances_to_all_dev_envs.assert_called_once() mock_platform.get_dev_env_by_name.assert_called_once_with(test_dev_env_name) console = Console(file=io.StringIO()) @@ -262,15 +263,48 @@ def test_execute(mock_modify_with_tui: MagicMock, mock_stdout_print: MagicMock) modify_cmd.execute(mock_platform, test_dev_env_name) # Check expectations + mock_platform.assign_tool_image_instances_to_all_dev_envs.assert_called_once() mock_platform.get_dev_env_by_name.assert_called_once_with(test_dev_env_name) mock_modify_with_tui.assert_called_once_with(mock_platform, mock_dev_env) mock_stdout_print.assert_called_once_with("[green]The Development Environment has been modified successfully![/]") +@patch("dem.cli.command.modify_cmd.modify_with_tui") +@patch("dem.cli.command.modify_cmd.typer.confirm") +@patch("dem.cli.command.modify_cmd.stdout.print") +def test_execute_installed(mock_stdout_print: MagicMock, mock_confirm: MagicMock, + mock_modify_with_tui: MagicMock) -> None: + # Test setup + mock_platform = MagicMock() + test_dev_env_name = "test_dev_env_name" + + mock_dev_env = MagicMock() + mock_dev_env.is_installed = True + mock_platform.get_dev_env_by_name.return_value = mock_dev_env + + test_uninstall_dev_env_status = ["test_uninstall_dev_env_status", + "test_uninstall_dev_env_status2"] + mock_platform.uninstall_dev_env.return_value = test_uninstall_dev_env_status + + # Run unit under test + modify_cmd.execute(mock_platform, test_dev_env_name) + + # Check expectations + mock_platform.assign_tool_image_instances_to_all_dev_envs.assert_called_once() + mock_platform.get_dev_env_by_name.assert_called_once_with(test_dev_env_name) + mock_stdout_print.assert_has_calls([ + call("[yellow]The Development Environment is installed, so it can't be modified.[/]"), + call(test_uninstall_dev_env_status[0]), call(test_uninstall_dev_env_status[1]), + call("[green]The Development Environment has been modified successfully![/]"), + ]) + mock_confirm.assert_called_once_with("Do you want to uninstall it first?", abort=True) + mock_platform.uninstall_dev_env.assert_called_once_with(mock_dev_env) + mock_modify_with_tui.assert_called_once_with(mock_platform, mock_dev_env) + @patch("dem.cli.command.modify_cmd.stderr.print") @patch("dem.cli.command.modify_cmd.typer.confirm") @patch("dem.cli.command.modify_cmd.stdout.print") -def test_execute_PlatformError(mock_stdout_print: MagicMock, mock_confirm: MagicMock, - mock_stderr_print: MagicMock) -> None: +def test_execute_installed_PlatformError(mock_stdout_print: MagicMock, mock_confirm: MagicMock, + mock_stderr_print: MagicMock) -> None: # Test setup mock_platform = MagicMock() test_dev_env_name = "test_dev_env_name" @@ -285,6 +319,7 @@ def test_execute_PlatformError(mock_stdout_print: MagicMock, mock_confirm: Magic modify_cmd.execute(mock_platform, test_dev_env_name) # Check expectations + mock_platform.assign_tool_image_instances_to_all_dev_envs.assert_called_once() mock_platform.get_dev_env_by_name.assert_called_once_with(test_dev_env_name) mock_stdout_print.assert_called_once_with("[yellow]The Development Environment is installed, so it can't be modified.[/]") mock_confirm.assert_called_once_with("Do you want to uninstall it first?", abort=True) diff --git a/tests/cli/test_uninstall_cmd.py b/tests/cli/test_uninstall_cmd.py index 24a0d7b..93c3615 100644 --- a/tests/cli/test_uninstall_cmd.py +++ b/tests/cli/test_uninstall_cmd.py @@ -6,7 +6,7 @@ # Test framework from typer.testing import CliRunner -from unittest.mock import patch, MagicMock +from unittest.mock import patch, MagicMock, call ## Global test variables runner = CliRunner() @@ -30,7 +30,7 @@ def test_uninstall_dev_env_invalid_name(mock_stderr_print): mock_stderr_print.assert_called_once_with(f"[red]Error: The {test_invalid_name} Development Environment does not exist.[/]") @patch("dem.cli.command.uninstall_cmd.stdout.print") -def test_uninstall_dev_env_valid_name(mock_stdout_print): +def test_uninstall_dev_env_valid_name(mock_stdout_print: MagicMock) -> None: # Test setup fake_dev_env_to_uninstall = MagicMock() fake_dev_env_to_uninstall.name = "dev_env" @@ -39,15 +39,24 @@ def test_uninstall_dev_env_valid_name(mock_stdout_print): mock_platform.get_dev_env_by_name.return_value = fake_dev_env_to_uninstall main.platform = mock_platform + test_uninstall_dev_env_status = ["test_uninstall_dev_env_status", + "test_uninstall_dev_env_status2"] + mock_platform.uninstall_dev_env.return_value = test_uninstall_dev_env_status + # Run unit under test - runner_result = runner.invoke(main.typer_cli, ["uninstall", fake_dev_env_to_uninstall.name ], color=True) + runner_result = runner.invoke(main.typer_cli, ["uninstall", fake_dev_env_to_uninstall.name], + color=True) # Check expectations assert 0 == runner_result.exit_code mock_platform.get_dev_env_by_name.assert_called_once_with(fake_dev_env_to_uninstall.name ) mock_platform.uninstall_dev_env.assert_called_once_with(fake_dev_env_to_uninstall) - mock_stdout_print.assert_called_once_with(f"[green]Successfully uninstalled the {fake_dev_env_to_uninstall.name}![/]") + mock_stdout_print.assert_has_calls([ + call(test_uninstall_dev_env_status[0]), + call(test_uninstall_dev_env_status[1]), + call(f"[green]Successfully uninstalled the {fake_dev_env_to_uninstall.name}![/]") + ]) @patch("dem.cli.command.uninstall_cmd.stderr.print") def test_uninstall_dev_env_valid_name_not_installed(mock_stderr_print): diff --git a/tests/core/test_container_engine.py b/tests/core/test_container_engine.py index 8d1904b..79c1853 100644 --- a/tests/core/test_container_engine.py +++ b/tests/core/test_container_engine.py @@ -254,7 +254,6 @@ def test_remove(mock_from_env: MagicMock, mock_user_output: MagicMock) -> None: # Check expectations mock_docker_client.images.remove.assert_called_once_with(test_image_to_remove) - mock_user_output.msg.assert_called_once_with(f"[green]Successfully removed the {test_image_to_remove}![/]\n") @patch.object(container_engine.ContainerEngine, "user_output") @patch("docker.from_env") diff --git a/tests/core/test_platform.py b/tests/core/test_platform.py index d34f740..1d2494d 100644 --- a/tests/core/test_platform.py +++ b/tests/core/test_platform.py @@ -73,11 +73,14 @@ def test_Platform_assign_tool_image_instances_to_all_dev_envs() -> None: test_platform._tool_images = mock_tool_images mock_dev_env = MagicMock() test_platform.local_dev_envs = [mock_dev_env] + test_platform.are_tool_images_assigned = False # Run unit under test test_platform.assign_tool_image_instances_to_all_dev_envs() # Check expectations + assert test_platform.are_tool_images_assigned == True + mock_dev_env.assign_tool_image_instances.assert_called_once_with(mock_tool_images) @patch("dem.core.platform.ToolImages") @@ -394,130 +397,179 @@ def test_Platform_install_dev_env_with_not_avilable_tool_image(mock___init__: Ma @patch.object(platform.Platform, "flush_dev_env_properties") @patch.object(platform.Platform, "container_engine") +@patch.object(platform.Platform, "assign_tool_image_instances_to_all_dev_envs") @patch.object(platform.Platform, "__init__") def test_Platform_uninstall_dev_env_success(mock___init__: MagicMock, + mock_assign_tool_image_instances_to_all_dev_envs: MagicMock, mock_container_engine: MagicMock, mock_flush_dev_env_properties: MagicMock) -> None: # Test setup mock___init__.return_value = None test_platform = platform.Platform() + test_platform.are_tool_images_assigned = False + + mock_tool_image1 = MagicMock() + mock_tool_image1.name = "test_image_name1:test_image_version1" + mock_tool_image2 = MagicMock() + mock_tool_image2.name = "test_image_name2:test_image_version2" + mock_tool_image3 = MagicMock() + mock_tool_image3.name = "test_image_name3:test_image_version3" + mock_tool_image4 = MagicMock() + mock_tool_image4.name = "test_image_name4:test_image_version4" + mock_dev_env1 = MagicMock() mock_dev_env2 = MagicMock() mock_dev_env_to_uninstall = MagicMock() + mock_dev_env_to_uninstall.name = "test_dev_env_to_uninstall" + test_platform.local_dev_envs = [ mock_dev_env1, mock_dev_env2, mock_dev_env_to_uninstall ] - mock_dev_env1.tool_image_descriptors = [ - { - "image_name": "test_image_name1", - "image_version": "test_image_version1" - }, - { - "image_name": "test_image_name2", - "image_version": "test_image_version2" - } - ] + + mock_dev_env1.tool_images = [mock_tool_image1, mock_tool_image2] + mock_dev_env2.tool_images = [mock_tool_image3] + mock_dev_env_to_uninstall.tool_images = [mock_tool_image1, mock_tool_image3, mock_tool_image4] + mock_dev_env1.is_installed = True - mock_dev_env2.tool_image_descriptors = [ - { - "image_name": "test_image_name3", - "image_version": "test_image_version3" - } - ] mock_dev_env2.is_installed = True - mock_dev_env_to_uninstall.tool_image_descriptors = [ - { - "image_name": "test_image_name1", - "image_version": "test_image_version1" - }, - { - "image_name": "test_image_name3", - "image_version": "test_image_version3" - }, - { - "image_name": "test_image_name4", - "image_version": "test_image_version4" - } - ] mock_dev_env_to_uninstall.is_installed = True - mock_container_engine.remove.return_value = True + test_platform.default_dev_env_name = mock_dev_env_to_uninstall.name # Run unit under test - test_platform.uninstall_dev_env(mock_dev_env_to_uninstall) + actual_status = [] + for status in test_platform.uninstall_dev_env(mock_dev_env_to_uninstall): + actual_status.append(status) # Check expectations mock___init__.assert_called_once() assert mock_dev_env_to_uninstall.is_installed == False + assert actual_status == [f"The {mock_tool_image4.name} image has been removed."] + assert test_platform.default_dev_env_name == "" + + mock_assign_tool_image_instances_to_all_dev_envs.assert_called_once() mock_container_engine.remove.asssert_called_once_with("test_image_name4:test_image_version4") mock_flush_dev_env_properties.assert_called_once() @patch.object(platform.Platform, "flush_dev_env_properties") @patch.object(platform.Platform, "container_engine") +@patch.object(platform.Platform, "assign_tool_image_instances_to_all_dev_envs") @patch.object(platform.Platform, "__init__") def test_Platform_uninstall_dev_env_with_duplicate_images(mock___init__: MagicMock, + mock_assign_tool_image_instances_to_all_dev_envs: MagicMock, mock_container_engine: MagicMock, mock_flush_dev_env_properties: MagicMock) -> None: # Test setup mock___init__.return_value = None test_platform = platform.Platform() + test_platform.are_tool_images_assigned = False + + mock_tool_image1 = MagicMock() + mock_tool_image1.name = "test_image_name1:test_image_version1" + mock_tool_image2 = MagicMock() + mock_tool_image2.name = "test_image_name2:test_image_version2" + mock_tool_image3 = MagicMock() + mock_tool_image3.name = "test_image_name3:test_image_version3" + mock_tool_image4 = MagicMock() + mock_tool_image4.name = "test_image_name4:test_image_version4" + mock_dev_env1 = MagicMock() mock_dev_env2 = MagicMock() mock_dev_env_to_uninstall = MagicMock() + mock_dev_env_to_uninstall.name = "test_dev_env_to_uninstall" + test_platform.local_dev_envs = [ mock_dev_env1, mock_dev_env2, mock_dev_env_to_uninstall ] - mock_dev_env1.tool_image_descriptors = [ - { - "image_name": "test_image_name1", - "image_version": "test_image_version1" - }, - { - "image_name": "test_image_name2", - "image_version": "test_image_version2" - } - ] + + mock_dev_env1.tool_images = [mock_tool_image1, mock_tool_image2] + mock_dev_env2.tool_images = [mock_tool_image3] + mock_dev_env_to_uninstall.tool_images = [mock_tool_image1, mock_tool_image3, mock_tool_image4, + mock_tool_image4] + mock_dev_env1.is_installed = True - mock_dev_env2.tool_image_descriptors = [ - { - "image_name": "test_image_name3", - "image_version": "test_image_version3" - } - ] mock_dev_env2.is_installed = True - mock_dev_env_to_uninstall.tool_image_descriptors = [ - { - "image_name": "test_image_name1", - "image_version": "test_image_version1" - }, - { - "image_name": "test_image_name3", - "image_version": "test_image_version3" - }, - { - "image_name": "test_image_name4", - "image_version": "test_image_version4" - }, - { - "image_name": "test_image_name4", - "image_version": "test_image_version4" - } + mock_dev_env_to_uninstall.is_installed = True + + test_platform.default_dev_env_name = mock_dev_env_to_uninstall.name + + # Run unit under test + actual_status = [] + for status in test_platform.uninstall_dev_env(mock_dev_env_to_uninstall): + actual_status.append(status) + + # Check expectations + mock___init__.assert_called_once() + + assert mock_dev_env_to_uninstall.is_installed == False + assert actual_status == [f"The {mock_tool_image4.name} image has been removed."] + assert test_platform.default_dev_env_name == "" + + mock_assign_tool_image_instances_to_all_dev_envs.assert_called_once() + + mock_container_engine.remove.asssert_called_once_with("test_image_name4:test_image_version4") + mock_flush_dev_env_properties.assert_called_once() + +@patch.object(platform.Platform, "flush_dev_env_properties") +@patch.object(platform.Platform, "container_engine") +@patch.object(platform.Platform, "__init__") +def test_Platform_uninstall_dev_env_image_not_found(mock___init__: MagicMock, + mock_container_engine: MagicMock, + mock_flush_dev_env_properties: MagicMock) -> None: + # Test setup + mock___init__.return_value = None + + test_platform = platform.Platform() + test_platform.are_tool_images_assigned = True + + mock_tool_image1 = MagicMock() + mock_tool_image1.name = "test_image_name1:test_image_version1" + mock_tool_image1.availability = platform.ToolImage.NOT_AVAILABLE + mock_tool_image2 = MagicMock() + mock_tool_image2.name = "test_image_name2:test_image_version2" + mock_tool_image3 = MagicMock() + mock_tool_image3.name = "test_image_name3:test_image_version3" + mock_tool_image3.availability = platform.ToolImage.REGISTRY_ONLY + mock_tool_image4 = MagicMock() + mock_tool_image4.name = "test_image_name4:test_image_version4" + + mock_dev_env1 = MagicMock() + mock_dev_env2 = MagicMock() + mock_dev_env_to_uninstall = MagicMock() + mock_dev_env_to_uninstall.name = "test_dev_env_to_uninstall" + + test_platform.local_dev_envs = [ + mock_dev_env1, mock_dev_env2, mock_dev_env_to_uninstall ] + + mock_dev_env1.tool_images = [mock_tool_image1, mock_tool_image2] + mock_dev_env2.tool_images = [mock_tool_image3] + mock_dev_env_to_uninstall.tool_images = [mock_tool_image1, mock_tool_image3, mock_tool_image4] + + mock_dev_env1.is_installed = True + mock_dev_env2.is_installed = True mock_dev_env_to_uninstall.is_installed = True - mock_container_engine.remove.return_value = True + test_platform.default_dev_env_name = mock_dev_env_to_uninstall.name # Run unit under test - test_platform.uninstall_dev_env(mock_dev_env_to_uninstall) + actual_status = [] + for status in test_platform.uninstall_dev_env(mock_dev_env_to_uninstall): + actual_status.append(status) # Check expectations mock___init__.assert_called_once() assert mock_dev_env_to_uninstall.is_installed == False + assert actual_status == [ + f"[yellow]Warning: The {mock_tool_image1.name} image could not be removed, because it is not available locally.[/]", + f"[yellow]Warning: The {mock_tool_image3.name} image could not be removed, because it is not available locally.[/]", + f"The {mock_tool_image4.name} image has been removed."] + assert test_platform.default_dev_env_name == "" mock_container_engine.remove.asssert_called_once_with("test_image_name4:test_image_version4") mock_flush_dev_env_properties.assert_called_once() @@ -530,51 +582,40 @@ def test_Platform_uninstall_dev_env_failure(mock___init__: MagicMock, mock___init__.return_value = None test_platform = platform.Platform() + test_platform.are_tool_images_assigned = True + + mock_tool_image1 = MagicMock() + mock_tool_image1.name = "test_image_name1:test_image_version1" + mock_tool_image2 = MagicMock() + mock_tool_image2.name = "test_image_name2:test_image_version2" + mock_tool_image3 = MagicMock() + mock_tool_image3.name = "test_image_name3:test_image_version3" + mock_tool_image4 = MagicMock() + mock_tool_image4.name = "test_image_name4:test_image_version4" + mock_dev_env1 = MagicMock() mock_dev_env2 = MagicMock() mock_dev_env_to_uninstall = MagicMock() + mock_dev_env_to_uninstall.name = "test_dev_env_to_uninstall" + test_platform.local_dev_envs = [ mock_dev_env1, mock_dev_env2, mock_dev_env_to_uninstall ] - mock_dev_env1.tool_image_descriptors = [ - { - "image_name": "test_image_name1", - "image_version": "test_image_version1" - }, - { - "image_name": "test_image_name2", - "image_version": "test_image_version2" - } - ] + + mock_dev_env1.tool_images = [mock_tool_image1, mock_tool_image2] + mock_dev_env2.tool_images = [mock_tool_image3] + mock_dev_env_to_uninstall.tool_images = [mock_tool_image1, mock_tool_image3, mock_tool_image4] + mock_dev_env1.is_installed = True - mock_dev_env2.tool_image_descriptors = [ - { - "image_name": "test_image_name3", - "image_version": "test_image_version3" - } - ] mock_dev_env2.is_installed = True - mock_dev_env_to_uninstall.tool_image_descriptors = [ - { - "image_name": "test_image_name1", - "image_version": "test_image_version1" - }, - { - "image_name": "test_image_name3", - "image_version": "test_image_version3" - }, - { - "image_name": "test_image_name4", - "image_version": "test_image_version4" - } - ] mock_dev_env_to_uninstall.is_installed = True mock_container_engine.remove.side_effect = platform.ContainerEngineError("") # Run unit under test with pytest.raises(platform.PlatformError) as exported_exception_info: - test_platform.uninstall_dev_env(mock_dev_env_to_uninstall) + for _ in test_platform.uninstall_dev_env(mock_dev_env_to_uninstall): + pass # Check expectations mock___init__.assert_called_once()