Skip to content

Commit

Permalink
Install command implementation and tests
Browse files Browse the repository at this point in the history
  • Loading branch information
magyta93 authored and janosmurai committed Jan 9, 2024
1 parent 1f301a0 commit b9ae8e3
Show file tree
Hide file tree
Showing 6 changed files with 201 additions and 6 deletions.
28 changes: 28 additions & 0 deletions dem/cli/command/install_cmd.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
"""install CLI command implementation."""
# dem/cli/command/install_cmd.py

from dem.core.dev_env import DevEnv
from dem.core.platform import Platform, PlatformError
from dem.cli.console import stderr, stdout

def execute(platform: Platform, dev_env_name: str) -> None:
"""
Install the given Development Environment.
Args:
platform -- the platform
dev_env_name -- the name of the Development Environment to install
"""
dev_env_to_install: DevEnv | None = platform.get_dev_env_by_name(dev_env_name)

if dev_env_to_install is None:
stderr.print(f"[red]Error: The {dev_env_name} Development Environment does not exist.[/]")
elif dev_env_to_install.is_installed == True:
stderr.print(f"[red]Error: The {dev_env_name} Development Environment is already installed.[/]")
else:
try:
platform.install_dev_env(dev_env_to_install)
except PlatformError as e:
stderr.print(f"[red]Error: {e}[/]")
else:
stdout.print(f"[green]Successfully installed the {dev_env_name}![/]")
13 changes: 12 additions & 1 deletion dem/cli/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from dem.cli.command import cp_cmd, info_cmd, list_cmd, pull_cmd, create_cmd, modify_cmd, delete_cmd, \
rename_cmd, run_cmd, export_cmd, load_cmd, clone_cmd, add_reg_cmd, \
list_reg_cmd, del_reg_cmd, add_cat_cmd, list_cat_cmd, del_cat_cmd, \
add_host_cmd, uninstall_cmd, assign_cmd, list_host_cmd, del_host_cmd
add_host_cmd, uninstall_cmd, install_cmd, assign_cmd, list_host_cmd, del_host_cmd
from dem.cli.console import stdout
from dem.core.platform import Platform
from dem.core.exceptions import InternalError
Expand Down Expand Up @@ -207,6 +207,17 @@ def delete(dev_env_name: Annotated[str, typer.Argument(help="Name of the Develop
else:
raise InternalError("Error: The platform hasn't been initialized properly!")

@typer_cli.command()
def install(dev_env_name: Annotated[str, typer.Argument(help="Name of the Development Environment to install.",
autocompletion=autocomplete_dev_env_name)]) -> None:
"""
Install the Development Environment from the local setup.
"""
if platform is not None:
install_cmd.execute(platform, dev_env_name)
else:
raise InternalError("Error: The platform hasn't been initialized properly!")

@typer_cli.command()
def uninstall(dev_env_name: Annotated[str, typer.Argument(help="Name of the Development Environment to uninstall.",
autocompletion=autocomplete_dev_env_name)]) -> None:
Expand Down
10 changes: 8 additions & 2 deletions dem/core/platform.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,8 +156,14 @@ def install_dev_env(self, dev_env_to_install: DevEnv) -> None:
dev_env_to_install -- the Development Environment to install
"""
for tool_image in dev_env_to_install.get_registry_only_tool_images(self.tool_images, False):
self.user_output.msg(f"\nPulling image {tool_image}", is_title=True)
self.container_engine.pull(tool_image)
self.user_output.msg(f"\nPulling image {tool_image}", is_title=True)
try:
self.container_engine.pull(tool_image)
except ContainerEngineError:
raise PlatformError("Dev Env install failed.")

dev_env_to_install.is_installed = "True"
self.flush_descriptors()

def uninstall_dev_env(self, dev_env_to_uninstall: DevEnv) -> None:
""" Uninstall the Dev Env by removing the images not required anymore.
Expand Down
24 changes: 24 additions & 0 deletions docs/commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,30 @@ List the available hosts from the config file.

---

## **`dem install DEV_ENV_NAME`**

Install the selected Development Environment. Set installed flag to True. Dem checks which tool image is
required by the selected local Development Environments and in case the tool image is
not installed, the dem installs it.

Arguments:

`DEV_ENV_NAME` Name of the Development Environment to install. [required]

---

## **`dem uninstall DEV_ENV_NAME`**

Uninstall the selected Development Environment. Set installed flag to False if it was True. Dem checks whether a tool image is
required or not by any of the remaining installed local Development Environments. In case the tool image is
not required anymore, the dem delete it.

Arguments:

`DEV_ENV_NAME` Name of the Development Environment to uninstall. [required]

---

## **`dem del-host NAME`**

Delete a host from the config file.
Expand Down
93 changes: 93 additions & 0 deletions tests/cli/test_install_cmd.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
"""Tests for the install command."""

# Unit under test:
import dem.cli.main as main
import dem.cli.command.install_cmd as install_cmd

# Test framework
from typer.testing import CliRunner
from unittest.mock import patch, MagicMock

## Global test variables
runner = CliRunner()

@patch("dem.cli.command.install_cmd.stderr.print")
def test_install_dev_env_invalid_name(mock_stderr_print):
# Test setup
test_invalid_name = "fake_dev_env_name"

mock_platform = MagicMock()
mock_platform.get_dev_env_by_name.return_value = None
main.platform = mock_platform

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

# Check expectations
assert 0 == runner_result.exit_code

mock_platform.get_dev_env_by_name.assert_called_once_with(test_invalid_name)
mock_stderr_print.assert_called_once_with(f"[red]Error: The {test_invalid_name} Development Environment does not exist.[/]")



@patch("dem.cli.command.install_cmd.stdout.print")
def test_install_dev_env_valid_name(mock_stdout_print):
# Test setup
fake_dev_env_to_install = MagicMock()
fake_dev_env_to_install.name = "dev_env"
fake_dev_env_to_install.is_installed = False
mock_platform = MagicMock()
mock_platform.get_dev_env_by_name.return_value = fake_dev_env_to_install
main.platform = mock_platform

# Run unit under test
runner_result = runner.invoke(main.typer_cli, ["install", fake_dev_env_to_install.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_install.name )
mock_platform.install_dev_env.assert_called_once_with(fake_dev_env_to_install)
mock_stdout_print.assert_called_once_with(f"[green]Successfully installed the {fake_dev_env_to_install.name}![/]")


@patch("dem.cli.command.install_cmd.stderr.print")
def test_install_dev_env_already_installed(mock_stderr_print):
# Test setup
fake_dev_env_to_install = MagicMock()
fake_dev_env_to_install.name = "dev_env"
fake_dev_env_to_install.is_installed = True
mock_platform = MagicMock()
mock_platform.get_dev_env_by_name.return_value = fake_dev_env_to_install
main.platform = mock_platform

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

# Check expectations
assert 0 == runner_result.exit_code

mock_stderr_print.assert_called_once_with(f"[red]Error: The {fake_dev_env_to_install.name} Development Environment is already installed.[/]")

@patch("dem.cli.command.install_cmd.stderr.print")
def test_install_dev_env_valid_name_failed(mock_stderr_print):
# Test setup
fake_dev_env_to_install = MagicMock()
fake_dev_env_to_install.name = "dev_env"
fake_dev_env_to_install.is_installed = False
mock_platform = MagicMock()
mock_platform.get_dev_env_by_name.return_value = fake_dev_env_to_install
test_exception_text = "test_exception_text"
mock_platform.install_dev_env.side_effect = install_cmd.PlatformError(test_exception_text)
main.platform = mock_platform

# Run unit under test
runner_result = runner.invoke(main.typer_cli, ["install", fake_dev_env_to_install.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_install.name )
mock_stderr_print.assert_called_once_with(f"[red]Error: Platform error: {test_exception_text}[/]")

39 changes: 36 additions & 3 deletions tests/core/test_platform.py
Original file line number Diff line number Diff line change
Expand Up @@ -292,16 +292,19 @@ def test_Platform_get_dev_env_by_name_no_match(mock___init__: MagicMock) -> None

mock___init__.assert_called_once()

@patch.object(platform.Platform, "flush_descriptors")
@patch.object(platform.Platform, "tool_images")
@patch.object(platform.Platform, "container_engine")
@patch.object(platform.Platform, "user_output")
@patch.object(platform.Platform, "__init__")
def test_Platform_install_dev_env(mock___init__: MagicMock, mock_user_input: MagicMock,
mock_container_engine: MagicMock, mock_tool_images) -> None:
def test_Platform_install_dev_env_succes(mock___init__: MagicMock, mock_user_input: MagicMock,
mock_container_engine: MagicMock, mock_tool_images,
mock_flush_descriptors: MagicMock) -> None:
# Test setup
mock___init__.return_value = None


test_dev_env = MagicMock()
test_dev_env = MagicMock()
test_registry_only_tool_images: list[str] = ["test_image_name1:test_image_version1",
"test_image_name2:test_image_version2"]
test_dev_env.get_registry_only_tool_images.return_value = test_registry_only_tool_images
Expand All @@ -323,6 +326,36 @@ def test_Platform_install_dev_env(mock___init__: MagicMock, mock_user_input: Mag
call(test_registry_only_tool_images[0]),
call(test_registry_only_tool_images[1])
])
mock_flush_descriptors.assert_called_once()

@patch.object(platform.Platform, "tool_images")
@patch.object(platform.Platform, "container_engine")
@patch.object(platform.Platform, "user_output")
@patch.object(platform.Platform, "__init__")
def test_Platform_install_dev_env_failure(mock___init__: MagicMock, mock_user_output: MagicMock,
mock_container_engine: MagicMock,mock_tool_images) -> None:
# Test setup
mock___init__.return_value = None


test_dev_env = MagicMock()
test_registry_only_tool_images: list[str] = ["test_image_name1:test_image_version1",
"test_image_name2:test_image_version2"]
test_dev_env.get_registry_only_tool_images.return_value = test_registry_only_tool_images

test_platform = platform.Platform()

mock_container_engine.pull.side_effect = platform.ContainerEngineError("")

# Run unit under test
with pytest.raises(platform.PlatformError) as exported_exception_info:
test_platform.install_dev_env(test_dev_env)

# Check expectations
mock___init__.assert_called_once()

assert str(exported_exception_info) == "Platform error: Dev Env install failed."


@patch.object(platform.Platform, "flush_descriptors")
@patch.object(platform.Platform, "container_engine")
Expand Down

0 comments on commit b9ae8e3

Please sign in to comment.