diff --git a/README.md b/README.md index ce123ab4..9730ba34 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,7 @@ Development Environments for embedded software development. > The DEM can be used locally, but it is in alpha state, so expect major new features!

-:star2: Contributors and early adopters are welcome! :star2: +Contributors and early adopters are welcome!

## Concept @@ -85,21 +85,25 @@ To be able to use the DEM on your PC, you need to have the following software in ## Installation -DEM is available in the [PyPI repository](https://pypi.org/project/axem-dem/). Install it with: +Use the following install script to get the latest version of DEM: + curl -fsSL 'https://raw.githubusercontent.com/axem-solutions/dem/main/install-dem.sh' | bash + +### Alternative installation + +If all the prerequisites are fulfilled, the DEM can be installed from the +[PyPI repository](https://pypi.org/project/axem-dem/): pip install axem-dem :information_source: The package name is axem-dem, but the command is `dem`. +### Enable autocompletion -You can also install it with install-dem.sh from our repository. The installer script checks if the corresponding python version is available and installs the docker and axem-dem pip module. -Download it with the following command: +After installation, you can enable the autocompletion for bash and zsh shells - curl 'https://raw.githubusercontent.com/axem-solutions/dem/main/install-dem.sh' > install-dem.sh - -Then execute it: + dem --install-completion - ./install-dem.sh +> Note for zsh users: `compinit` must be called from your .zshrc. ## Quick start diff --git a/dem/__main__.py b/dem/__main__.py index a3048393..864af2c2 100644 --- a/dem/__main__.py +++ b/dem/__main__.py @@ -3,15 +3,19 @@ from dem import __command__ from dem.cli.console import stderr, stdout -from dem.core.exceptions import RegistryError, ContainerEngineError +from dem.core.exceptions import RegistryError, ContainerEngineError, InternalError import dem.cli.main import docker.errors from dem.core.core import Core +from dem.core.platform import DevEnvLocalSetup from dem.cli.tui.tui_user_output import TUIUserOutput def main(): """ Entry point for the CLI application""" + # Create the Development Platform + dem.cli.main.platform = DevEnvLocalSetup() + # Connect the UI to the user output interface Core.set_user_output(TUIUserOutput()) @@ -30,7 +34,7 @@ def main(): stdout.print("\nHint: The input repository might not exist in the registry.") elif "400" in str(e): stdout.print("\nHint: The input parameters might not be valid.") - except ContainerEngineError as e: + except (ContainerEngineError, InternalError) as e: stderr.print("[red]" + str(e) + "[/]") # Call the main() when run as `python -m` diff --git a/dem/cli/command/add_cat_cmd.py b/dem/cli/command/add_cat_cmd.py index 01c82cb9..ffcaedb7 100644 --- a/dem/cli/command/add_cat_cmd.py +++ b/dem/cli/command/add_cat_cmd.py @@ -4,14 +4,14 @@ from dem.core.platform import DevEnvLocalSetup from dem.cli.console import stdout -def execute(name: str, url:str) -> None: +def execute(platform: DevEnvLocalSetup, name: str, url:str) -> None: """ Add a new Dev Env Catalog. Args: name -- name of the catalog url -- URL of the catalog's JSON file """ - platform = DevEnvLocalSetup() + catalog_config = { "name": name, "url": url diff --git a/dem/cli/command/add_host_cmd.py b/dem/cli/command/add_host_cmd.py index 8f6d6775..7a26bb65 100644 --- a/dem/cli/command/add_host_cmd.py +++ b/dem/cli/command/add_host_cmd.py @@ -2,23 +2,19 @@ from dem.core.platform import DevEnvLocalSetup from dem.cli.console import stdout -import json -import os -def execute(name: str, address: str) -> None: +def execute(platform: DevEnvLocalSetup, name: str, address: str) -> None: """ Add a new host. Args: name -- name of the host address -- IP or hostname of the host """ - if not name or not address: stdout.print("[red]Error: NAME or ADDRESS cannot be empty.[/]") exit(1) - platform = DevEnvLocalSetup() - data = platform.config_file.deserialized.get("hosts", []) # this way the data object is a list + data = platform.config_file.deserialized.get("hosts", []) if not data: platform.config_file.deserialized["hosts"] = [{"name": name, "address": address}] diff --git a/dem/cli/command/add_reg_cmd.py b/dem/cli/command/add_reg_cmd.py index a518f5e1..d1ea8d23 100644 --- a/dem/cli/command/add_reg_cmd.py +++ b/dem/cli/command/add_reg_cmd.py @@ -4,14 +4,14 @@ from dem.core.platform import DevEnvLocalSetup from dem.cli.console import stdout -def execute(name: str, url:str) -> None: +def execute(platform: DevEnvLocalSetup, name: str, url:str) -> None: """ Add a new registry. Args: name -- name or IP address of the registry url -- API URL of the registry """ - platform = DevEnvLocalSetup() + registry = { "name": name, "url": url diff --git a/dem/cli/command/cp_cmd.py b/dem/cli/command/cp_cmd.py index 5422aa4f..2f89136d 100644 --- a/dem/cli/command/cp_cmd.py +++ b/dem/cli/command/cp_cmd.py @@ -29,8 +29,7 @@ def cp_given_dev_env(platform: DevEnvLocalSetup, dev_env_to_cp: DevEnv, platform.local_dev_envs.append(new_dev_env) platform.flush_to_file() -def execute(dev_env_to_cp_name: str, new_dev_env_name: str) -> None: - platform = DevEnvLocalSetup() +def execute(platform: DevEnvLocalSetup, dev_env_to_cp_name: str, new_dev_env_name: str) -> None: dev_env_to_cp = get_dev_env_to_cp(platform, dev_env_to_cp_name) if (dev_env_to_cp is not None and diff --git a/dem/cli/command/create_cmd.py b/dem/cli/command/create_cmd.py index 6fd2c17a..91a58ed7 100644 --- a/dem/cli/command/create_cmd.py +++ b/dem/cli/command/create_cmd.py @@ -172,8 +172,7 @@ def create_dev_env(platform: DevEnvLocalSetup, dev_env_name: str) -> DevEnv: return new_dev_env -def execute(dev_env_name: str) -> None: - platform = DevEnvLocalSetup() +def execute(platform: DevEnvLocalSetup, dev_env_name: str) -> None: dev_env = create_dev_env(platform, dev_env_name) # Validate the Dev Env creation diff --git a/dem/cli/command/del_cat_cmd.py b/dem/cli/command/del_cat_cmd.py index 1fef56fd..763c75d2 100644 --- a/dem/cli/command/del_cat_cmd.py +++ b/dem/cli/command/del_cat_cmd.py @@ -4,13 +4,11 @@ from dem.core.platform import DevEnvLocalSetup from dem.cli.console import stdout, stderr -def execute(catalog_name: str) -> None: +def execute(platform: DevEnvLocalSetup, catalog_name: str) -> None: """ Delete the Dev Env Catalog. Args: catalog_name -- name of the catalog to delete """ - platform = DevEnvLocalSetup() - for catalog_config in platform.dev_env_catalogs.list_catalog_configs(): if catalog_config["name"] == catalog_name: platform.dev_env_catalogs.delete_catalog(catalog_config) diff --git a/dem/cli/command/del_reg_cmd.py b/dem/cli/command/del_reg_cmd.py index fd3b38a7..58aff53d 100644 --- a/dem/cli/command/del_reg_cmd.py +++ b/dem/cli/command/del_reg_cmd.py @@ -4,13 +4,11 @@ from dem.core.platform import DevEnvLocalSetup from dem.cli.console import stdout, stderr -def execute(registry_name: str) -> None: +def execute(platform: DevEnvLocalSetup, registry_name: str) -> None: """ Delete the registry. Args: registry_name -- name of the registry to delete """ - platform = DevEnvLocalSetup() - for registry in platform.registries.list_registry_configs(): if registry["name"] == registry_name: platform.registries.delete_registry(registry) diff --git a/dem/cli/command/delete_cmd.py b/dem/cli/command/delete_cmd.py index d91b1d3d..121ffce5 100644 --- a/dem/cli/command/delete_cmd.py +++ b/dem/cli/command/delete_cmd.py @@ -33,8 +33,7 @@ def remove_unused_tool_images(deleted_dev_env: DevEnv, dev_env_local_setup: DevE if tool_image not in all_required_tool_images: try_to_delete_tool_image(tool_image, dev_env_local_setup) -def execute(dev_env_name: str) -> None: - platform = DevEnvLocalSetup() +def execute(platform: DevEnvLocalSetup, dev_env_name: str) -> None: dev_env_to_delete = platform.get_dev_env_by_name(dev_env_name) if dev_env_to_delete is None: diff --git a/dem/cli/command/export_cmd.py b/dem/cli/command/export_cmd.py index 93775e5e..079e23bc 100644 --- a/dem/cli/command/export_cmd.py +++ b/dem/cli/command/export_cmd.py @@ -8,14 +8,14 @@ import json, os def check_is_directory(param: str): - if None != param: + if "" != param: return(os.path.isdir(param)) else: return False def check_is_path_contains_spec_char(param: str): special_chars=re.compile('[~/\^]') - if None != param: + if "" != param: if None != special_chars.search(param): return True else: @@ -34,7 +34,7 @@ def create_exported_dev_env_json(dev_env_name: str,dev_env_json: str,given_path: elif True == check_is_path_contains_spec_char(given_path): file_name="" file_path=given_path - elif None != given_path: + elif "" != given_path: file_name=given_path file_path="" else: @@ -45,8 +45,7 @@ def create_exported_dev_env_json(dev_env_name: str,dev_env_json: str,given_path: json.dump(dev_env_json, exported_file, indent=4) exported_file.close() -def execute(dev_env_name: str, path_to_export: str) -> None: - platform = DevEnvLocalSetup() +def execute(platform: DevEnvLocalSetup, dev_env_name: str, path_to_export: str) -> None: dev_env_to_export = platform.get_dev_env_by_name(dev_env_name) if dev_env_to_export is not None: try: diff --git a/dem/cli/command/info_cmd.py b/dem/cli/command/info_cmd.py index dda7fc00..771db3f4 100644 --- a/dem/cli/command/info_cmd.py +++ b/dem/cli/command/info_cmd.py @@ -25,8 +25,7 @@ def print_info(dev_env: (DevEnv | DevEnv)) -> None: image_status_messages[tool["image_status"]]) stdout.print(tool_info_table) -def execute(arg_dev_env_name: str) -> None: - platform = DevEnvLocalSetup() +def execute(platform: DevEnvLocalSetup, arg_dev_env_name: str) -> None: dev_env = platform.get_dev_env_by_name(arg_dev_env_name) if dev_env is None: diff --git a/dem/cli/command/list_cat_cmd.py b/dem/cli/command/list_cat_cmd.py index 7374619e..730a2bcc 100644 --- a/dem/cli/command/list_cat_cmd.py +++ b/dem/cli/command/list_cat_cmd.py @@ -5,9 +5,8 @@ from dem.cli.console import stdout from rich.table import Table -def execute() -> None: +def execute(platform: DevEnvLocalSetup) -> None: """ List available Development Environment Catalogs.""" - platform = DevEnvLocalSetup() catalog_config = None table = Table() table.add_column("name") diff --git a/dem/cli/command/list_cmd.py b/dem/cli/command/list_cmd.py index 4800bed9..da9ed6f4 100644 --- a/dem/cli/command/list_cmd.py +++ b/dem/cli/command/list_cmd.py @@ -116,8 +116,7 @@ def list_tool_images(platform: DevEnvLocalSetup, local: bool, org: bool) -> None else: stdout.print("[yellow]No images are available in the registries!") -def execute(local: bool, org: bool, env: bool, tool: bool) -> None: - platform = DevEnvLocalSetup() +def execute(platform: DevEnvLocalSetup, local: bool, org: bool, env: bool, tool: bool) -> None: if ((local == True) or (org == True)) and (env == True) and (tool == False): list_dev_envs(platform, local, org) elif ((local == True) or (org == True)) and (env == False) and (tool == True): diff --git a/dem/cli/command/list_reg_cmd.py b/dem/cli/command/list_reg_cmd.py index 41b70d7c..f77d7f51 100644 --- a/dem/cli/command/list_reg_cmd.py +++ b/dem/cli/command/list_reg_cmd.py @@ -5,9 +5,8 @@ from dem.cli.console import stdout from rich.table import Table -def execute() -> None: +def execute(platform: DevEnvLocalSetup) -> None: """ List available registries.""" - platform = DevEnvLocalSetup() registry = None table = Table() table.add_column("name") diff --git a/dem/cli/command/load_cmd.py b/dem/cli/command/load_cmd.py index 9b42cdd4..9cfaf6b6 100644 --- a/dem/cli/command/load_cmd.py +++ b/dem/cli/command/load_cmd.py @@ -33,9 +33,7 @@ def load_dev_env_to_dev_env_json(dev_env_local_setup: DevEnvLocalSetup,path_to_d raw_file.close() return True -def execute(path_to_dev_env: str) -> None: - platform = DevEnvLocalSetup() - +def execute(platform: DevEnvLocalSetup, path_to_dev_env: str) -> None: if check_is_file_exist(path_to_dev_env) is True: retval = load_dev_env_to_dev_env_json(platform,path_to_dev_env) if retval == True: diff --git a/dem/cli/command/modify_cmd.py b/dem/cli/command/modify_cmd.py index 0a41c474..7817f6b8 100644 --- a/dem/cli/command/modify_cmd.py +++ b/dem/cli/command/modify_cmd.py @@ -172,8 +172,7 @@ def handle_user_confirm(confirmation: str, dev_env_local: DevEnv, dev_env_local_setup.pull_images(dev_env_local.tools) -def execute(dev_env_name: str) -> None: - platform = DevEnvLocalSetup() +def execute(platform: DevEnvLocalSetup, dev_env_name: str) -> None: dev_env_local = platform.get_dev_env_by_name(dev_env_name) if dev_env_local is None: diff --git a/dem/cli/command/pull_cmd.py b/dem/cli/command/pull_cmd.py index 8642de53..612ce2b8 100644 --- a/dem/cli/command/pull_cmd.py +++ b/dem/cli/command/pull_cmd.py @@ -34,9 +34,7 @@ def install_to_dev_env_json(local_dev_env: DevEnv | None, catalog_dev_env: DevEn return local_dev_env -def execute(dev_env_name: str) -> None: - # Get the organization's Dev Env if available. - platform = DevEnvLocalSetup() +def execute(platform: DevEnvLocalSetup, dev_env_name: str) -> None: catalog_dev_env: DevEnv | None = None if not platform.dev_env_catalogs.catalogs: diff --git a/dem/cli/command/rename_cmd.py b/dem/cli/command/rename_cmd.py index ea5b4389..766547d5 100644 --- a/dem/cli/command/rename_cmd.py +++ b/dem/cli/command/rename_cmd.py @@ -4,8 +4,7 @@ from dem.core.platform import DevEnvLocalSetup from dem.cli.console import stderr -def execute(dev_env_name_to_rename: str, new_dev_env_name: str) -> None: - platform = DevEnvLocalSetup() +def execute(platform: DevEnvLocalSetup, dev_env_name_to_rename: str, new_dev_env_name: str) -> None: dev_env_to_rename = platform.get_dev_env_by_name(dev_env_name_to_rename) if dev_env_to_rename is not None: diff --git a/dem/cli/command/run_cmd.py b/dem/cli/command/run_cmd.py index 5e5bc2ad..605e78c6 100644 --- a/dem/cli/command/run_cmd.py +++ b/dem/cli/command/run_cmd.py @@ -26,7 +26,7 @@ def handle_missing_tool_images(missing_tool_images: set[str], dev_env_local: Dev platform.pull_images(dev_env_local.tools) stdout.print("[green]DEM fixed the " + dev_env_local.name + "![/]") -def execute(dev_env_name: str, container_arguments: list[str]) -> None: +def execute(platform: DevEnvLocalSetup, dev_env_name: str, container_arguments: list[str]) -> None: """ Execute the run command in the given Dev Env context. If something is wrong with the Dev Env the DEM can try to fix it. @@ -34,7 +34,7 @@ def execute(dev_env_name: str, container_arguments: list[str]) -> None: dev_env_name -- name of the Development Environment container_arguments -- arguments passed to the container """ - platform = DevEnvLocalSetup() + dev_env_local = platform.get_dev_env_by_name(dev_env_name) if dev_env_local is None: diff --git a/dem/cli/main.py b/dem/cli/main.py index 782a137d..57fe1915 100644 --- a/dem/cli/main.py +++ b/dem/cli/main.py @@ -2,21 +2,66 @@ # dem/cli/main.py import typer, importlib.metadata -from typing import Optional +from typing import Generator +from typing_extensions import Annotated from dem import __command__, __app_name__ 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, add_reg_cmd, \ list_reg_cmd, del_reg_cmd, add_cat_cmd, list_cat_cmd, del_cat_cmd, \ add_host_cmd -from dem.cli.console import stdout, stderr +from dem.cli.console import stdout +from dem.core.platform import DevEnvLocalSetup +from dem.core.exceptions import InternalError -typer_cli = typer.Typer(rich_markup_mode="rich") +typer_cli: typer.Typer = typer.Typer(rich_markup_mode="rich") +platform: DevEnvLocalSetup | None = None -@typer_cli.command("list") -def list_(local: bool = typer.Option(False, help="Scope is the local host."), - all: bool = typer.Option(False, help="Scope is the organization."), - env: bool = typer.Option(False, help="List the environments."), - tool: bool = typer.Option(False, help="List the tool images.")) -> None: +# Autocomplete functions +def autocomplete_dev_env_name(incomplete: str) -> Generator: + """ + Autocomplete the input Dev Env name with the available matching local Dev Envs. + + Return with the matching Dev Env names by a Generator. + + Args: + incomplete -- the parameter the user supplied so far when the tab was pressed + """ + for dev_env in platform.local_dev_envs: + if dev_env.name.startswith(incomplete) or (incomplete == ""): + yield dev_env.name + +def autocomplete_cat_name(incomplete: str) -> Generator: + """ + Autocomplete the input Catalog name with the available matching catalogs. + + Return with the matching Catalog name by a Generator. + + Args: + incomplete -- the parameter the user supplied so far when the tab was pressed + """ + for catalog_config in platform.dev_env_catalogs.list_catalog_configs(): + if catalog_config["name"].startswith(incomplete) or (incomplete == ""): + yield catalog_config["name"] + +def autocomplete_reg_name(incomplete: str) -> Generator: + """ + Autocomplete the input Registry name with the available matching Registries. + + Return with the matching Registry name by a Generator. + + Args: + incomplete -- the parameter the user supplied so far when the tab was pressed + """ + for registry_config in platform.registries.list_registry_configs(): + if registry_config["name"].startswith(incomplete) or (incomplete == ""): + yield registry_config["name"] + +# DEM commands +@typer_cli.command("list") # "list" is a Python keyword +def list_(local: Annotated[bool, typer.Option(help="Scope is the local host.")] = False, + all: Annotated[bool, typer.Option(help="Scope is the organization.")] = False, + env: Annotated[bool, typer.Option(help="List the environments.")] = False, + tool: Annotated[bool, typer.Option(help="List the tool images.")] = False) -> None: """ List the Development Environments available locally or for the organization. @@ -30,86 +75,119 @@ def list_(local: bool = typer.Option(False, help="Scope is the local host."), --all --tool -> List the tool images available in the axemsolutions registry. """ - list_cmd.execute(local, all, env, tool) + if platform is not None: + list_cmd.execute(platform, local, all, env, tool) + else: + raise InternalError("Error: The platform hasn't been initialized properly!") @typer_cli.command() -def info(dev_env_name: str = typer.Argument(..., - help="Name of the Development Environment to get info about.")) -> None: +def info(dev_env_name: Annotated[str, typer.Argument(help="Name of the Development Environment to get info about.", + autocompletion=autocomplete_dev_env_name)]) -> None: """ - Get information about the specified Development Environment. + Get information about the specified Development Environment available locally or in the catalogs. + + Note: Autocomplete only works with the locally avialable Dev Envs. """ - info_cmd.execute(dev_env_name) + if platform is not None: + info_cmd.execute(platform, dev_env_name) + else: + raise InternalError("Error: The platform hasn't been initialized properly!") @typer_cli.command() -def pull(dev_env_name: str = typer.Argument(..., - help="Name of the Development Environment to install.")) -> None: +def pull(dev_env_name: Annotated[str, typer.Argument(help="Name of the Development Environment to install.")]) -> None: """ Pull all the required tool images from the registry and install the Development Environment locally. """ - pull_cmd.execute(dev_env_name) + if platform is not None: + pull_cmd.execute(platform, dev_env_name) + else: + raise InternalError("Error: The platform hasn't been initialized properly!") @typer_cli.command() -def cp(dev_env_name: str = typer.Argument(...,help="Name of the Development Environment to cp."), - new_dev_env_name: str = typer.Argument(...,help="Name of the New Development Environment.")) -> None: +def cp(dev_env_name: Annotated[str, typer.Argument(help="Name of the Development Environment to cp.", + autocompletion=autocomplete_dev_env_name)], + new_dev_env_name: Annotated[str, typer.Argument(help="Name of the New Development Environment.")]) -> None: """ - cp existing Development Environment locally. + Create a copy of a local Dev Env. """ - cp_cmd.execute(dev_env_name,new_dev_env_name) + if platform is not None: + cp_cmd.execute(platform, dev_env_name, new_dev_env_name) + else: + raise InternalError("Error: The platform hasn't been initialized properly!") @typer_cli.command() -def create(dev_env_name: str = typer.Argument(..., - help="Name of the Development Environment to create."),) -> None: +def create(dev_env_name: Annotated[str, typer.Argument(help="Name of the Development Environment to create.")]) -> None: """ Create a new Development Environment. """ - create_cmd.execute(dev_env_name) + if platform is not None: + create_cmd.execute(platform, dev_env_name) + else: + raise InternalError("Error: The platform hasn't been initialized properly!") @typer_cli.command() -def export(dev_env_name: str = typer.Argument(...,help="Name of the Development Environment to export."), - path_to_export: str = typer.Argument(None,help="Path where to extract the Dev Env.")) -> None: +def export(dev_env_name: Annotated[str, typer.Argument(help="Name of the Development Environment to export.", + autocompletion=autocomplete_dev_env_name)], + path_to_export: Annotated[str, typer.Argument(help="Path where to extract the Dev Env.")] = "") -> None: """ Export the Development Environment. """ - export_cmd.execute(dev_env_name,path_to_export) + if platform is not None: + export_cmd.execute(platform, dev_env_name,path_to_export) + else: + raise InternalError("Error: The platform hasn't been initialized properly!") @typer_cli.command() -def load(path_to_dev_env: str = typer.Argument(...,help="Path to the Dev Env to import.")) -> None: +def load(path_to_dev_env: Annotated[str, typer.Argument(help="Path to the Dev Env to import.")]) -> None: """ Import the Development Environment. """ - load_cmd.execute(path_to_dev_env) + if platform is not None: + load_cmd.execute(platform, path_to_dev_env) + else: + raise InternalError("Error: The platform hasn't been initialized properly!") @typer_cli.command() -def rename(dev_env_name: str = typer.Argument(...,help="Name of the Development Environment to rename."), - new_dev_env_name: str = typer.Argument(...,help="The new name.")) -> None: +def rename(dev_env_name: Annotated[str, typer.Argument(help="Name of the Development Environment to rename.", + autocompletion=autocomplete_dev_env_name)], + new_dev_env_name: Annotated[str, typer.Argument(help="The new name.")]) -> None: """ Rename the Development Environment. """ - rename_cmd.execute(dev_env_name,new_dev_env_name) + if platform is not None: + rename_cmd.execute(platform, dev_env_name,new_dev_env_name) + else: + raise InternalError("Error: The platform hasn't been initialized properly!") @typer_cli.command() -def modify(dev_env_name: str = typer.Argument(..., - help="Name of the Development Environment to modify.")) -> None: +def modify(dev_env_name: Annotated[str, typer.Argument(help="Name of the Development Environment to modify.", + autocompletion=autocomplete_dev_env_name)]) -> None: """ Modify the tool types and required tool images for an existing Development Environment. """ - modify_cmd.execute(dev_env_name) + if platform is not None: + modify_cmd.execute(platform, dev_env_name) + else: + raise InternalError("Error: The platform hasn't been initialized properly!") @typer_cli.command() -def delete(dev_env_name: str = typer.Argument(..., - help="Name of the Development Environment to delete.")) -> None: +def delete(dev_env_name: Annotated[str, typer.Argument(help="Name of the Development Environment to delete.", + autocompletion=autocomplete_dev_env_name)]) -> None: """ Delete the Development Environment from the local setup. If a tool image is not required anymore by any of the available local Development Environments, the DEM asks the user whether they want to delete that image or not. """ - delete_cmd.execute(dev_env_name) + if platform is not None: + delete_cmd.execute(platform, dev_env_name) + else: + raise InternalError("Error: The platform hasn't been initialized properly!") @typer_cli.command(context_settings={"allow_extra_args": True, "ignore_unknown_options": True}) -def run(dev_env_name: str = typer.Argument(..., - help="Run the container in this Development Environment context"), - ctx: typer.Context = typer.Option(None)) -> None: +def run(dev_env_name: Annotated[str, typer.Argument(help="Run the container in this Development Environment context", + autocompletion=autocomplete_dev_env_name)], + ctx: Annotated[typer.Context, typer.Option()]) -> None: """ Run the `docker run` command in the Development Environment's context with the given parameters. @@ -119,11 +197,14 @@ def run(dev_env_name: str = typer.Argument(..., See the documentation for the list of currently supported docker run parameters. """ - run_cmd.execute(dev_env_name, ctx.args) + if platform is not None: + run_cmd.execute(platform, dev_env_name, ctx.args) + else: + raise InternalError("Error: The platform hasn't been initialized properly!") @typer_cli.command() -def add_reg(name: str = typer.Argument(..., help="Name of the registry to add"), - url: str = typer.Argument(..., help="API URL of the registry")) -> None: +def add_reg(name: Annotated[str, typer.Argument(help="Name of the registry to add")], + url: Annotated[str, typer.Argument(help="API URL of the registry")]) -> None: """ Add a new registry. @@ -135,25 +216,35 @@ def add_reg(name: str = typer.Argument(..., help="Name of the registry to add"), The URL should point to the registry's REST API. For the Docker Hub its https://registry.hub.docker.com, or it can be http://localhost:5000 for a self-hosted one. """ - add_reg_cmd.execute(name, url) + if platform is not None: + add_reg_cmd.execute(platform, name, url) + else: + raise InternalError("Error: The platform hasn't been initialized properly!") @typer_cli.command() def list_reg() -> None: """ List the available registries. """ - list_reg_cmd.execute() + if platform is not None: + list_reg_cmd.execute(platform) + else: + raise InternalError("Error: The platform hasn't been initialized properly!") @typer_cli.command() -def del_reg(registry_name: str = typer.Argument(..., help="Name or IP address of the registry to delete.")) -> None: +def del_reg(registry_name: Annotated[str, typer.Argument(help="Name or IP address of the registry to delete.", + autocompletion=autocomplete_reg_name)]) -> None: """ Delete a registry. """ - del_reg_cmd.execute(registry_name) + if platform is not None: + del_reg_cmd.execute(platform, registry_name) + else: + raise InternalError("Error: The platform hasn't been initialized properly!") @typer_cli.command() -def add_cat(name: str = typer.Argument(..., help="Name of the Development Environment Catalog to add"), - url: str = typer.Argument(..., help="URL of the Development Environment Catalog's JSON file")) -> None: +def add_cat(name: Annotated[str, typer.Argument(help="Name of the Development Environment Catalog to add")], + url: Annotated[str, typer.Argument(help="URL of the Development Environment Catalog's JSON file")]) -> None: """ Add a new catalog. @@ -161,28 +252,43 @@ def add_cat(name: str = typer.Argument(..., help="Name of the Development Enviro The URL must point to an HTTP(S) server where the Catalog json file is available. """ - add_cat_cmd.execute(name, url) + if platform is not None: + add_cat_cmd.execute(platform, name, url) + else: + raise InternalError("Error: The platform hasn't been initialized properly!") @typer_cli.command() def list_cat() -> None: """ List the available catalogs. """ - list_cat_cmd.execute() + if platform is not None: + list_cat_cmd.execute(platform) + else: + raise InternalError("Error: The platform hasn't been initialized properly!") @typer_cli.command() -def del_cat(registry_name: str = typer.Argument(..., help="Name of the Development Environment Catalog to delete.")) -> None: +def del_cat(catalog_name: Annotated[str, typer.Argument(help="Name of the Development Environment Catalog to delete.", + autocompletion=autocomplete_cat_name)]) -> None: """ Delete a catalog. """ - del_cat_cmd.execute(registry_name) + if platform is not None: + del_cat_cmd.execute(platform, catalog_name) + else: + raise InternalError("Error: The platform hasn't been initialized properly!") + @typer_cli.command() -def add_host(name: str = typer.Argument(..., help="Name of the host"), - address: str = typer.Argument(..., help="IP or hostname of the host")) -> None: +def add_host(name: Annotated[str, typer.Argument(help="Name of the host")], + address: Annotated[str, typer.Argument(help="IP or hostname of the host")]) -> None: """ Add a new host. """ - add_host_cmd.execute(name, address) + if platform is not None: + add_host_cmd.execute(platform, name, address) + else: + raise InternalError("Error: The platform hasn't been initialized properly!") + def _version_callback(value: bool) -> None: if value: try: diff --git a/dem/core/exceptions.py b/dem/core/exceptions.py index 23f20fad..23751b29 100644 --- a/dem/core/exceptions.py +++ b/dem/core/exceptions.py @@ -19,4 +19,8 @@ class ContainerEngineError(Exception): base_message = "Container engine error: " def __init__(self, message: str) -> None: - super().__init__(self.base_message + message) \ No newline at end of file + super().__init__(self.base_message + message) + +class InternalError(Exception): + """Raised when an object is used incorrectly.""" + pass \ No newline at end of file diff --git a/docs/installation.md b/docs/installation.md index 6257095a..07af93a8 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -11,26 +11,25 @@ To use the DEM on your PC, you need to have the following tools installed: ## Installation -dem is available in the PyPI repository. Install it with: +Use the following install script to get the latest version of DEM: + curl -fsSL 'https://raw.githubusercontent.com/axem-solutions/dem/main/install-dem.sh' | bash - pip install axem-dem +### Alternative installation -And that's it! Now you should be able to use the `dem` command. +If all the prerequisites are fulfilled, the DEM can be installed from the +[PyPI repository](https://pypi.org/project/axem-dem/): -!!! info + pip install axem-dem - The package name is axem-dem, but the command is `dem`. +:information_source: The package name is axem-dem, but the command is `dem`. +### Enable autocompletion -You can also install it with install-dem.sh from our repository. The installer script checks if the -corresponding python version is available and installs the docker and axem-dem pip module. -Download it with the following command: +After installation, you can enable the autocompletion for bash and zsh shells - curl 'https://raw.githubusercontent.com/axem-solutions/dem/main/install-dem.sh' > install-dem.sh - -Then execute it: + dem --install-completion - ./install-dem.sh +> Note for zsh users: `compinit` must be called from your .zshrc. ## Optional: Use the source code diff --git a/pyproject.toml b/pyproject.toml index d52a04db..f99e9240 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -10,16 +10,16 @@ documentation = "https://axemsolutions.io/dem_doc/" repository = "https://github.com/axem-solutions/dem" keywords = ["iot", "embedded", "edge", "devops", "tools", "containers"] classifiers = [ - "Development Status :: 3 - Alpha", - "Environment :: Console", - "Intended Audience :: Developers", - "Natural Language :: English", - "Topic :: Software Development", - "Topic :: Software Development :: Build Tools", - "Topic :: Software Development :: Compilers", - "Topic :: Software Development :: Debuggers", - "Topic :: Software Development :: Embedded Systems", - "Topic :: Software Development :: Testing" + "Development Status :: 3 - Alpha", + "Environment :: Console", + "Intended Audience :: Developers", + "Natural Language :: English", + "Topic :: Software Development", + "Topic :: Software Development :: Build Tools", + "Topic :: Software Development :: Compilers", + "Topic :: Software Development :: Debuggers", + "Topic :: Software Development :: Embedded Systems", + "Topic :: Software Development :: Testing" ] packages = [{include = "dem"}] @@ -50,13 +50,19 @@ pytest-cov = "^4.1.0" [tool.coverage.report] # Regexes for lines to exclude from consideration exclude_also = [ - "if __name__ == .__main__.:", - ] + "if __name__ == .__main__.:", +] + [tool.coverage.run] -omit =[ - # Tests are not needed for the absract base class. - "dem/core/user_output.py", - ] +omit = [ + # Tests are not needed for the absract base class. + "dem/core/user_output.py", +] + +[tool.pytest.ini_options] +filterwarnings = [ + "ignore::DeprecationWarning", +] [build-system] requires = ["poetry-core"] diff --git a/tests/cli/test_add_cat_cmd.py b/tests/cli/test_add_cat_cmd.py index f7e18bd1..610e97a4 100644 --- a/tests/cli/test_add_cat_cmd.py +++ b/tests/cli/test_add_cat_cmd.py @@ -14,11 +14,10 @@ runner = CliRunner(mix_stderr=False) ## Test cases -@patch("dem.cli.command.add_cat_cmd.DevEnvLocalSetup") -def test_add_cat(mock_DevEnvLocalSetup: MagicMock): +def test_add_cat(): # Test setup mock_platform = MagicMock() - mock_DevEnvLocalSetup.return_value = mock_platform + main.platform = mock_platform test_name = "test_name" test_url = "test_url" @@ -31,7 +30,6 @@ def test_add_cat(mock_DevEnvLocalSetup: MagicMock): # Check expectations assert runner_result.exit_code == 0 - mock_DevEnvLocalSetup.assert_called_once() mock_platform.dev_env_catalogs.list_catalog_configs.assert_called_once() expected_catalog = { "name": test_name, @@ -40,11 +38,10 @@ def test_add_cat(mock_DevEnvLocalSetup: MagicMock): mock_platform.dev_env_catalogs.add_catalog.assert_called_once_with(expected_catalog) @patch("dem.cli.command.add_cat_cmd.stdout.print") -@patch("dem.cli.command.add_cat_cmd.DevEnvLocalSetup") -def test_add_cat_already_added(mock_DevEnvLocalSetup: MagicMock, mock_stdout_print: MagicMock): +def test_add_cat_already_added(mock_stdout_print: MagicMock): # Test setup mock_platform = MagicMock() - mock_DevEnvLocalSetup.return_value = mock_platform + main.platform = mock_platform test_name = "test_name" test_url = "test_url" @@ -60,6 +57,5 @@ def test_add_cat_already_added(mock_DevEnvLocalSetup: MagicMock, mock_stdout_pri # Check expectations assert runner_result.exit_code == 0 - mock_DevEnvLocalSetup.assert_called_once() mock_platform.dev_env_catalogs.list_catalog_configs.assert_called_once() mock_stdout_print.assert_called_once_with("[yellow]The input catalog is already added.[/]") \ No newline at end of file diff --git a/tests/cli/test_add_host_cmd.py b/tests/cli/test_add_host_cmd.py index eb71cff9..ec04b68f 100644 --- a/tests/cli/test_add_host_cmd.py +++ b/tests/cli/test_add_host_cmd.py @@ -9,13 +9,12 @@ runner = CliRunner(mix_stderr=False) # Mocked DevEnvLocalSetup instance -mocked_platform = MagicMock() -mocked_platform.config_file.deserialized = {} - -@patch("dem.cli.command.add_host_cmd.DevEnvLocalSetup", return_value=mocked_platform) -def test_add_host(mock_platform): +def test_add_host(): # Test setup + mocked_platform = MagicMock() + mocked_platform.config_file.deserialized = {} + main.platform = mocked_platform test_name = "test_host_name" test_address = "test_host_address" @@ -28,11 +27,12 @@ def test_add_host(mock_platform): assert mocked_platform.config_file.deserialized["hosts"][0]["address"] == test_address mocked_platform.config_file.flush.assert_called_once() - -@patch("dem.cli.command.add_host_cmd.DevEnvLocalSetup", return_value=mocked_platform) @patch("builtins.input", return_value="yes") -def test_add_host_already_added(mock_input, mock_platform): +def test_add_host_already_added(mock_input): # Test setup + mocked_platform = MagicMock() + mocked_platform.config_file.deserialized = {} + main.platform = mocked_platform test_name = "test_host_name" test_address = "test_host_address" mocked_platform.config_file.deserialized["hosts"] = [{"name": test_name, "address": "old_address"}] @@ -45,12 +45,13 @@ def test_add_host_already_added(mock_input, mock_platform): assert mocked_platform.config_file.deserialized["hosts"][0]["address"] == test_address mocked_platform.config_file.flush.assert_called_once() - # Test for when the user declines to overwrite an existing host -@patch("dem.cli.command.add_host_cmd.DevEnvLocalSetup", return_value=mocked_platform) @patch("builtins.input", return_value="no") -def test_add_host_decline_overwrite(mock_input, mock_platform): +def test_add_host_decline_overwrite(mock_input): # Test setup + mocked_platform = MagicMock() + mocked_platform.config_file.deserialized = {} + main.platform = mocked_platform test_name = "test_host_name" test_address = "test_host_address" mocked_platform.config_file.deserialized["hosts"] = [{"name": test_name, "address": "old_address"}] @@ -62,8 +63,7 @@ def test_add_host_decline_overwrite(mock_input, mock_platform): assert mocked_platform.config_file.deserialized["hosts"][0]["address"] == "old_address" mocked_platform.config_file.flush.assert_not_called() -@patch("dem.cli.command.add_host_cmd.DevEnvLocalSetup", side_effect=Exception("Mocked exception")) -def test_add_host_exception(mock_platform): +def test_add_host_exception(): # Test setup test_name = "test_host_name" test_address = "test_host_address" @@ -73,29 +73,28 @@ def test_add_host_exception(mock_platform): # Check expectations assert runner_result.exit_code != 0 - # Remove the assertion for the exception message in the output + # Test for when the add-host command is invoked without any arguments -@patch("dem.cli.command.add_host_cmd.DevEnvLocalSetup", return_value=mocked_platform) -def test_add_host_no_arguments(mock_platform): +def test_add_host_no_arguments(): runner_result = runner.invoke(main.typer_cli, ["add-host"], color=True) assert runner_result.exit_code != 0 assert "Missing argument 'NAME'" in runner_result.stderr # Check stderr -@patch("dem.cli.command.add_host_cmd.DevEnvLocalSetup", return_value=mocked_platform) -def test_add_host_one_argument(mock_platform): +def test_add_host_one_argument(): runner_result = runner.invoke(main.typer_cli, ["add-host", "test_host_name"], color=True) assert runner_result.exit_code != 0 assert "Missing argument 'ADDRESS'" in runner_result.stderr # Check stderr -@patch("dem.cli.command.add_host_cmd.DevEnvLocalSetup", return_value=mocked_platform) -def test_add_host_invalid_arguments(mock_platform): +def test_add_host_invalid_arguments(): runner_result = runner.invoke(main.typer_cli, ["add-host", "", "test_host_address"], color=True) assert runner_result.exit_code != 0 assert "Error: NAME or ADDRESS cannot be empty." in runner_result.output -@patch("dem.cli.command.add_host_cmd.DevEnvLocalSetup", return_value=mocked_platform) @patch("builtins.input", side_effect=EOFError) -def test_add_host_no_user_input(mock_input, mock_platform): +def test_add_host_no_user_input(mock_input): + mocked_platform = MagicMock() + mocked_platform.config_file.deserialized = {} + main.platform = mocked_platform test_name = "test_host_name" test_address = "test_host_address" mocked_platform.config_file.deserialized["hosts"] = [{"name": test_name, "address": "old_address"}] @@ -103,9 +102,11 @@ def test_add_host_no_user_input(mock_input, mock_platform): assert runner_result.exit_code != 0 assert "Host addition cancelled." in runner_result.output -@patch("dem.cli.command.add_host_cmd.DevEnvLocalSetup", return_value=mocked_platform) @patch("builtins.input", side_effect=["invalid_choice", "yes"]) -def test_add_host_invalid_choice_then_yes(mock_input, mock_platform): +def test_add_host_invalid_choice_then_yes(mock_input): + mocked_platform = MagicMock() + mocked_platform.config_file.deserialized = {} + main.platform = mocked_platform test_name = "test_host_name" test_address = "test_host_address" mocked_platform.config_file.deserialized["hosts"] = [{"name": test_name, "address": "old_address"}] @@ -114,9 +115,11 @@ def test_add_host_invalid_choice_then_yes(mock_input, mock_platform): assert mocked_platform.config_file.deserialized["hosts"][0]["address"] == test_address # Test for when the user provides an invalid choice and then chooses 'no' -@patch("dem.cli.command.add_host_cmd.DevEnvLocalSetup", return_value=mocked_platform) @patch("builtins.input", side_effect=["invalid_choice", "no"]) -def test_add_host_invalid_choice_then_no(mock_input, mock_platform): +def test_add_host_invalid_choice_then_no(mock_input): + mocked_platform = MagicMock() + mocked_platform.config_file.deserialized = {} + main.platform = mocked_platform test_name = "test_host_name" test_address = "test_host_address" mocked_platform.config_file.deserialized["hosts"] = [{"name": test_name, "address": "old_address"}] @@ -125,8 +128,10 @@ def test_add_host_invalid_choice_then_no(mock_input, mock_platform): assert mocked_platform.config_file.deserialized["hosts"][0]["address"] == "old_address" # Test for adding a new host when the host name doesn't already exist -@patch("dem.cli.command.add_host_cmd.DevEnvLocalSetup", return_value=mocked_platform) -def test_add_new_host(mock_platform): +def test_add_new_host(): + mocked_platform = MagicMock() + mocked_platform.config_file.deserialized = {} + main.platform = mocked_platform test_name = "new_host_name" test_address = "new_host_address" mocked_platform.config_file.deserialized["hosts"] = [{"name": "existing_host_name", "address": "existing_host_address"}] @@ -135,8 +140,10 @@ def test_add_new_host(mock_platform): assert {"name": test_name, "address": test_address} in mocked_platform.config_file.deserialized["hosts"] # Test for adding a host when the data list is initially empty -@patch("dem.cli.command.add_host_cmd.DevEnvLocalSetup", return_value=mocked_platform) -def test_add_host_empty_data(mock_platform): +def test_add_host_empty_data(): + mocked_platform = MagicMock() + mocked_platform.config_file.deserialized = {} + main.platform = mocked_platform test_name = "test_host_name" test_address = "test_host_address" mocked_platform.config_file.deserialized = {} @@ -145,9 +152,11 @@ def test_add_host_empty_data(mock_platform): assert mocked_platform.config_file.deserialized["hosts"][0]["name"] == test_name assert mocked_platform.config_file.deserialized["hosts"][0]["address"] == test_address -@patch("dem.cli.command.add_host_cmd.DevEnvLocalSetup", return_value=mocked_platform) @patch("builtins.input", side_effect=["maybe", EOFError]) # First return "maybe", then raise EOFError -def test_add_host_eof_during_invalid_choice(mock_input, mock_platform): +def test_add_host_eof_during_invalid_choice(mock_input): + mocked_platform = MagicMock() + mocked_platform.config_file.deserialized = {} + main.platform = mocked_platform test_name = "test_host_name" test_address = "test_host_address" mocked_platform.config_file.deserialized["hosts"] = [{"name": test_name, "address": "old_address"}] diff --git a/tests/cli/test_add_reg_cmd.py b/tests/cli/test_add_reg_cmd.py index 6dadc985..77864ce7 100644 --- a/tests/cli/test_add_reg_cmd.py +++ b/tests/cli/test_add_reg_cmd.py @@ -14,11 +14,10 @@ runner = CliRunner(mix_stderr=False) ## Test cases -@patch("dem.cli.command.add_reg_cmd.DevEnvLocalSetup") -def test_add_reg(mock_DevEnvLocalSetup: MagicMock): +def test_add_reg(): # Test setup mock_platform = MagicMock() - mock_DevEnvLocalSetup.return_value = mock_platform + main.platform = mock_platform test_name = "test_name" test_url = "test_url" @@ -31,7 +30,6 @@ def test_add_reg(mock_DevEnvLocalSetup: MagicMock): # Check expectations assert runner_result.exit_code == 0 - mock_DevEnvLocalSetup.assert_called_once() mock_platform.registries.list_registry_configs.assert_called_once() expected_registry = { "name": test_name, @@ -40,11 +38,10 @@ def test_add_reg(mock_DevEnvLocalSetup: MagicMock): mock_platform.registries.add_registry.assert_called_once_with(expected_registry) @patch("dem.cli.command.add_reg_cmd.stdout.print") -@patch("dem.cli.command.add_reg_cmd.DevEnvLocalSetup") -def test_add_reg_already_added(mock_DevEnvLocalSetup: MagicMock, mock_stdout_print: MagicMock): +def test_add_reg_already_added(mock_stdout_print: MagicMock): # Test setup mock_platform = MagicMock() - mock_DevEnvLocalSetup.return_value = mock_platform + main.platform = mock_platform test_name = "test_name" test_url = "test_url" @@ -60,6 +57,5 @@ def test_add_reg_already_added(mock_DevEnvLocalSetup: MagicMock, mock_stdout_pri # Check expectations assert runner_result.exit_code == 0 - mock_DevEnvLocalSetup.assert_called_once() mock_platform.registries.list_registry_configs.assert_called_once() mock_stdout_print.assert_called_once_with("[yellow]The input registry is already added.[/]") \ No newline at end of file diff --git a/tests/cli/test_cp.py b/tests/cli/test_cp.py index c2f6f0f3..4dbb84a5 100644 --- a/tests/cli/test_cp.py +++ b/tests/cli/test_cp.py @@ -94,18 +94,17 @@ def test_cp_given_dev_env(): mock_platform.flush_to_file.assert_called_once() -@patch("dem.cli.command.cp_cmd.DevEnvLocalSetup") @patch("dem.cli.command.cp_cmd.get_dev_env_to_cp") @patch("dem.cli.command.cp_cmd.check_new_dev_env_name_taken") @patch("dem.cli.command.cp_cmd.cp_given_dev_env") def test_cp(mock_cp_given_dev_env, mock_check_new_dev_env_name_taken, - mock_get_dev_env_to_cp, mock_DevEnvLocalSetup): + mock_get_dev_env_to_cp): # Test setup - fake_local_platform = MagicMock() - mock_DevEnvLocalSetup.return_value = fake_local_platform + mock_platform = MagicMock() fake_dev_env_to_cp = MagicMock() mock_get_dev_env_to_cp.return_value = fake_dev_env_to_cp mock_check_new_dev_env_name_taken.return_value = False + main.platform = mock_platform test_dev_env_to_cp_name = "test_dev_env_to_cp_name" test_new_dev_env_name = "test_new_dev_env_name" @@ -118,10 +117,9 @@ def test_cp(mock_cp_given_dev_env, mock_check_new_dev_env_name_taken, # Check expectations assert runner_result.exit_code == 0 - mock_DevEnvLocalSetup.assert_called_once() - mock_get_dev_env_to_cp.assert_called_once_with(fake_local_platform, + mock_get_dev_env_to_cp.assert_called_once_with(mock_platform, test_dev_env_to_cp_name) - mock_check_new_dev_env_name_taken.assert_called_once_with(fake_local_platform, + mock_check_new_dev_env_name_taken.assert_called_once_with(mock_platform, test_new_dev_env_name) - mock_cp_given_dev_env.assert_called_once_with(fake_local_platform, + mock_cp_given_dev_env.assert_called_once_with(mock_platform, fake_dev_env_to_cp, test_new_dev_env_name) \ No newline at end of file diff --git a/tests/cli/test_create_cmd.py b/tests/cli/test_create_cmd.py index 561db673..ad6d9c4a 100644 --- a/tests/cli/test_create_cmd.py +++ b/tests/cli/test_create_cmd.py @@ -169,11 +169,10 @@ def test_execute_abort(mock_confirm, mock_get_dev_env_descriptor_from_user): @patch("dem.cli.command.create_cmd.stdout.print") @patch("dem.cli.command.create_cmd.create_dev_env") -@patch("dem.cli.command.create_cmd.DevEnvLocalSetup") -def test_execute(mock_DevEnvLocalSetup, mock_create_dev_env, mock_stdout_print): +def test_execute(mock_create_dev_env, mock_stdout_print): # Test setup - mock_dev_env_local_setup = MagicMock() - mock_DevEnvLocalSetup.return_value = mock_dev_env_local_setup + mock_platform = MagicMock() + main.platform = mock_platform mock_dev_env = MagicMock() expected_dev_env_name = "test_dev_env" @@ -189,21 +188,19 @@ def test_execute(mock_DevEnvLocalSetup, mock_create_dev_env, mock_stdout_print): # Check expectations assert 0 == runner_result.exit_code - mock_DevEnvLocalSetup.assert_called_once() - mock_create_dev_env.assert_called_once_with(mock_dev_env_local_setup, expected_dev_env_name) - mock_dev_env.check_image_availability.assert_called_once_with(mock_dev_env_local_setup.tool_images, + mock_create_dev_env.assert_called_once_with(mock_platform, expected_dev_env_name) + mock_dev_env.check_image_availability.assert_called_once_with(mock_platform.tool_images, update_tool_images=True) mock_stdout_print.assert_called_once_with("The [yellow]" + expected_dev_env_name + "[/] Development Environment is ready!") - mock_dev_env_local_setup.update_json() + mock_platform.update_json() @patch("dem.cli.command.create_cmd.stderr.print") @patch("dem.cli.command.create_cmd.create_dev_env") -@patch("dem.cli.command.create_cmd.DevEnvLocalSetup") -def test_execute_failure(mock_DevEnvLocalSetup, mock_create_dev_env, mock_stderr_print): +def test_execute_failure(mock_create_dev_env, mock_stderr_print): # Test setup - mock_dev_env_local_setup = MagicMock() - mock_DevEnvLocalSetup.return_value = mock_dev_env_local_setup + mock_platform = MagicMock() + main.platform = mock_platform mock_dev_env = MagicMock() mock_create_dev_env.return_value = mock_dev_env @@ -219,9 +216,8 @@ def test_execute_failure(mock_DevEnvLocalSetup, mock_create_dev_env, mock_stderr # Check expectations assert 0 == runner_result.exit_code - mock_DevEnvLocalSetup.assert_called_once() - mock_create_dev_env.assert_called_once_with(mock_dev_env_local_setup, expected_dev_env_name) - mock_dev_env.check_image_availability.assert_called_once_with(mock_dev_env_local_setup.tool_images, + mock_create_dev_env.assert_called_once_with(mock_platform, expected_dev_env_name) + mock_dev_env.check_image_availability.assert_called_once_with(mock_platform.tool_images, update_tool_images=True) mock_stderr_print.assert_called_once_with("The installation failed.") diff --git a/tests/cli/test_del_cat_cmd.py b/tests/cli/test_del_cat_cmd.py index 853ba3e8..ea7507ce 100644 --- a/tests/cli/test_del_cat_cmd.py +++ b/tests/cli/test_del_cat_cmd.py @@ -13,11 +13,10 @@ ## Test cases @patch("dem.cli.command.del_cat_cmd.stdout.print") -@patch("dem.cli.command.del_cat_cmd.DevEnvLocalSetup") -def test_del_cat(mock_DevEnvLocalSetup: MagicMock, mock_stdout_print: MagicMock): +def test_del_cat(mock_stdout_print: MagicMock): # Test setup mock_platform = MagicMock() - mock_DevEnvLocalSetup.return_value = mock_platform + main.platform = mock_platform test_catalog_to_delete = { "name": "test_catalog_name", "url": "test_url1" @@ -38,17 +37,15 @@ def test_del_cat(mock_DevEnvLocalSetup: MagicMock, mock_stdout_print: MagicMock) # Check expectations assert runner_result.exit_code == 0 - mock_DevEnvLocalSetup.assert_called_once() mock_platform.dev_env_catalogs.list_catalog_configs.assert_called_once() mock_platform.dev_env_catalogs.delete_catalog.assert_called_once_with(test_catalog_to_delete) mock_stdout_print.assert_called_once_with("[green]The input catalog has been successfully deleted.") @patch("dem.cli.command.del_cat_cmd.stderr.print") -@patch("dem.cli.command.del_cat_cmd.DevEnvLocalSetup") -def test_del_cat_not_exist(mock_DevEnvLocalSetup: MagicMock, mock_stderr_print: MagicMock): +def test_del_cat_not_exist(mock_stderr_print: MagicMock): # Test setup mock_platform = MagicMock() - mock_DevEnvLocalSetup.return_value = mock_platform + main.platform = mock_platform mock_platform.dev_env_catalogs.list_catalog_configs.return_value = [] # Run unit under test @@ -57,6 +54,5 @@ def test_del_cat_not_exist(mock_DevEnvLocalSetup: MagicMock, mock_stderr_print: # Check expectations assert runner_result.exit_code == 0 - mock_DevEnvLocalSetup.assert_called_once() mock_platform.dev_env_catalogs.list_catalog_configs.assert_called_once() mock_stderr_print.assert_called_once_with("[red]Error: The input catalog name doesn't exist![/]") \ No newline at end of file diff --git a/tests/cli/test_del_reg_cmd.py b/tests/cli/test_del_reg_cmd.py index a59c14aa..ac08f7bb 100644 --- a/tests/cli/test_del_reg_cmd.py +++ b/tests/cli/test_del_reg_cmd.py @@ -13,11 +13,10 @@ ## Test cases @patch("dem.cli.command.del_reg_cmd.stdout.print") -@patch("dem.cli.command.del_reg_cmd.DevEnvLocalSetup") -def test_del_reg(mock_DevEnvLocalSetup: MagicMock, mock_stdout_print: MagicMock): +def test_del_reg(mock_stdout_print: MagicMock): # Test setup mock_platform = MagicMock() - mock_DevEnvLocalSetup.return_value = mock_platform + main.platform = mock_platform test_registry_to_delete = { "name": "test_registry_name", "url": "test_url1" @@ -38,17 +37,15 @@ def test_del_reg(mock_DevEnvLocalSetup: MagicMock, mock_stdout_print: MagicMock) # Check expectations assert runner_result.exit_code == 0 - mock_DevEnvLocalSetup.assert_called_once() mock_platform.registries.list_registry_configs.assert_called_once() mock_platform.registries.delete_registry.assert_called_once_with(test_registry_to_delete) mock_stdout_print.assert_called_once_with("[green]The input registry has been successfully deleted.") @patch("dem.cli.command.del_reg_cmd.stderr.print") -@patch("dem.cli.command.del_reg_cmd.DevEnvLocalSetup") -def test_del_reg_not_exist(mock_DevEnvLocalSetup: MagicMock, mock_stderr_print: MagicMock): +def test_del_reg_not_exist(mock_stderr_print: MagicMock): # Test setup mock_platform = MagicMock() - mock_DevEnvLocalSetup.return_value = mock_platform + main.platform = mock_platform mock_platform.registries.list_registry_configs.return_value = [] # Run unit under test @@ -57,6 +54,5 @@ def test_del_reg_not_exist(mock_DevEnvLocalSetup: MagicMock, mock_stderr_print: # Check expectations assert runner_result.exit_code == 0 - mock_DevEnvLocalSetup.assert_called_once() mock_platform.registries.list_registry_configs.assert_called_once() mock_stderr_print.assert_called_once_with("[red]Error: The input registry name doesn't exist![/]") \ No newline at end of file diff --git a/tests/cli/test_delete_cmd.py b/tests/cli/test_delete_cmd.py index 467c3dea..c425210e 100644 --- a/tests/cli/test_delete_cmd.py +++ b/tests/cli/test_delete_cmd.py @@ -141,16 +141,15 @@ def test_remove_unused_tool_images(mock_try_to_delete_tool_image): @patch("dem.cli.command.delete_cmd.remove_unused_tool_images") -@patch("dem.cli.command.delete_cmd.DevEnvLocalSetup") -def test_delete_dev_env_valid_name(mock_DevEnvLocalSetup, mock_remove_unused_tool_images): +def test_delete_dev_env_valid_name(mock_remove_unused_tool_images): # Test setup fake_dev_env1 = MagicMock() fake_dev_env_to_delete = MagicMock() fake_dev_env_to_delete.name = "dev_env" mock_platform = MagicMock() mock_platform.local_dev_envs = [fake_dev_env1, fake_dev_env_to_delete] - mock_DevEnvLocalSetup.return_value = mock_platform mock_platform.get_dev_env_by_name.return_value = fake_dev_env_to_delete + main.platform = mock_platform # Run unit under test runner_result = runner.invoke(main.typer_cli, ["delete", fake_dev_env_to_delete.name], color=True) @@ -158,23 +157,20 @@ def test_delete_dev_env_valid_name(mock_DevEnvLocalSetup, mock_remove_unused_too # Check expectations assert 0 == runner_result.exit_code - mock_DevEnvLocalSetup.assert_called_once() mock_platform.get_dev_env_by_name.assert_called_once_with(fake_dev_env_to_delete.name) mock_platform.flush_to_file.assert_called_once() - mock_remove_unused_tool_images.assert_called_once_with(fake_dev_env_to_delete, - mock_platform) + mock_remove_unused_tool_images.assert_called_once_with(fake_dev_env_to_delete, mock_platform) assert fake_dev_env1 in mock_platform.local_dev_envs assert fake_dev_env_to_delete not in mock_platform.local_dev_envs @patch("dem.cli.command.delete_cmd.stderr.print") -@patch("dem.cli.command.delete_cmd.DevEnvLocalSetup") -def test_delete_dev_env_invalid_name(mock_DevEnvLocalSetup, mock_stderr_print): +def test_delete_dev_env_invalid_name(mock_stderr_print): # Test setup - fake_local_platform = MagicMock() - mock_DevEnvLocalSetup.return_value = fake_local_platform - fake_local_platform.get_dev_env_by_name.return_value = None + mock_platform = MagicMock() + mock_platform.get_dev_env_by_name.return_value = None test_invalid_name = "test_invalid_name" + main.platform = mock_platform # Run unit under test runner_result = runner.invoke(main.typer_cli, ["delete", test_invalid_name], color=True) @@ -182,6 +178,5 @@ def test_delete_dev_env_invalid_name(mock_DevEnvLocalSetup, mock_stderr_print): # Check expectations assert 0 == runner_result.exit_code - mock_DevEnvLocalSetup.assert_called_once() - fake_local_platform.get_dev_env_by_name.assert_called_once_with(test_invalid_name) + mock_platform.get_dev_env_by_name.assert_called_once_with(test_invalid_name) mock_stderr_print.assert_called_once_with("[red]Error: The [bold]" + test_invalid_name + "[/bold] Development Environment doesn't exist.") \ No newline at end of file diff --git a/tests/cli/test_export_cmd.py b/tests/cli/test_export_cmd.py index 30cbd48c..c0baa11d 100644 --- a/tests/cli/test_export_cmd.py +++ b/tests/cli/test_export_cmd.py @@ -60,7 +60,7 @@ def test_create_exported_dev_env_json(mock_os_path_isdir,mock_open): mock_os_path_isdir.assert_called() mock_os_path_isdir.return_value = False - given_path = None + given_path = "" export_cmd.create_exported_dev_env_json(dev_env_name,dev_env_json,given_path) fake_opened_file.write.assert_called() fake_opened_file.close.assert_called() @@ -71,13 +71,12 @@ def test_create_exported_dev_env_json(mock_os_path_isdir,mock_open): @patch("dem.cli.command.export_cmd.open") @patch("dem.cli.command.export_cmd.check_is_path_contains_spec_char") @patch("dem.cli.command.export_cmd.check_is_directory") -@patch("dem.cli.command.export_cmd.DevEnvLocalSetup") -def test_wo_path(mock_DevEnvLocalSetup: MagicMock, mock_check_is_directory: MagicMock, +def test_wo_path(mock_check_is_directory: MagicMock, mock_check_is_path_contains_spec_char: MagicMock, mock_open: MagicMock, mock_json_dump: MagicMock): # Test setup mock_platform = MagicMock() - mock_DevEnvLocalSetup.return_value = mock_platform + main.platform = mock_platform mock_dev_env_to_export = MagicMock() mock_platform.get_dev_env_by_name.return_value = mock_dev_env_to_export @@ -93,39 +92,46 @@ def test_wo_path(mock_DevEnvLocalSetup: MagicMock, mock_check_is_directory: Magi # Run unit under test runner_result = runner.invoke(main.typer_cli, ["export", test_dev_env_name]) - # Check expectations + # # Check expectations assert 0 == runner_result.exit_code - mock_DevEnvLocalSetup.assert_called_once() mock_platform.get_dev_env_by_name.assert_called_once_with(test_dev_env_name) - mock_check_is_directory.assert_called_once_with(None) - mock_check_is_path_contains_spec_char.assert_called_once_with(None) + mock_check_is_directory.assert_called_once_with("") + mock_check_is_path_contains_spec_char.assert_called_once_with("") mock_open.assert_called_once_with(test_dev_env_name, "w") mock_json_dump.assert_called_once_with(mock_dev_env_to_export.__dict__, mock_exported_file, indent=4) mock_exported_file.close.assert_called_once() def test_with_invalid_devenv(): + # Test setup + mock_platform = MagicMock() + main.platform = mock_platform + + mock_platform.get_dev_env_by_name.return_value = None + + test_invalid_dev_env_name = "" + # Run unit under test - runner_result = runner.invoke(main.typer_cli, ["export", ""]) + runner_result = runner.invoke(main.typer_cli, ["export", test_invalid_dev_env_name]) # Check expectations assert 0 == runner_result.exit_code + mock_platform.get_dev_env_by_name.assert_called_once_with(test_invalid_dev_env_name) + console = Console(file=io.StringIO()) console.print("[red]Error: The input Development Environment does not exist.[/]") assert console.file.getvalue() == runner_result.stderr @patch("dem.cli.command.export_cmd.create_exported_dev_env_json") -@patch("dem.cli.command.export_cmd.DevEnvLocalSetup") -def test_execute_valid_parameters(mock_DevEnvLocalSetup: MagicMock, - mock_create_exported_dev_env_json: MagicMock): +def test_execute_valid_parameters(mock_create_exported_dev_env_json: MagicMock): # Test setup test_dev_env_name = "test_dev_env_name" test_path_to_export = "test_path_to_export" mock_platform = MagicMock() - mock_DevEnvLocalSetup.return_value = mock_platform + main.platform = mock_platform mock_dev_env_to_export = MagicMock() mock_platform.get_dev_env_by_name.return_value = mock_dev_env_to_export @@ -137,22 +143,19 @@ def test_execute_valid_parameters(mock_DevEnvLocalSetup: MagicMock, # Check expectations assert 0 == runner_result.exit_code - mock_DevEnvLocalSetup.assert_called_once() mock_platform.get_dev_env_by_name.assert_called_once_with(test_dev_env_name) mock_create_exported_dev_env_json.assert_called_once_with(test_dev_env_name, mock_dev_env_to_export.__dict__, test_path_to_export) @patch("dem.cli.command.export_cmd.create_exported_dev_env_json", side_effect=FileNotFoundError("FileNotFoundError")) -@patch("dem.cli.command.export_cmd.DevEnvLocalSetup") -def test_execute_FileNotFoundError(mock_DevEnvLocalSetup: MagicMock, - mock_create_exported_dev_env_json: MagicMock): +def test_execute_FileNotFoundError(mock_create_exported_dev_env_json: MagicMock): # Test setup test_dev_env_name = "test_dev_env_name" test_path_to_export = "" mock_platform = MagicMock() - mock_DevEnvLocalSetup.return_value = mock_platform + main.platform = mock_platform mock_dev_env_to_export = MagicMock() mock_platform.get_dev_env_by_name.return_value = mock_dev_env_to_export @@ -166,9 +169,7 @@ def test_execute_FileNotFoundError(mock_DevEnvLocalSetup: MagicMock, console.print("[red]Error: Invalid input path.[/]") assert console.file.getvalue() == runner_result.stderr - mock_DevEnvLocalSetup.assert_called_once() mock_platform.get_dev_env_by_name.assert_called_once_with(test_dev_env_name) mock_create_exported_dev_env_json.assert_called_once_with(test_dev_env_name, mock_dev_env_to_export.__dict__, - test_path_to_export) - \ No newline at end of file + test_path_to_export) \ No newline at end of file diff --git a/tests/cli/test_info_cmd.py b/tests/cli/test_info_cmd.py index e1ebfeb0..975cab19 100644 --- a/tests/cli/test_info_cmd.py +++ b/tests/cli/test_info_cmd.py @@ -33,13 +33,13 @@ def get_expected_table(expected_tools: list[list[str]]) ->str: ## Test cases -@patch("dem.cli.command.info_cmd.DevEnvLocalSetup") -def test_info_local_dev_env_demo(mock_DevEnvLocalSetup): +def test_info_local_dev_env_demo(): # Test setup - fake_platform = MagicMock() - mock_DevEnvLocalSetup.return_value = fake_platform - fake_dev_env = MagicMock() - fake_dev_env.tools = [ + mock_platform = MagicMock() + main.platform = mock_platform + + mock_dev_env = MagicMock() + mock_dev_env.tools = [ { "type": "build system", "image_name": "axemsolutions/make_gnu_arm", @@ -66,11 +66,11 @@ def test_info_local_dev_env_demo(mock_DevEnvLocalSetup): "image_version": "latest" }, ] - fake_platform.get_dev_env_by_name.return_value = fake_dev_env + mock_platform.get_dev_env_by_name.return_value = mock_dev_env def stub_check_image_availability(*args, **kwargs): - for tool in fake_dev_env.tools: + for tool in mock_dev_env.tools: tool["image_status"] = ToolImages.LOCAL_AND_REGISTRY - fake_dev_env.check_image_availability.side_effect = stub_check_image_availability + mock_dev_env.check_image_availability.side_effect = stub_check_image_availability # Run unit under test test_dev_env_name = "demo" @@ -79,9 +79,8 @@ def stub_check_image_availability(*args, **kwargs): # Check expectations assert runner_result.exit_code == 0 - mock_DevEnvLocalSetup.assert_called_once() - fake_platform.get_dev_env_by_name.assert_called_once_with(test_dev_env_name) - fake_dev_env.check_image_availability.assert_called_once_with(fake_platform.tool_images) + mock_platform.get_dev_env_by_name.assert_called_once_with(test_dev_env_name) + mock_dev_env.check_image_availability.assert_called_once_with(mock_platform.tool_images) expected_tools = [ ["build system", "axemsolutions/make_gnu_arm:latest", "Image is available locally and in the registry."], @@ -92,11 +91,11 @@ def stub_check_image_availability(*args, **kwargs): ] assert get_expected_table(expected_tools) == runner_result.stdout -@patch("dem.cli.command.info_cmd.DevEnvLocalSetup") -def test_info_local_dev_env_nagy_cica_project(mock_DevEnvLocalSetup): +def test_info_local_dev_env_nagy_cica_project(): # Test setup - fake_platform = MagicMock() - mock_DevEnvLocalSetup.return_value = fake_platform + mock_platform = MagicMock() + main.platform = mock_platform + fake_dev_env = MagicMock() fake_dev_env.tools = [ { @@ -125,7 +124,7 @@ def test_info_local_dev_env_nagy_cica_project(mock_DevEnvLocalSetup): "image_version": "latest" }, ] - fake_platform.get_dev_env_by_name.return_value = fake_dev_env + mock_platform.get_dev_env_by_name.return_value = fake_dev_env def stub_check_image_availability(*args, **kwargs): fake_dev_env.tools[0]["image_status"] = ToolImages.NOT_AVAILABLE fake_dev_env.tools[1]["image_status"] = ToolImages.NOT_AVAILABLE @@ -141,9 +140,8 @@ def stub_check_image_availability(*args, **kwargs): # Check expectations assert runner_result.exit_code == 0 - mock_DevEnvLocalSetup.assert_called_once() - fake_platform.get_dev_env_by_name.assert_called_once_with(test_dev_env_name) - fake_dev_env.check_image_availability.assert_called_once_with(fake_platform.tool_images) + mock_platform.get_dev_env_by_name.assert_called_once_with(test_dev_env_name) + fake_dev_env.check_image_availability.assert_called_once_with(mock_platform.tool_images) expected_tools = [ ["build system", "axemsolutions/bazel:latest", "[red]Error: Required image is not available![/]"], @@ -154,11 +152,11 @@ def stub_check_image_availability(*args, **kwargs): ] assert get_expected_table(expected_tools) == runner_result.stdout -@patch("dem.cli.command.info_cmd.DevEnvLocalSetup") -def test_info_dev_env_invalid(mock_DevEnvLocalSetup): +def test_info_dev_env_invalid(): # Test setup mock_platform = MagicMock() - mock_DevEnvLocalSetup.return_value = mock_platform + main.platform = mock_platform + mock_platform.get_dev_env_by_name.return_value = None mock_platform.dev_env_catalogs.catalogs = [] @@ -169,7 +167,6 @@ def test_info_dev_env_invalid(mock_DevEnvLocalSetup): # Check expectations assert runner_result.exit_code == 0 - mock_DevEnvLocalSetup.assert_called_once() mock_platform.get_dev_env_by_name.assert_called_once_with(test_dev_env_name) console = Console(file=io.StringIO()) @@ -177,11 +174,11 @@ def test_info_dev_env_invalid(mock_DevEnvLocalSetup): expected_output = console.file.getvalue() assert expected_output == runner_result.stderr -@patch("dem.cli.command.info_cmd.DevEnvLocalSetup") -def test_info_org_dev_env(mock_DevEnvLocalSetup): +def test_info_org_dev_env(): # Test setup mock_platform = MagicMock() - mock_DevEnvLocalSetup.return_value = mock_platform + main.platform = mock_platform + mock_platform.get_dev_env_by_name.return_value = None mock_catalog = MagicMock() @@ -227,7 +224,6 @@ def stub_check_image_availability(*args, **kwargs): # Check expectations assert runner_result.exit_code == 0 - mock_DevEnvLocalSetup.assert_called_once() mock_platform.get_dev_env_by_name.assert_called_once_with(test_dev_env_name) mock_catalog.get_dev_env_by_name.assert_called_once_with(test_dev_env_name) diff --git a/tests/cli/test_list_cat_cmd.py b/tests/cli/test_list_cat_cmd.py index 7ddfcbdf..43ef4492 100644 --- a/tests/cli/test_list_cat_cmd.py +++ b/tests/cli/test_list_cat_cmd.py @@ -16,12 +16,10 @@ ## Test cases @patch("dem.cli.command.list_cat_cmd.Table") @patch("dem.cli.command.list_cat_cmd.stdout.print") -@patch("dem.cli.command.list_cat_cmd.DevEnvLocalSetup") -def test_list_cat(mock_DevEnvLocalSetup: MagicMock, mock_stdout_print: MagicMock, - mock_Table: MagicMock): +def test_list_cat(mock_stdout_print: MagicMock, mock_Table: MagicMock): # Test setup mock_platform = MagicMock() - mock_DevEnvLocalSetup.return_value = mock_platform + main.platform = mock_platform test_catalog_configs = [ { "name": "test_name1", @@ -42,8 +40,6 @@ def test_list_cat(mock_DevEnvLocalSetup: MagicMock, mock_stdout_print: MagicMock # Check expectations assert runner_result.exit_code == 0 - mock_DevEnvLocalSetup.assert_called_once() - mock_Table.assert_called_once() calls = [call("name"), call("url")] mock_table.add_column.assert_has_calls(calls) @@ -59,12 +55,10 @@ def test_list_cat(mock_DevEnvLocalSetup: MagicMock, mock_stdout_print: MagicMock @patch("dem.cli.command.list_cat_cmd.Table") @patch("dem.cli.command.list_cat_cmd.stdout.print") -@patch("dem.cli.command.list_cat_cmd.DevEnvLocalSetup") -def test_list_cat_non_available(mock_DevEnvLocalSetup: MagicMock, mock_stdout_print: MagicMock, - mock_Table): +def test_list_cat_non_available(mock_stdout_print: MagicMock, mock_Table): # Test setup mock_platform = MagicMock() - mock_DevEnvLocalSetup.return_value = mock_platform + main.platform = mock_platform mock_platform.dev_env_catalogs.list_catalog_configs.return_value = [] mock_table = MagicMock() mock_Table.return_value = mock_table @@ -75,8 +69,6 @@ def test_list_cat_non_available(mock_DevEnvLocalSetup: MagicMock, mock_stdout_pr # Check expectations assert runner_result.exit_code == 0 - mock_DevEnvLocalSetup.assert_called_once() - mock_Table.assert_called_once() calls = [call("name"), call("url")] mock_table.add_column.assert_has_calls(calls) diff --git a/tests/cli/test_list_cmd.py b/tests/cli/test_list_cmd.py index ba8e08d1..3fc43955 100644 --- a/tests/cli/test_list_cmd.py +++ b/tests/cli/test_list_cmd.py @@ -27,8 +27,7 @@ ## Test listing the local dev envs. -@patch("dem.cli.command.list_cmd.DevEnvLocalSetup") -def test_with_valid_dev_env_json(mock_DevEnvLocalSetup: MagicMock): +def test_with_valid_dev_env_json(): # Test setup mock_platform = MagicMock() expected_dev_env_list = [ @@ -46,14 +45,12 @@ def test_with_valid_dev_env_json(mock_DevEnvLocalSetup: MagicMock): fake_dev_env.check_image_availability.return_value = fake_image_statuses[idx] fake_dev_envs.append(fake_dev_env) mock_platform.local_dev_envs = fake_dev_envs - mock_DevEnvLocalSetup.return_value = mock_platform + main.platform = mock_platform # Run unit under test runner_result = runner.invoke(main.typer_cli, ["list", "--local", "--env"]) # Check expectations - mock_DevEnvLocalSetup.assert_called_once() - assert 0 == runner_result.exit_code expected_table = Table() @@ -66,12 +63,11 @@ def test_with_valid_dev_env_json(mock_DevEnvLocalSetup: MagicMock): expected_output = console.file.getvalue() assert expected_output == runner_result.stdout -@patch("dem.cli.command.list_cmd.DevEnvLocalSetup") -def test_with_empty_dev_env_json(mock_DevEnvLocalSetup): +def test_with_empty_dev_env_json(): # Test setup mock_platform = MagicMock() mock_platform.local_dev_envs = [] - mock_DevEnvLocalSetup.return_value = mock_platform + main.platform = mock_platform # Run unit under test runner_result = runner.invoke(main.typer_cli, ["list", "--local", "--env"]) @@ -87,12 +83,11 @@ def test_with_empty_dev_env_json(mock_DevEnvLocalSetup): ## Test listing the org dev envs. @patch("dem.cli.command.list_cmd.stdout.print") -@patch("dem.cli.command.list_cmd.DevEnvLocalSetup") -def test_without_avialable_catalogs(mock_DevEnvLocalSetup: MagicMock, mock_stdout_print: MagicMock): +def test_without_avialable_catalogs(mock_stdout_print: MagicMock): # Test setup mock_platform = MagicMock() - mock_DevEnvLocalSetup.return_value = mock_platform mock_platform.dev_env_catalogs.catalogs = [] + main.platform = mock_platform # Run unit under test runner_result = runner.invoke(main.typer_cli, ["list", "--all", "--env"]) @@ -100,17 +95,15 @@ def test_without_avialable_catalogs(mock_DevEnvLocalSetup: MagicMock, mock_stdou # Check expectations assert 0 == runner_result.exit_code - mock_DevEnvLocalSetup.assert_called_once() mock_stdout_print.assert_called_once_with("[yellow]No Development Environment Catalogs are available!") -@patch("dem.cli.command.list_cmd.DevEnvLocalSetup") -def test_with_empty_catalog(mock_DevEnvLocalSetup: MagicMock): +def test_with_empty_catalog(): # Test setup mock_catalog = MagicMock() mock_catalog.dev_envs = [] mock_platform = MagicMock() - mock_DevEnvLocalSetup.return_value = mock_platform mock_platform.dev_env_catalogs.catalogs = [mock_catalog] + main.platform = mock_platform # Run unit under test runner_result = runner.invoke(main.typer_cli, ["list", "--all", "--env"]) @@ -118,14 +111,11 @@ def test_with_empty_catalog(mock_DevEnvLocalSetup: MagicMock): # Check expectations assert 0 == runner_result.exit_code - mock_DevEnvLocalSetup.assert_called_once() - console = Console(file=io.StringIO()) console.print("[yellow]No Development Environments are available in the catalogs.[/]") assert console.file.getvalue() == runner_result.stdout -@patch("dem.cli.command.list_cmd.DevEnvLocalSetup") -def test_with_valid_dev_env_org_json(mock_DevEnvLocalSetup): +def test_with_valid_dev_env_org_json(): # Test setup mock_platform = MagicMock() expected_dev_env_list = [ @@ -149,14 +139,13 @@ def test_with_valid_dev_env_org_json(mock_DevEnvLocalSetup): mock_catalog = MagicMock() mock_platform.dev_env_catalogs.catalogs = [mock_catalog] mock_catalog.dev_envs = fake_catalog_dev_envs - mock_DevEnvLocalSetup.return_value = mock_platform mock_platform.get_local_dev_env.side_effect = [None, MagicMock(), MagicMock()] + main.platform = mock_platform # Run unit under test runner_result = runner.invoke(main.typer_cli, ["list", "--all", "--env"]) # Check expectations - mock_DevEnvLocalSetup.assert_called_once() calls = [] for fake_dev_env in fake_catalog_dev_envs: calls.append(call(fake_dev_env)) @@ -200,8 +189,7 @@ def test_with_invalid_option(): ## Test listing the local tool images. -@patch("dem.cli.command.list_cmd.DevEnvLocalSetup") -def test_local_tool_images(mock_DevEnvLocalSetup: MagicMock): +def test_local_tool_images(): # Test setup test_local_tool_images = [ "axemsolutions/cpputest:latest", @@ -209,8 +197,8 @@ def test_local_tool_images(mock_DevEnvLocalSetup: MagicMock): "axemsolutions/make_gnu_arm:latest", ] mock_platform = MagicMock() - mock_DevEnvLocalSetup.return_value = mock_platform mock_platform.container_engine.get_local_tool_images.return_value = test_local_tool_images + main.platform = mock_platform # Run unit under test runner_result = runner.invoke(main.typer_cli, ["list", "--local", "--tool"]) @@ -218,7 +206,6 @@ def test_local_tool_images(mock_DevEnvLocalSetup: MagicMock): # Check expectations assert 0 == runner_result.exit_code - mock_DevEnvLocalSetup.assert_called_once() mock_platform.container_engine.get_local_tool_images.assert_called_once() expected_table = Table() @@ -230,13 +217,12 @@ def test_local_tool_images(mock_DevEnvLocalSetup: MagicMock): console.print(expected_table) assert console.file.getvalue() == runner_result.stdout -@patch("dem.cli.command.list_cmd.DevEnvLocalSetup") -def test_no_local_tool_images(mock_DevEnvLocalSetup: MagicMock): +def test_no_local_tool_images(): # Test setup test_local_tool_images = [] mock_platform = MagicMock() - mock_DevEnvLocalSetup.return_value = mock_platform mock_platform.container_engine.get_local_tool_images.return_value = test_local_tool_images + main.platform = mock_platform # Run unit under test runner_result = runner.invoke(main.typer_cli, ["list", "--local", "--tool"]) @@ -244,7 +230,6 @@ def test_no_local_tool_images(mock_DevEnvLocalSetup: MagicMock): # Check expectations assert 0 == runner_result.exit_code - mock_DevEnvLocalSetup.assert_called_once() mock_platform.container_engine.get_local_tool_images.assert_called_once() expected_table = Table() @@ -255,8 +240,7 @@ def test_no_local_tool_images(mock_DevEnvLocalSetup: MagicMock): ## Test listing the local tool images. -@patch("dem.cli.command.list_cmd.DevEnvLocalSetup") -def test_registry_tool_images(mock_DevEnvLocalSetup: MagicMock): +def test_registry_tool_images(): # Test setup test_registry_tool_images = [ "axemsolutions/cpputest:latest", @@ -264,8 +248,8 @@ def test_registry_tool_images(mock_DevEnvLocalSetup: MagicMock): "axemsolutions/make_gnu_arm:latest", ] mock_platform = MagicMock() - mock_DevEnvLocalSetup.return_value = mock_platform mock_platform.registries.list_repos.return_value = test_registry_tool_images + main.platform = mock_platform # Run unit under test runner_result = runner.invoke(main.typer_cli, ["list", "--all", "--tool"]) @@ -285,13 +269,12 @@ def test_registry_tool_images(mock_DevEnvLocalSetup: MagicMock): assert console.file.getvalue() == runner_result.stdout @patch("dem.cli.command.list_cmd.stdout.print") -@patch("dem.cli.command.list_cmd.DevEnvLocalSetup") -def test_empty_repository(mock_DevEnvLocalSetup: MagicMock, mock_stdout_print: MagicMock): +def test_empty_repository(mock_stdout_print: MagicMock): # Test setup test_registry_tool_images = [] mock_platform = MagicMock() - mock_DevEnvLocalSetup.return_value = mock_platform mock_platform.registries.list_repos.return_value = test_registry_tool_images + main.platform = mock_platform # Run unit under test runner_result = runner.invoke(main.typer_cli, ["list", "--all", "--tool"]) @@ -303,12 +286,11 @@ def test_empty_repository(mock_DevEnvLocalSetup: MagicMock, mock_stdout_print: M mock_stdout_print.assert_called_once_with("[yellow]No images are available in the registries!") @patch("dem.cli.command.list_cmd.stdout.print") -@patch("dem.cli.command.list_cmd.DevEnvLocalSetup") -def test_no_registries_available(mock_DevEnvLocalSetup: MagicMock, mock_stdout_print: MagicMock): +def test_no_registries_available(mock_stdout_print: MagicMock): # Test setup mock_platform = MagicMock() mock_platform.registries.registries = [] - mock_DevEnvLocalSetup.return_value = mock_platform + main.platform = mock_platform # Run unit under test runner_result = runner.invoke(main.typer_cli, ["list", "--all", "--tool"]) @@ -316,7 +298,6 @@ def test_no_registries_available(mock_DevEnvLocalSetup: MagicMock, mock_stdout_p # Check expectations assert 0 == runner_result.exit_code - mock_DevEnvLocalSetup.assert_called_once() mock_stdout_print.assert_called_once_with("[yellow]No registries are available!") def test_get_local_dev_env_status_reinstall(): diff --git a/tests/cli/test_list_reg_cmd.py b/tests/cli/test_list_reg_cmd.py index 9a16a4f8..b8440799 100644 --- a/tests/cli/test_list_reg_cmd.py +++ b/tests/cli/test_list_reg_cmd.py @@ -16,12 +16,11 @@ ## Test cases @patch("dem.cli.command.list_reg_cmd.Table") @patch("dem.cli.command.list_reg_cmd.stdout.print") -@patch("dem.cli.command.list_reg_cmd.DevEnvLocalSetup") -def test_list_reg(mock_DevEnvLocalSetup: MagicMock, mock_stdout_print: MagicMock, - mock_Table: MagicMock): +def test_list_reg(mock_stdout_print: MagicMock, mock_Table: MagicMock): # Test setup mock_platform = MagicMock() - mock_DevEnvLocalSetup.return_value = mock_platform + main.platform = mock_platform + test_registries = [ { "name": "test_name1", @@ -42,8 +41,6 @@ def test_list_reg(mock_DevEnvLocalSetup: MagicMock, mock_stdout_print: MagicMock # Check expectations assert runner_result.exit_code == 0 - mock_DevEnvLocalSetup.assert_called_once() - mock_Table.assert_called_once() calls = [call("name"), call("url")] mock_table.add_column.assert_has_calls(calls) @@ -59,12 +56,10 @@ def test_list_reg(mock_DevEnvLocalSetup: MagicMock, mock_stdout_print: MagicMock @patch("dem.cli.command.list_reg_cmd.Table") @patch("dem.cli.command.list_reg_cmd.stdout.print") -@patch("dem.cli.command.list_reg_cmd.DevEnvLocalSetup") -def test_list_reg_non_available(mock_DevEnvLocalSetup: MagicMock, mock_stdout_print: MagicMock, - mock_Table): +def test_list_reg_non_available(mock_stdout_print: MagicMock, mock_Table): # Test setup mock_platform = MagicMock() - mock_DevEnvLocalSetup.return_value = mock_platform + main.platform = mock_platform mock_platform.registries.list_registry_configs.return_value = [] mock_table = MagicMock() mock_Table.return_value = mock_table @@ -75,8 +70,6 @@ def test_list_reg_non_available(mock_DevEnvLocalSetup: MagicMock, mock_stdout_pr # Check expectations assert runner_result.exit_code == 0 - mock_DevEnvLocalSetup.assert_called_once() - mock_Table.assert_called_once() calls = [call("name"), call("url")] mock_table.add_column.assert_has_calls(calls) diff --git a/tests/cli/test_load_cmd.py b/tests/cli/test_load_cmd.py index a87e21f7..f3430f42 100644 --- a/tests/cli/test_load_cmd.py +++ b/tests/cli/test_load_cmd.py @@ -75,24 +75,24 @@ def test_load_dev_env_to_dev_env_json(mock_open, mock_json, mock_DevEnvLocal: Ma mock_platform.pull_images.assert_called_once_with(mock_new_dev_env.tools) fake_opened_file.close.assert_called() - @patch("dem.cli.command.load_cmd.open",MagicMock()) @patch("dem.cli.command.load_cmd.json.load") -@patch("dem.cli.command.load_cmd.DevEnvLocalSetup") -def test_json_decode_error(mock_DevEnvLocalSetup,mock_json): +def test_json_decode_error(mock_json): # Test setup - fake_local_platform = MagicMock() - mock_DevEnvLocalSetup.return_value = fake_local_platform + mock_platform = MagicMock() + main.platform = mock_platform path="/home/cica.json" mock_json.side_effect = json.decoder.JSONDecodeError("asd","asd",0) - fake_local_platform.get_dev_env_by_name.return_value = MagicMock() - retval_dev_env_cant_load = load_cmd.load_dev_env_to_dev_env_json(fake_local_platform,path) - + mock_platform.get_dev_env_by_name.return_value = MagicMock() + + # Run unit under test + retval_dev_env_cant_load = load_cmd.load_dev_env_to_dev_env_json(mock_platform,path) + + # Check expectations assert retval_dev_env_cant_load is False def test_wo_path(): - # Run unit under test runner_result = runner.invoke(main.typer_cli, ["load"]) @@ -110,8 +110,6 @@ def test_with_invalid_file(): console = Console(file=io.StringIO()) console.print("[red]Error: The input file does not exist.[/]") assert console.file.getvalue() == runner_result.stderr - - @patch("dem.cli.command.load_cmd.load_dev_env_to_dev_env_json") @patch("dem.cli.command.load_cmd.check_is_file_exist") diff --git a/tests/cli/test_main.py b/tests/cli/test_main.py new file mode 100644 index 00000000..b60dbcf9 --- /dev/null +++ b/tests/cli/test_main.py @@ -0,0 +1,155 @@ +"""Unit tests for running the dem in CLI mode without commands.""" +# tests/cli/test_main_options.py + +# Unit under test +import dem.cli.main as main + +# Test framework +import pytest +from typer.testing import CliRunner +from unittest.mock import patch, MagicMock + +import importlib.metadata, typer + +## Global test variables + +# In order to test stdout and stderr separately, the stderr can't be mixed into the stdout. +runner = CliRunner(mix_stderr=False) + +def test_autocomplete_dev_env_name(): + # Test setup + mock_platform = MagicMock() + mock_dev_env = MagicMock() + mock_dev_env.name = "TeSt" + mock_platform.local_dev_envs = [ + mock_dev_env + ] + main.platform = mock_platform + + expected_completions = [mock_dev_env.name] + + # Run unit under test + actual_completions = [] + for result in main.autocomplete_dev_env_name("TeS"): + actual_completions.append(result) + + # Check expectations + assert expected_completions == actual_completions + +def test_autocomplete_cat_name(): + # Test setup + mock_platform = MagicMock() + fake_catalog_config = { + "name": "test" + } + mock_platform.dev_env_catalogs.list_catalog_configs.return_value = [fake_catalog_config] + main.platform = mock_platform + + expected_completions = [fake_catalog_config["name"]] + + # Run unit under test + actual_completions = [] + for result in main.autocomplete_cat_name("tes"): + actual_completions.append(result) + + # Check expectations + assert expected_completions == actual_completions + +def test_autocomplete_reg_name(): + # Test setup + mock_platform = MagicMock() + fake_registry_config = { + "name": "test" + } + mock_platform.registries.list_registry_configs.return_value = [fake_registry_config] + main.platform = mock_platform + + expected_completions = [fake_registry_config["name"]] + + # Run unit under test + actual_completions = [] + for result in main.autocomplete_reg_name("tes"): + actual_completions.append(result) + + # Check expectations + assert expected_completions == actual_completions + +@patch("dem.cli.main.__app_name__", "axem-dem") +@patch("dem.cli.main.stdout.print") +@patch("dem.cli.main.importlib.metadata.version") +def test_version_as_installed(mock_importlib_metadata_version, mock_stdout_print): + # Test setup + test_version = "0.1.2" + mock_importlib_metadata_version.return_value = test_version + + # Run unit under test + result = runner.invoke(main.typer_cli, ["--version"]) + + # Check expectations + assert result.exit_code == 0 + + mock_stdout_print.assert_called_once_with("[cyan]" + main.__app_name__ + " v" + test_version + "[/]") + +@patch("dem.cli.main.stdout.print") +@patch("dem.cli.main.importlib.metadata.version") +def test_version_as_module(mock_importlib_metadata_version, mock_stdout_print): + # Test setup + mock_importlib_metadata_version.side_effect = importlib.metadata.PackageNotFoundError() + + # Run unit under test + result = runner.invoke(main.typer_cli, ["-v"]) + + # Check expectations + assert result.exit_code == 0 + + mock_stdout_print.assert_called_once_with("[yellow]Install DEM to get the version number.[/]") + +@patch("dem.cli.main.__app_name__", "axem-dem") +@patch("dem.cli.main.stdout.print", MagicMock()) +@patch("dem.cli.main.importlib.metadata.version") +def test_version_exit_raised(mock_importlib_metadata_version): + # Test setup + test_version = "0.1.2" + mock_importlib_metadata_version.return_value = test_version + + # Run unit under test + with pytest.raises(typer.Exit): + main._version_callback(True) + +def test_platform_not_initialized(): + # Test setup + test_dev_env_name = "test_dev_env_name" + test_path = "test_path" + test_name = "test_name" + test_url = "test_url" + mock_ctx = MagicMock() + main.platform = None + + units_to_test = { + main.list_: [], + main.info: [test_dev_env_name], + main.pull: [test_dev_env_name], + main.cp: [test_dev_env_name, test_dev_env_name], + main.create: [test_dev_env_name], + main.export: [test_dev_env_name], + main.load: [test_path], + main.rename: [test_dev_env_name, test_dev_env_name], + main.modify: [test_dev_env_name], + main.delete: [test_dev_env_name], + main.run: [test_dev_env_name, mock_ctx], + main.add_reg: [test_name, test_url], + main.list_reg: [], + main.del_reg: [test_name], + main.add_cat: [test_name, test_url], + main.list_cat: [], + main.del_cat: [test_name], + main.add_host: [test_name, test_url] + } + + for function, parameter in units_to_test.items(): + with pytest.raises(main.InternalError) as exported_exception_info: + # Run unit under test + function(*parameter) + + # Check expectations + assert str(exported_exception_info) == "Error: The platform hasn't been initialized properly!" \ No newline at end of file diff --git a/tests/cli/test_main_options.py b/tests/cli/test_main_options.py deleted file mode 100644 index 21d73233..00000000 --- a/tests/cli/test_main_options.py +++ /dev/null @@ -1,59 +0,0 @@ -"""Unit tests for running the dem in CLI mode without commands.""" -# tests/cli/test_main_options.py - -# Unit under test -import dem.cli.main as main - -# Test framework -import pytest -from typer.testing import CliRunner -from unittest.mock import patch, MagicMock - -import importlib.metadata, typer - -## Global test variables - -# In order to test stdout and stderr separately, the stderr can't be mixed into the stdout. -runner = CliRunner(mix_stderr=False) - -@patch("dem.cli.main.__app_name__", "axem-dem") -@patch("dem.cli.main.stdout.print") -@patch("dem.cli.main.importlib.metadata.version") -def test_version_as_installed(mock_importlib_metadata_version, mock_stdout_print): - # Test setup - test_version = "0.1.2" - mock_importlib_metadata_version.return_value = test_version - - # Run unit under test - result = runner.invoke(main.typer_cli, ["--version"]) - - # Check expectations - assert result.exit_code == 0 - - mock_stdout_print.assert_called_once_with("[cyan]" + main.__app_name__ + " v" + test_version + "[/]") - -@patch("dem.cli.main.stdout.print") -@patch("dem.cli.main.importlib.metadata.version") -def test_version_as_module(mock_importlib_metadata_version, mock_stdout_print): - # Test setup - mock_importlib_metadata_version.side_effect = importlib.metadata.PackageNotFoundError() - - # Run unit under test - result = runner.invoke(main.typer_cli, ["-v"]) - - # Check expectations - assert result.exit_code == 0 - - mock_stdout_print.assert_called_once_with("[yellow]Install DEM to get the version number.[/]") - -@patch("dem.cli.main.__app_name__", "axem-dem") -@patch("dem.cli.main.stdout.print", MagicMock()) -@patch("dem.cli.main.importlib.metadata.version") -def test_version_exit_raised(mock_importlib_metadata_version): - # Test setup - test_version = "0.1.2" - mock_importlib_metadata_version.return_value = test_version - - # Run unit under test - with pytest.raises(typer.Exit): - main._version_callback(True) \ No newline at end of file diff --git a/tests/cli/test_modify_cmd.py b/tests/cli/test_modify_cmd.py index 1b55882d..e5225670 100644 --- a/tests/cli/test_modify_cmd.py +++ b/tests/cli/test_modify_cmd.py @@ -117,12 +117,11 @@ def test_handle_user_confirm_cancel(): with pytest.raises(typer.Abort): modify_cmd.handle_user_confirm("cancel", MagicMock(), MagicMock()) -@patch("dem.cli.command.modify_cmd.DevEnvLocalSetup") -def test_execute_invalid_name(mock_DevEnvLocalSetup): +def test_execute_invalid_name(): # Test setup - mock_dev_env_local_setup = MagicMock() - mock_DevEnvLocalSetup.return_value = mock_dev_env_local_setup - mock_dev_env_local_setup.get_dev_env_by_name.return_value = None + 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 @@ -131,8 +130,7 @@ def test_execute_invalid_name(mock_DevEnvLocalSetup): # Check expectations assert 0 == runner_result.exit_code - mock_DevEnvLocalSetup.assert_called_once() - mock_dev_env_local_setup.get_dev_env_by_name.assert_called_once_with(test_dev_env_name) + 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.") @@ -142,15 +140,13 @@ def test_execute_invalid_name(mock_DevEnvLocalSetup): @patch("dem.cli.command.modify_cmd.get_confirm_from_user") @patch("dem.cli.command.modify_cmd.get_modifications_from_user") @patch("dem.cli.command.modify_cmd.get_tool_image_list") -@patch("dem.cli.command.modify_cmd.DevEnvLocalSetup") -def test_execute_valid_name(mock_DevEnvLocalSetup, mock_get_tool_image_list, - mock_get_modifications_from_user, +def test_execute_valid_name(mock_get_tool_image_list, mock_get_modifications_from_user, mock_get_confirm_from_user, mock_handle_user_confirm): # Test setup - mock_dev_env_local_setup = MagicMock() - mock_DevEnvLocalSetup.return_value = mock_dev_env_local_setup + mock_platform = MagicMock() + main.platform = mock_platform mock_dev_env_local = MagicMock() - mock_dev_env_local_setup.get_dev_env_by_name.return_value = mock_dev_env_local + mock_platform.get_dev_env_by_name.return_value = mock_dev_env_local mock_tool_image_list = MagicMock() mock_get_tool_image_list.return_value = mock_tool_image_list @@ -165,11 +161,10 @@ def test_execute_valid_name(mock_DevEnvLocalSetup, mock_get_tool_image_list, # Check expectations assert 0 == runner_result.exit_code - mock_DevEnvLocalSetup.assert_called_once() - mock_dev_env_local_setup.get_dev_env_by_name.assert_called_once_with(test_dev_env_name) - mock_get_tool_image_list.assert_called_once_with(mock_dev_env_local_setup.tool_images) + mock_platform.get_dev_env_by_name.assert_called_once_with(test_dev_env_name) + mock_get_tool_image_list.assert_called_once_with(mock_platform.tool_images) mock_get_modifications_from_user.assert_called_once_with(mock_dev_env_local, mock_tool_image_list) mock_get_confirm_from_user.assert_called_once() mock_handle_user_confirm.assert_called_once_with(mock_confirmation, mock_dev_env_local, - mock_dev_env_local_setup) \ No newline at end of file + mock_platform) \ No newline at end of file diff --git a/tests/cli/test_pull_cmd.py b/tests/cli/test_pull_cmd.py index 6d28ced7..c59b93a8 100644 --- a/tests/cli/test_pull_cmd.py +++ b/tests/cli/test_pull_cmd.py @@ -17,23 +17,18 @@ # In order to test stdout and stderr separately, the stderr can't be mixed into the stdout. runner = CliRunner(mix_stderr=False) -## Test helpers -## Test cases - -@patch("dem.cli.command.pull_cmd.DevEnvLocalSetup") -def test_dev_env_not_available_in_org(mock_DevEnvLocalSetup: MagicMock): +def test_dev_env_not_available_in_org(): # Test setup mock_platform = MagicMock() - mock_DevEnvLocalSetup.return_value = mock_platform mock_catalog = MagicMock() mock_platform.dev_env_catalogs.catalogs = [mock_catalog] mock_catalog.get_dev_env_by_name.return_value = None + main.platform = mock_platform # Run unit under test runner_result = runner.invoke(main.typer_cli, ["pull", "not existing env"], color=True) # Check expectations - mock_DevEnvLocalSetup.assert_called_once() mock_catalog.get_dev_env_by_name.assert_called_once_with("not existing env") assert 0 == runner_result.exit_code @@ -42,13 +37,12 @@ def test_dev_env_not_available_in_org(mock_DevEnvLocalSetup: MagicMock): console.print("[red]Error: The input Development Environment is not available for the organization.[/]") assert console.file.getvalue() == runner_result.stderr -@patch("dem.cli.command.pull_cmd.DevEnvLocalSetup") -def test_dev_env_already_installed(mock_DevEnvLocalSetup: MagicMock): +def test_dev_env_already_installed(): # Test setup mock_platform = MagicMock() - mock_DevEnvLocalSetup.return_value = mock_platform mock_catalog = MagicMock() mock_platform.dev_env_catalogs.catalogs = [mock_catalog] + main.platform = mock_platform mock_catalog_dev_env = MagicMock() mock_tools = MagicMock() @@ -78,7 +72,6 @@ def stub_check_image_availability(*args, **kwargs): # Check expectations assert 0 == runner_result.exit_code - mock_DevEnvLocalSetup.assert_called_once() mock_catalog.get_dev_env_by_name.assert_called_once_with(test_env_name) mock_platform.get_local_dev_env.assert_called_once_with(mock_catalog_dev_env) @@ -91,13 +84,12 @@ def stub_check_image_availability(*args, **kwargs): console.print("The [yellow]test_env[/] Development Environment is ready!") assert console.file.getvalue() == runner_result.stdout -@patch("dem.cli.command.pull_cmd.DevEnvLocalSetup") -def test_dev_env_installed_but_different(mock_DevEnvLocalSetup: MagicMock): +def test_dev_env_installed_but_different(): # Test setup mock_platform = MagicMock() - mock_DevEnvLocalSetup.return_value = mock_platform mock_catalog = MagicMock() mock_platform.dev_env_catalogs.catalogs = [mock_catalog] + main.platform = mock_platform mock_catalog_dev_env = MagicMock() mock_tools = MagicMock() @@ -125,7 +117,6 @@ def stub_check_image_availability(*args, **kwargs): assert 0 == runner_result.exit_code assert mock_local_dev_env.tools is mock_catalog_dev_env.tools - mock_DevEnvLocalSetup.assert_called_once() mock_catalog.get_dev_env_by_name.assert_called_once_with(test_env_name) mock_platform.get_local_dev_env.assert_called_once_with(mock_catalog_dev_env) @@ -140,13 +131,12 @@ def stub_check_image_availability(*args, **kwargs): assert console.file.getvalue() == runner_result.stdout @patch("dem.cli.command.pull_cmd.DevEnv") -@patch("dem.cli.command.pull_cmd.DevEnvLocalSetup") -def test_dev_env_new_install(mock_DevEnvLocalSetup: MagicMock, mock_DevEnv: MagicMock): +def test_dev_env_new_install(mock_DevEnv: MagicMock): # Test setup mock_platform = MagicMock() - mock_DevEnvLocalSetup.return_value = mock_platform mock_catalog = MagicMock() mock_platform.dev_env_catalogs.catalogs = [mock_catalog] + main.platform = mock_platform mock_catalog_dev_env = MagicMock() mock_tools = MagicMock() @@ -175,7 +165,6 @@ def stub_check_image_availability(*args, **kwargs): assert 0 == runner_result.exit_code assert mock_local_dev_env in mock_platform.local_dev_envs - mock_DevEnvLocalSetup.assert_called_once() mock_catalog.get_dev_env_by_name.assert_called_once_with(test_env_name) mock_platform.get_local_dev_env.assert_called_once_with(mock_catalog_dev_env) mock_DevEnv.assert_called_once_with(dev_env_to_copy=mock_catalog_dev_env) @@ -191,13 +180,11 @@ def stub_check_image_availability(*args, **kwargs): @patch("dem.cli.command.pull_cmd.stderr.print") @patch("dem.cli.command.pull_cmd.install_to_dev_env_json") -@patch("dem.cli.command.pull_cmd.DevEnvLocalSetup") -def test_execute_install_failed(mock_DevEnvLocalSetup: MagicMock, - mock_install_to_dev_env_json: MagicMock, +def test_execute_install_failed(mock_install_to_dev_env_json: MagicMock, mock_stderr_print: MagicMock): # Test setup mock_platform = MagicMock() - mock_DevEnvLocalSetup.return_value = mock_platform + main.platform = mock_platform mock_catalog = MagicMock() mock_platform.dev_env_catalogs.catalogs = [mock_catalog] @@ -222,7 +209,6 @@ def test_execute_install_failed(mock_DevEnvLocalSetup: MagicMock, # Check expectations assert 0 == runner_result.exit_code - mock_DevEnvLocalSetup.assert_called_once() mock_catalog.get_dev_env_by_name(test_env_name) mock_platform.get_local_dev_env.assert_called_once_with(mock_catalog_dev_env) mock_install_to_dev_env_json.assert_called_once_with(mock_local_dev_env, mock_catalog_dev_env, @@ -234,12 +220,11 @@ def test_execute_install_failed(mock_DevEnvLocalSetup: MagicMock, mock_stderr_print.assert_called_once_with("The installation failed.") @patch("dem.cli.command.pull_cmd.stderr.print") -@patch("dem.cli.command.pull_cmd.DevEnvLocalSetup") -def test_execute_no_catalogs(mock_DevEnvLocalSetup: MagicMock, mock_stderr_print: MagicMock): +def test_execute_no_catalogs(mock_stderr_print: MagicMock): # Test setup mock_platform = MagicMock() - mock_DevEnvLocalSetup.return_value = mock_platform mock_platform.dev_env_catalogs.catalogs = [] + main.platform = mock_platform test_env_name = "test_env" @@ -249,19 +234,16 @@ def test_execute_no_catalogs(mock_DevEnvLocalSetup: MagicMock, mock_stderr_print # Check expectations assert 0 == runner_result.exit_code - mock_DevEnvLocalSetup.assert_called_once() mock_stderr_print.assert_called_once_with("[red]Error: No Development Environment Catalogs are available to pull the image from![/]") @patch("dem.cli.command.pull_cmd.stderr.print") -@patch("dem.cli.command.pull_cmd.DevEnvLocalSetup") -def test_execute_dev_env_not_available_in_catalog(mock_DevEnvLocalSetup: MagicMock, - mock_stderr_print: MagicMock): +def test_execute_dev_env_not_available_in_catalog(mock_stderr_print: MagicMock): # Test setup mock_platform = MagicMock() - mock_DevEnvLocalSetup.return_value = mock_platform mock_catalog = MagicMock() mock_catalog.get_dev_env_by_name.return_value = None mock_platform.dev_env_catalogs.catalogs = [mock_catalog] + main.platform = mock_platform test_env_name = "test_env" @@ -271,6 +253,5 @@ def test_execute_dev_env_not_available_in_catalog(mock_DevEnvLocalSetup: MagicMo # Check expectations assert 0 == runner_result.exit_code - mock_DevEnvLocalSetup.assert_called_once() mock_catalog.get_dev_env_by_name.assert_called_once_with(test_env_name) mock_stderr_print.assert_called_once_with("[red]Error: The input Development Environment is not available for the organization.[/]") \ No newline at end of file diff --git a/tests/cli/test_rename_cmd.py b/tests/cli/test_rename_cmd.py index 727f0f5d..4a1e11cb 100644 --- a/tests/cli/test_rename_cmd.py +++ b/tests/cli/test_rename_cmd.py @@ -14,14 +14,13 @@ runner = CliRunner(mix_stderr=False) ## Test cases -@patch("dem.cli.command.rename_cmd.DevEnvLocalSetup") -def test_rename_success(mock_DevEnvLocalSetup): +def test_rename_success(): # Test setup original_dev_env_name = "original_dev_env_name" new_dev_env_name = "new_dev_env_name" fake_local_platform = MagicMock() - mock_DevEnvLocalSetup.return_value = fake_local_platform + main.platform = fake_local_platform fake_dev_env_to_rename = MagicMock() fake_local_platform.get_dev_env_by_name.return_value = fake_dev_env_to_rename @@ -34,21 +33,18 @@ def test_rename_success(mock_DevEnvLocalSetup): assert 0 == runner_result.exit_code assert fake_dev_env_to_rename.name is new_dev_env_name - mock_DevEnvLocalSetup.assert_called_once() fake_local_platform.get_dev_env_by_name.assert_called_once_with(original_dev_env_name) fake_local_platform.flush_to_file.assert_called_once() @patch("dem.cli.command.rename_cmd.stderr.print") -@patch("dem.cli.command.rename_cmd.DevEnvLocalSetup") -def test_rename_non_existing(mock_DevEnvLocalSetup, mock_stderr_print): +def test_rename_non_existing(mock_stderr_print): # Test setup original_dev_env_name = "original_dev_env_name" new_dev_env_name = "new_dev_env_name" - fake_local_platform = MagicMock() - mock_DevEnvLocalSetup.return_value = fake_local_platform - - fake_local_platform.get_dev_env_by_name.return_value = None + 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, @@ -57,6 +53,5 @@ def test_rename_non_existing(mock_DevEnvLocalSetup, mock_stderr_print): # Check expectations assert 0 == runner_result.exit_code - mock_DevEnvLocalSetup.assert_called_once() - fake_local_platform.get_dev_env_by_name.assert_called_once_with(original_dev_env_name) + mock_platform.get_dev_env_by_name.assert_called_once_with(original_dev_env_name) mock_stderr_print.assert_called_once_with("[red]Error: The input Development Environment does not exist.[/]") \ No newline at end of file diff --git a/tests/cli/test_run_cmd.py b/tests/cli/test_run_cmd.py index 61bcba2b..f60a29c0 100644 --- a/tests/cli/test_run_cmd.py +++ b/tests/cli/test_run_cmd.py @@ -19,23 +19,20 @@ ## Test cases @patch("dem.cli.command.run_cmd.stderr.print") -@patch("dem.cli.command.run_cmd.DevEnvLocalSetup") -def test_handle_invalid_dev_env(mock_DevEnvLocalSetup: MagicMock, mock_stderr_print: MagicMock): +def test_handle_invalid_dev_env(mock_stderr_print: MagicMock): # Test setup mock_platform = MagicMock() - mock_DevEnvLocalSetup.return_value = mock_platform mock_platform.get_dev_env_by_name.return_value = None test_dev_env_name = "test_dev_env_name" # Run unit under test with pytest.raises(typer.Abort): # execute() gets tested directly to see if the exception is raised - run_cmd.execute(test_dev_env_name, []) + run_cmd.execute(mock_platform, test_dev_env_name, []) # Check expectations mock_stderr_print.assert_called_once_with("[red]Error: Unknown Development Environment: " + test_dev_env_name + "[/]") - mock_DevEnvLocalSetup.assert_called_once() mock_platform.get_dev_env_by_name.assert_called_once_with(test_dev_env_name) @@ -98,8 +95,7 @@ def test_handle_missing_tool_images_do_fix(mock_stderr_print, mock_confirm, mock mock_stdout_print.assert_called_once_with("[green]DEM fixed the " + mock_dev_env_local.name + "![/]") @patch("dem.cli.command.run_cmd.handle_missing_tool_images") -@patch("dem.cli.command.run_cmd.DevEnvLocalSetup") -def test_execute(mock_DevEnvLocalSetup, mock_handle_missing_tool_images): +def test_execute(mock_handle_missing_tool_images): # Test setup test_dev_env_name = "test_dev_env_name" test_tool_type = "test_tool_type" @@ -109,11 +105,11 @@ def test_execute(mock_DevEnvLocalSetup, mock_handle_missing_tool_images): mock_platform = MagicMock() mock_platform.tool_images.local.elements = ["test_image_name:test_image_version"] - mock_DevEnvLocalSetup.return_value = mock_platform + main.platform = mock_platform mock_dev_env_local = MagicMock() mock_platform.get_dev_env_by_name.return_value = mock_dev_env_local - mock_DevEnvLocalSetup.update_tool_images_on_instantiation = True + main.DevEnvLocalSetup.update_tool_images_on_instantiation = True mock_dev_env_local.tools = [ { @@ -133,9 +129,8 @@ def test_execute(mock_DevEnvLocalSetup, mock_handle_missing_tool_images): # Check expectations assert 0 == runner_result.exit_code - assert mock_DevEnvLocalSetup.update_tool_images_on_instantiation is False + assert main.DevEnvLocalSetup.update_tool_images_on_instantiation is False - mock_DevEnvLocalSetup.assert_called_once() mock_platform.get_dev_env_by_name.assert_called_once_with(test_dev_env_name) mock_platform.tool_images.local.update.assert_called_once()