Skip to content

Commit

Permalink
Exception handling added for the uninstall_dev_env calls. The error r…
Browse files Browse the repository at this point in the history
…eporting for the Platform Error cleaned up.
  • Loading branch information
janosmurai committed Mar 20, 2024
1 parent 4382ebe commit 16197e6
Show file tree
Hide file tree
Showing 13 changed files with 103 additions and 34 deletions.
7 changes: 6 additions & 1 deletion dem/cli/command/create_cmd.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from dem.core.dev_env import DevEnv, DevEnv
from dem.core.tool_images import ToolImages
from dem.core.platform import Platform
from dem.core.exceptions import PlatformError
from dem.cli.console import stdout, stderr
from dem.cli.tui.panel.tool_type_selector import ToolTypeSelectorPanel
from dem.cli.tui.panel.tool_image_selector import ToolImageSelectorPanel
Expand Down Expand Up @@ -171,7 +172,11 @@ def create_dev_env(platform: Platform, dev_env_name: str) -> None:
if dev_env_original.is_installed:
typer.confirm("The Development Environment is installed, so it can't be overwritten. " + \
"Uninstall it first?", abort=True)
platform.uninstall_dev_env(dev_env_original)
try:
platform.uninstall_dev_env(dev_env_original)
except PlatformError as e:
stderr.print(f"[red]{str(e)}[/]")
typer.Abort()

tool_image_list = get_tool_image_list(platform.tool_images)
new_dev_env_descriptor = get_dev_env_descriptor_from_user(dev_env_name, tool_image_list)
Expand Down
2 changes: 1 addition & 1 deletion dem/cli/command/delete_cmd.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ def execute(platform: Platform, dev_env_name: str) -> None:
try:
platform.uninstall_dev_env(dev_env_to_delete)
except PlatformError as e:
stderr.print(f"[red]Error: The deletion failed, because the Dev Env can't be uninstalled. {str(e)}[/]")
stderr.print(f"[red]{str(e)}[/]")
return

stdout.print("Deleting the Development Environment...")
Expand Down
2 changes: 1 addition & 1 deletion dem/cli/command/init_cmd.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ def execute(platform: Platform, project_path: str) -> None:
try:
platform.uninstall_dev_env(local_dev_env)
except PlatformError as e:
stderr.print(f"[red]Error: The Dev Env can't be uninstalled. {str(e)}")
stderr.print(f"[red]{str(e)}[/]")
return

platform.local_dev_envs.remove(local_dev_env)
Expand Down
7 changes: 6 additions & 1 deletion dem/cli/command/modify_cmd.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from dem.core.dev_env import DevEnv, DevEnv
from dem.core.tool_images import ToolImages
from dem.core.platform import Platform
from dem.core.exceptions import PlatformError
from dem.cli.console import stderr, stdout
from dem.cli.tui.renderable.menu import SelectMenu
from dem.cli.tui.panel.tool_type_selector import ToolTypeSelectorPanel
Expand Down Expand Up @@ -207,7 +208,11 @@ def execute(platform: Platform, dev_env_name: str, tool_type: str, tool_image: s
elif dev_env.is_installed is True:
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)
platform.uninstall_dev_env(dev_env)
try:
platform.uninstall_dev_env(dev_env)
except PlatformError as e:
stderr.print(f"[red]{str(e)}[/]")
return

if (tool_type or tool_image):
modify_single_tool(platform, dev_env, tool_type, tool_image)
Expand Down
2 changes: 1 addition & 1 deletion dem/cli/command/uninstall_cmd.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,6 @@ def execute(platform: Platform, dev_env_name: str) -> None:
try:
platform.uninstall_dev_env(dev_env_to_uninstall)
except PlatformError as e:
stderr.print(f"[red]Error: {str(e)}[/]")
stderr.print(f"[red]{str(e)}[/]")
else:
stdout.print(f"[green]Successfully uninstalled the {dev_env_name}![/]")
2 changes: 1 addition & 1 deletion dem/core/container_engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ def remove(self, image: str) -> None:
except docker.errors.ImageNotFound:
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")
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")

