From a1e3e4e3ec2308210597963ba014dfbf8ecebddd Mon Sep 17 00:00:00 2001 From: bra-i-am Date: Wed, 27 Mar 2024 18:26:48 -0500 Subject: [PATCH] test: add behave & unit tests for run_extra_commands command * refactor: solve some linter issues and --- features/run_extra_commands.feature | 14 ++++ features/steps/run_extra_commands_step.py | 64 ++++++++++++++++ tests/distro/run_extra_commands/__init__.py | 0 .../application/__init__.py | 0 .../application/test_run_command.py | 74 +++++++++++++++++++ .../infrastructure/__init__.py | 0 .../infrastructure/test_tutor_commands.py | 42 +++++++++++ .../extra_commands/domain/command_manager.py | 2 +- .../infrastructure/tutor_commands.py | 45 ++++++----- tutordistro/utils/constants.py | 17 +++++ 10 files changed, 239 insertions(+), 19 deletions(-) create mode 100644 features/run_extra_commands.feature create mode 100644 features/steps/run_extra_commands_step.py create mode 100644 tests/distro/run_extra_commands/__init__.py create mode 100644 tests/distro/run_extra_commands/application/__init__.py create mode 100644 tests/distro/run_extra_commands/application/test_run_command.py create mode 100644 tests/distro/run_extra_commands/infrastructure/__init__.py create mode 100644 tests/distro/run_extra_commands/infrastructure/test_tutor_commands.py create mode 100644 tutordistro/utils/constants.py diff --git a/features/run_extra_commands.feature b/features/run_extra_commands.feature new file mode 100644 index 0000000..f42234e --- /dev/null +++ b/features/run_extra_commands.feature @@ -0,0 +1,14 @@ +Feature: Run extra commands + @fixture.behave.tutor_root + Scenario: Execute the extra commands from config.yml properly + Given There is a tutor root + And There is a config.yml file + And There are valid commands defined + When I write the command tutor distro run-extra-commands and commands will be properly executed + + @fixture.behave.tutor_root + Scenario: Execute commands that are not valid + Given There is a tutor root + And There is a config.yml file + And There are invalid commands defined + When I write the command tutor distro run-extra-commands and commands execution will fail \ No newline at end of file diff --git a/features/steps/run_extra_commands_step.py b/features/steps/run_extra_commands_step.py new file mode 100644 index 0000000..a7044fa --- /dev/null +++ b/features/steps/run_extra_commands_step.py @@ -0,0 +1,64 @@ +import os + +import subprocess + +from behave import given, when, then # pylint: disable=no-name-in-module +from click.testing import CliRunner +from tutor import config as tutor_config + +from tutordistro.commands.run_extra_commands import run_extra_commands + + +@given("There are valid commands defined") +def step_impl(context): # pylint: disable=function-redefined,missing-function-docstring + extra_commands = [ + "tutor plugins update", + "tutor plugins install forum", + "tutor plugins enable forum" + ] + + config = context.scenario.config + config.update({ + "DISTRO_EXTRA_COMMANDS": extra_commands + }) + + tutor_config.save_config_file(context.scenario.tutor_root, config) + config = tutor_config.load(context.scenario.tutor_root) + context.scenario.config = config + context.scenario.extra_commands = "DISTRO_EXTRA_COMMANDS" + + assert "DISTRO_EXTRA_COMMANDS" in config + + +@given("There are invalid commands defined") +def step_impl(context): # pylint: disable=function-redefined,missing-function-docstring + extra_commands = [ + "pip install application" + ] + + config = context.scenario.config + config.update({ + "DISTRO_EXTRA_COMMANDS": extra_commands + }) + + tutor_config.save_config_file(context.scenario.tutor_root, config) + config = tutor_config.load(context.scenario.tutor_root) + context.scenario.config = config + context.scenario.extra_commands = "DISTRO_EXTRA_COMMANDS" + + assert "DISTRO_EXTRA_COMMANDS" in config + + +@when("I write the command tutor distro run-extra-commands and commands will be properly executed") +def step_impl(context): # pylint: disable=function-redefined,missing-function-docstring + runner = CliRunner() + result = runner.invoke(run_extra_commands, obj=context) + assert result.exit_code == 0 + + +@when("I write the command tutor distro run-extra-commands and commands execution will fail") +def step_impl(context): # pylint: disable=function-redefined,missing-function-docstring + runner = CliRunner() + result = runner.invoke(run_extra_commands, obj=context) + assert result.exit_code != 0 + diff --git a/tests/distro/run_extra_commands/__init__.py b/tests/distro/run_extra_commands/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/distro/run_extra_commands/application/__init__.py b/tests/distro/run_extra_commands/application/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/distro/run_extra_commands/application/test_run_command.py b/tests/distro/run_extra_commands/application/test_run_command.py new file mode 100644 index 0000000..b198ff0 --- /dev/null +++ b/tests/distro/run_extra_commands/application/test_run_command.py @@ -0,0 +1,74 @@ +""" +Test run commands application. +""" + +import pytest + +from tests.distro.run_extra_commands.infrastructure.test_tutor_commands import TestTutorCommandManager +from tutordistro.distro.extra_commands.application.commands_runner import CommandsRunner +from tutordistro.distro.share.domain.command_error import CommandError + + +def test_valid_tutor_command(): + """ + Test running valid commands. + + This test verifies that are executed all the extra commands successfully. + """ + # Given + tutor_commands_manager = TestTutorCommandManager() + run_tutor_command = CommandsRunner(commands_manager=tutor_commands_manager) + + valid_tutor_commands = [ + "command with word tutor 1", + "command with word tutor 2", + "command with word tutor 3", + ] + + # When + for command in valid_tutor_commands: + run_tutor_command(command=command) + + assert tutor_commands_manager.commands_ran == len(valid_tutor_commands) + + +def test_invalid_tutor_command(): + """ + Test running invalid commands. + + This test verifies that the execution fails when is + intended to execute invalid extra commands. + """ + # Given + tutor_commands_manager = TestTutorCommandManager() + run_tutor_command = CommandsRunner(commands_manager=tutor_commands_manager) + + invalid_tutor_command = "pip command 1" + + # When + with pytest.raises(CommandError) as command_error: + run_tutor_command(command=invalid_tutor_command) + + assert command_error.type is CommandError + assert "is not a valid Tutor command" in command_error.value.args[0] + + +def test_misspelled_tutor_command(): + """ + Test running misspelled Tutor commands. + + This test verifies that is warned the user of trying to execute + a misspelled Tutor command. + """ + # Given + tutor_commands_manager = TestTutorCommandManager() + run_tutor_command = CommandsRunner(commands_manager=tutor_commands_manager) + + invalid_tutor_command = "totur command bad written" + + # When + with pytest.raises(CommandError) as command_error: + run_tutor_command(command=invalid_tutor_command) + + assert command_error.type is CommandError + assert "you have a typo" in command_error.value.args[0] diff --git a/tests/distro/run_extra_commands/infrastructure/__init__.py b/tests/distro/run_extra_commands/infrastructure/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/distro/run_extra_commands/infrastructure/test_tutor_commands.py b/tests/distro/run_extra_commands/infrastructure/test_tutor_commands.py new file mode 100644 index 0000000..9d3b970 --- /dev/null +++ b/tests/distro/run_extra_commands/infrastructure/test_tutor_commands.py @@ -0,0 +1,42 @@ +""" +Test tutor commands functions. +""" + +from tutordistro.distro.extra_commands.domain.command_manager import CommandManager +from tutordistro.distro.share.domain.command_error import CommandError +from tutordistro.utils.constants import find_tutor_misspelled + + +class TestTutorCommandManager(CommandManager): + """ + Executes a Tutor command for testing. + + This class provides functionality to execute extra Tutor commands for testing. + + Args: + CommandManager (class): Base command manager class. + """ + commands_ran = 0 + + def run_command(self, command: str): + """ + This method runs an testing command. + + Args: + command (str): Testing command. + """ + is_tutor_misspelled = find_tutor_misspelled(command) + + if "tutor" not in command.lower(): + if is_tutor_misspelled: + raise CommandError( + f'Maybe you have a typo using the command "{command}"' + ) + raise CommandError( + f''' + Command "{command}" is not a valid Tutor command. + Take the official Tutor commands into account + https://docs.tutor.edly.io/reference/cli/index.html + ''' + ) + self.commands_ran += 1 diff --git a/tutordistro/distro/extra_commands/domain/command_manager.py b/tutordistro/distro/extra_commands/domain/command_manager.py index b453ec2..29f3437 100644 --- a/tutordistro/distro/extra_commands/domain/command_manager.py +++ b/tutordistro/distro/extra_commands/domain/command_manager.py @@ -8,5 +8,5 @@ class CommandManager(metaclass=abc.ABCMeta): """Command Manager""" @abstractmethod - def run_command(self, command: str, tutor_root: str): + def run_command(self, command: str): """Run a command.""" diff --git a/tutordistro/distro/extra_commands/infrastructure/tutor_commands.py b/tutordistro/distro/extra_commands/infrastructure/tutor_commands.py index a2b0188..fd38eed 100644 --- a/tutordistro/distro/extra_commands/infrastructure/tutor_commands.py +++ b/tutordistro/distro/extra_commands/infrastructure/tutor_commands.py @@ -2,12 +2,11 @@ Distro tutor commands functions. """ -import os import subprocess -import re from tutordistro.distro.extra_commands.domain.command_manager import CommandManager from tutordistro.distro.share.domain.command_error import CommandError +from tutordistro.utils.constants import find_tutor_misspelled class TutorCommandManager(CommandManager): @@ -28,26 +27,36 @@ def run_command(self, command: str): Args: command (str): Tutor command. - tutor_root (str): Tutor path where to execute the command. """ try: - is_tutor_bad_written = re.match(r'[tT](?:[oru]{3}|[oru]{2}[rR]|[oru]u?)', command) + is_tutor_misspelled = find_tutor_misspelled(command) if "tutor" not in command.lower(): - if is_tutor_bad_written: - raise CommandError(f'Maybe you have a typo using the command "{command}"') - else: - raise CommandError(f'Command "{command}" is not a valid Tutor command. Take the official Tutor commands into account https://docs.tutor.edly.io/reference/cli/index.html') - - process = subprocess.Popen( + if is_tutor_misspelled: + raise CommandError( + f'Maybe you have a typo using the command "{command}"' + ) + raise CommandError( + f""" + Command "{command}" is not a valid Tutor command. + Take the official Tutor commands into account + https://docs.tutor.edly.io/reference/cli/index.html + """ + ) + with subprocess.Popen( command, - shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, executable='/bin/bash' - ) - - output, error = process.communicate() - # If a command failed - if process.returncode != 0: - raise CommandError(f'Error running command "{command}".\n{output.decode()}\n{error.decode()}') + shell=True, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + executable="/bin/bash", + ) as process: + output, error = process.communicate() + # If a command failed + if process.returncode != 0: + raise CommandError( + f'Error running command "{command}".\n{error.decode()}' + ) + print(output.decode()) except subprocess.SubprocessError as error: - raise CommandError(f'Error running command {command}: {error}') from error + raise CommandError(f"Error running command {command}: {error}") from error diff --git a/tutordistro/utils/constants.py b/tutordistro/utils/constants.py new file mode 100644 index 0000000..110528d --- /dev/null +++ b/tutordistro/utils/constants.py @@ -0,0 +1,17 @@ +""" +File of constant variables +""" +import re + + +def find_tutor_misspelled(command: str): + """ + This function takes a command and looks if it has the word 'tutor' misspelled + + Args: + command (str): Command to be reviewed + + Return: + If its found the word 'tutor' misspelled is returned True + """ + return re.match(r'[tT](?:[oru]{3}|[oru]{2}[rR]|[oru]u?)', command)