Expand Down
8 changes: 4 additions & 4 deletions dem/core/platform.py
Original file line number Diff line number Diff line change
Expand Up @@ -166,11 +166,11 @@ def install_dev_env(self, dev_env_to_install: DevEnv) -> None:
def uninstall_dev_env(self, dev_env_to_uninstall: DevEnv) -> None:
""" Uninstall the Dev Env by removing the images not required anymore.
Exceptions:
PlatformError -- if the uninstall fails
Args:
dev_env_to_uninstall -- the Development Environment to uninstall
Exceptions:
PlatformError -- if the uninstall fails
"""
all_required_tool_images = set()
for dev_env in self.local_dev_envs:
Expand All @@ -188,7 +188,7 @@ def uninstall_dev_env(self, dev_env_to_uninstall: DevEnv) -> None:
try:
self.container_engine.remove(tool_image)
except ContainerEngineError as e:
raise PlatformError(f"Dev Env uninstall failed. {str(e)}")
raise PlatformError(f"Dev Env uninstall failed. <-caused by- {str(e)}")

dev_env_to_uninstall.is_installed = False
self.flush_descriptors()
Expand Down
32 changes: 32 additions & 0 deletions tests/cli/test_create_cmd.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,38 @@ def test_create_dev_env_overwrite(mock_confirm, mock_get_tool_image_list,
mock_get_dev_env_descriptor_from_user.assert_called_once_with(expected_dev_env_name,
mock_tool_images)

@patch("dem.cli.command.create_cmd.typer.Abort")
@patch("dem.cli.command.create_cmd.stderr.print")
@patch("dem.cli.command.create_cmd.typer.confirm")
def test_create_dev_env_overwrite_PlatformError(mock_confirm: MagicMock, mock_stderr_print: MagicMock,
mock_Abort: MagicMock) -> None:
# Test setup
mock_platform = MagicMock()
mock_dev_env_original = MagicMock()
mock_dev_env_original.is_installed = True
mock_platform.get_dev_env_by_name.return_value = mock_dev_env_original
test_exception_text = "test_exception_text"
mock_platform.uninstall_dev_env.side_effect = create_cmd.PlatformError(test_exception_text)
mock_Abort.side_effect = Exception("")

test_dev_env_name = "test_dev_env"

# Run unit under test
with pytest.raises(Exception):
create_cmd.create_dev_env(mock_platform, test_dev_env_name)

# Check expectations
mock_platform.get_dev_env_by_name.assert_called_once_with(test_dev_env_name)
mock_confirm.assert_has_calls([
call("The input name is already used by a Development Environment. Overwrite it?",
abort=True),
call("The Development Environment is installed, so it can't be overwritten. " + \
"Uninstall it first?", abort=True)
])
mock_platform.uninstall_dev_env.assert_called_once_with(mock_dev_env_original)
mock_stderr_print.assert_called_once_with(f"[red]Platform error: {test_exception_text}[/]")
mock_Abort.assert_called_once()

@patch("dem.cli.command.create_cmd.get_dev_env_descriptor_from_user")
@patch("dem.cli.command.create_cmd.typer.confirm")
def test_create_dev_env_abort(mock_confirm, mock_get_dev_env_descriptor_from_user):
Expand Down
2 changes: 1 addition & 1 deletion tests/cli/test_delete_cmd.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ def test_delete_uninstall_failed(mock_stderr_print: MagicMock, mock_confirm: Mag
mock_confirm.assert_called_once_with("The Development Environment is installed. Do you want to uninstall it?",
abort=True)
mock_platform.uninstall_dev_env.assert_called_once_with(test_dev_env)
mock_stderr_print.assert_called_once_with(f"[red]Error: The deletion failed, because the Dev Env can't be uninstalled. Platform error: {test_exception_text}[/]")
mock_stderr_print.assert_called_once_with(f"[red]Platform error: {test_exception_text}[/]")

@patch("dem.cli.command.delete_cmd.stderr.print")
def test_delete_not_existing(mock_stderr_print: MagicMock) -> None:
Expand Down
2 changes: 1 addition & 1 deletion tests/cli/test_init_cmd.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,4 +133,4 @@ def test_execute_reinit_installed_uninstall_fails(mock_DevEnv, mock_confirm, moc
mock_confirm.assert_has_calls([call("Would you like to re-init the Dev Env? All local changes will be lost!", abort=True),
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_stderr_print.assert_called_once_with(f"[red]Error: The Dev Env can't be uninstalled. Platform error: {test_exception_text}")
mock_stderr_print.assert_called_once_with(f"[red]Platform error: {test_exception_text}[/]")
67 changes: 47 additions & 20 deletions tests/cli/test_modify_cmd.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,25 +117,6 @@ def test_handle_user_confirm_cancel():
with pytest.raises(typer.Abort):
modify_cmd.handle_user_confirm("cancel", MagicMock(), MagicMock())

def test_execute_invalid_name():
# Test setup
mock_platform = MagicMock()
main.platform = mock_platform
mock_platform.get_dev_env_by_name.return_value = None
test_dev_env_name = "not existing env"

# Run unit under test
runner_result = runner.invoke(main.typer_cli, ["modify", test_dev_env_name], color=True)

# Check expectations
assert 0 == runner_result.exit_code

mock_platform.get_dev_env_by_name.assert_called_once_with(test_dev_env_name)

console = Console(file=io.StringIO())
console.print("[red]The Development Environment doesn't exist.")
assert console.file.getvalue() == runner_result.stderr

@patch("dem.cli.command.modify_cmd.handle_user_confirm")
@patch("dem.cli.command.modify_cmd.get_confirm_from_user")
@patch("dem.cli.command.modify_cmd.get_modifications_from_user")
Expand Down Expand Up @@ -276,6 +257,25 @@ def test_modify_single_tool_no_type(mock_stderr_print: MagicMock) -> None:

mock_stderr_print.assert_called_once_with("[red]Error: The tool type and the tool image must be set together.[/]")

def test_execute_invalid_name():
# Test setup
mock_platform = MagicMock()
main.platform = mock_platform
mock_platform.get_dev_env_by_name.return_value = None
test_dev_env_name = "not existing env"

# Run unit under test
runner_result = runner.invoke(main.typer_cli, ["modify", test_dev_env_name], color=True)

# Check expectations
assert 0 == runner_result.exit_code

mock_platform.get_dev_env_by_name.assert_called_once_with(test_dev_env_name)

console = Console(file=io.StringIO())
console.print("[red]The Development Environment doesn't exist.")
assert console.file.getvalue() == runner_result.stderr

@patch("dem.cli.command.modify_cmd.modify_single_tool")
@patch("dem.cli.command.modify_cmd.typer.confirm")
@patch("dem.cli.command.modify_cmd.stdout.print")
Expand Down Expand Up @@ -319,4 +319,31 @@ def test_execute_open_modify_panel(mock_open_modify_panel: MagicMock) -> None:

# Check expectations
mock_platform.get_dev_env_by_name.assert_called_once_with(test_dev_env_name)
mock_open_modify_panel.assert_called_once_with(mock_platform, mock_dev_env)
mock_open_modify_panel.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:
# Test setup
mock_platform = MagicMock()
test_dev_env_name = "test_dev_env_name"
test_tool_type = "test_tool_type"
test_tool_image = "test_tool_image"
mock_dev_env = MagicMock()
mock_dev_env.is_installed = True

mock_platform.get_dev_env_by_name.return_value = mock_dev_env
test_exception_text = "test_exception_text"
mock_platform.uninstall_dev_env.side_effect = modify_cmd.PlatformError(test_exception_text)

# Run unit under test
modify_cmd.execute(mock_platform, test_dev_env_name, test_tool_type, test_tool_image)

# Check expectations
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)
mock_platform.uninstall_dev_env.assert_called_once_with(mock_dev_env)
mock_stderr_print.assert_called_once_with(f"[red]Platform error: {test_exception_text}[/]")
2 changes: 1 addition & 1 deletion tests/cli/test_uninstall_cmd.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,4 +87,4 @@ def test_uninstall_dev_env_valid_name_failed(mock_stderr_print):
assert 0 == runner_result.exit_code

mock_platform.get_dev_env_by_name.assert_called_once_with(fake_dev_env_to_uninstall.name )
mock_stderr_print.assert_called_once_with(f"[red]Error: Platform error: {test_exception_text}[/]")
mock_stderr_print.assert_called_once_with(f"[red]Platform error: {test_exception_text}[/]")
2 changes: 1 addition & 1 deletion tests/core/test_platform.py
Original file line number Diff line number Diff line change
Expand Up @@ -580,7 +580,7 @@ def test_Platform_uninstall_dev_env_failure(mock___init__: MagicMock,
# Check expectations
mock___init__.assert_called_once()

assert str(exported_exception_info) == "Platform error: Dev Env uninstall failed."
assert str(exported_exception_info) == "Platform error: Dev Env uninstall failed. <-caused by-"
assert mock_dev_env_to_uninstall.is_installed == True

mock_container_engine.remove.asssert_called_once_with("test_image_name4:test_image_version4")
Expand Down

0 comments on commit 16197e6

Please sign in to comment.