From a67f1df9410cea9422fed67c59cc6e897936898f Mon Sep 17 00:00:00 2001 From: sowmyasri Date: Fri, 26 Jul 2024 13:28:01 +0200 Subject: [PATCH] wrapped check yaml exist to separate method changed the import test cases for CLI command train,validate,startup,controller start and version --- fedn/cli/client_cmd.py | 4 +- fedn/cli/controller_cmd.py | 2 +- fedn/cli/run_cmd.py | 35 +++--- fedn/cli/tests/tests.py | 227 ++++++++++++++++++++++++++++++++++++- 4 files changed, 243 insertions(+), 25 deletions(-) diff --git a/fedn/cli/client_cmd.py b/fedn/cli/client_cmd.py index 80b0b3353..bb71003d7 100644 --- a/fedn/cli/client_cmd.py +++ b/fedn/cli/client_cmd.py @@ -6,8 +6,8 @@ from fedn.common.exceptions import InvalidClientConfig from fedn.network.clients.client import Client -from .main import main -from .shared import CONTROLLER_DEFAULTS, apply_config, get_api_url, get_token, print_response +from fedn.cli.main import main +from fedn.cli.shared import CONTROLLER_DEFAULTS, apply_config, get_api_url, get_token, print_response def validate_client_config(config): diff --git a/fedn/cli/controller_cmd.py b/fedn/cli/controller_cmd.py index ab8727b27..443628c9a 100644 --- a/fedn/cli/controller_cmd.py +++ b/fedn/cli/controller_cmd.py @@ -1,6 +1,6 @@ import click -from .main import main +from fedn.cli.main import main @main.group("controller") diff --git a/fedn/cli/run_cmd.py b/fedn/cli/run_cmd.py index 5c0fc797e..9191c0d55 100644 --- a/fedn/cli/run_cmd.py +++ b/fedn/cli/run_cmd.py @@ -10,9 +10,9 @@ from fedn.network.combiner.combiner import Combiner from fedn.utils.dispatcher import Dispatcher, _read_yaml_file -from .client_cmd import validate_client_config -from .main import main -from .shared import apply_config +from fedn.cli.client_cmd import validate_client_config +from fedn.cli.main import main +from fedn.cli.shared import apply_config def get_statestore_config_from_file(init): @@ -36,7 +36,14 @@ def check_helper_config_file(config): exit(-1) return helper - +def check_yaml_exists(path): + """Check if fedn.yaml exists in the given path.""" + yaml_file = os.path.join(path, "fedn.yaml") + if not os.path.exists(yaml_file): + logger.error(f"Could not find fedn.yaml in {path}") + click.echo(f"Could not find fedn.yaml in {path}") + exit(-1) + return yaml_file @main.group("run") @click.pass_context def run_cmd(ctx): @@ -57,10 +64,7 @@ def validate_cmd(ctx, path,input,output,remove_venv): :type path: str """ path = os.path.abspath(path) - yaml_file = os.path.join(path, "fedn.yaml") - if not os.path.exists(yaml_file): - logger.error(f"Could not find fedn.yaml in {path}") - exit(-1) + yaml_file = check_yaml_exists(path) config = _read_yaml_file(yaml_file) # Check that validate is defined in fedn.yaml under entry_points @@ -92,10 +96,7 @@ def train_cmd(ctx, path,input,output,remove_venv): :type path: str """ path = os.path.abspath(path) - yaml_file = os.path.join(path, "fedn.yaml") - if not os.path.exists(yaml_file): - logger.error(f"Could not find fedn.yaml in {path}") - exit(-1) + yaml_file = check_yaml_exists(path) config = _read_yaml_file(yaml_file) # Check that train is defined in fedn.yaml under entry_points @@ -125,10 +126,7 @@ def startup_cmd(ctx, path,remove_venv): :type path: str """ path = os.path.abspath(path) - yaml_file = os.path.join(path, "fedn.yaml") - if not os.path.exists(yaml_file): - logger.error(f"Could not find fedn.yaml in {path}") - exit(-1) + yaml_file = check_yaml_exists(path) config = _read_yaml_file(yaml_file) # Check that startup is defined in fedn.yaml under entry_points @@ -159,10 +157,7 @@ def build_cmd(ctx, path,remove_venv): :type path: str """ path = os.path.abspath(path) - yaml_file = os.path.join(path, "fedn.yaml") - if not os.path.exists(yaml_file): - logger.error(f"Could not find fedn.yaml in {path}") - exit(-1) + yaml_file = check_yaml_exists(path) config = _read_yaml_file(yaml_file) # Check that build is defined in fedn.yaml under entry_points diff --git a/fedn/cli/tests/tests.py b/fedn/cli/tests/tests.py index dffe90a2c..7cf6878c4 100644 --- a/fedn/cli/tests/tests.py +++ b/fedn/cli/tests/tests.py @@ -1,9 +1,17 @@ import unittest - +import sys +import os +import fedn +from unittest.mock import patch from click.testing import CliRunner from run_cmd import check_helper_config_file +from run_cmd import run_cmd,check_yaml_exists,logger +import click +from main import main +from fedn.network.api.server import start_server_api +from controller_cmd import main, controller_cmd - +MOCK_VERSION = "0.11.1" class TestReducerCLI(unittest.TestCase): def setUp(self): @@ -56,6 +64,221 @@ def test_get_statestore_config_from_file(self): # self.assertEqual(result.output, "--remote was set to False, but no helper was found in --init settings file: settings.yaml\n") # self.assertEqual(result.exit_code, -1) + #testcase for --version in fedn + @patch('main.get_version') + def test_version_output(self, mock_get_version): + # Mock the get_version function to return a predefined version + mock_get_version.return_value = MOCK_VERSION + + runner = CliRunner() + result = runner.invoke(main, ['--version']) + + # Check that the command exits with a status code of 0 + self.assertEqual(result.exit_code, 0) + + # Check that the output contains the mocked version string + expected_output = f"main, version {MOCK_VERSION}\n" + self.assertEqual(result.output, expected_output) + + #train command unit test cases + #To test check yaml function + @patch('run_cmd.os.path.exists') + @patch('run_cmd.click.echo') + def test_yaml_exists(self, mock_click_echo, mock_exists): + path = '/fake/path' + mock_exists.return_value = True + + # Call the function + result = check_yaml_exists(path) + # Assertions + mock_exists.assert_called_once_with(os.path.join(path, 'fedn.yaml')) + self.assertEqual(result, os.path.join(path, 'fedn.yaml')) + mock_click_echo.assert_not_called() + #test missing fedn yaml file + @patch('run_cmd.os.path.exists') + def test_missing_fedn_yaml(self, mock_exists): + mock_exists.return_value = False + result = self.runner.invoke(run_cmd, [ + 'train', + '--path', 'fedn/examples/mnist-pytorch/client', + '--input', 'client.npz', + '--output', 'client' + ]) + self.assertEqual(result.exit_code, -1) + self.assertIn("", result.output) + + #train cmd missing in fedn yaml file + @patch('run_cmd._read_yaml_file') + @patch('run_cmd.logger') + @patch('run_cmd.exit') + @patch('run_cmd.check_yaml_exists') + def test_train_not_defined(self, mock_check_yaml_exists, mock_exit, mock_logger, mock_read_yaml_file): + # Setup the mock to simulate fedn.yaml content without "train" entry point + mock_read_yaml_file.return_value = { + "entry_points": { + "vaidate": "some_train_command" + } + } + mock_check_yaml_exists.return_value = '/fake/path/fedn.yaml' + result = self.runner.invoke(run_cmd, [ + 'train', + '--path', '/fake/path', + '--input', 'input', + '--output', 'output', + '--remove-venv', 'True' + ]) + mock_logger.error.assert_called_once_with("No train command defined in fedn.yaml") + #print("hereeeeee",mock_logger.error.call_count) + log_messages = [call[0][0] for call in mock_logger.error.call_args_list] + #print("Captured log messages:", log_messages) + mock_exit.assert_called_once_with(-1) + + #to test with venv flag as false + @patch('run_cmd.os.path.exists') + @patch('run_cmd.logger') + @patch('run_cmd.Dispatcher') + def test_train_cmd_with_venv_false(self, MockDispatcher,mock_exists,mock_logger): + mock_exists.return_value = True + mock_dispatcher = MockDispatcher.return_value + mock_dispatcher.run_cmd.return_value = None + result = self.runner.invoke(run_cmd, [ + 'train', + '--path', '../../.././fedn/examples/mnist-pytorch/client', + '--input', 'client.npz', + '--output', 'client', + '--remove-venv', 'False' + ]) + + self.assertEqual(result.exit_code, 0) + mock_dispatcher.run_cmd.assert_called_once_with("train client.npz client") + #print(mock_dispatcher.run_cmd.call_count) + +#Validate cmd test cases + @patch('run_cmd._read_yaml_file') + @patch('run_cmd.logger') + @patch('run_cmd.exit') + @patch('run_cmd.check_yaml_exists') + def test_validate_not_defined(self, mock_check_yaml_exists, mock_exit, mock_logger, mock_read_yaml_file): + mock_read_yaml_file.return_value = { + "entry_points": { + "train": "some_train_command" + } + } + mock_check_yaml_exists.return_value = '/fake/path/fedn.yaml' + result = self.runner.invoke(run_cmd, [ + 'validate', + '--path', '/fake/path', + '--input', 'input', + '--output', 'output', + '--remove-venv', 'True' + ]) + + + # Verify that the error was logged + mock_logger.error.assert_called_once_with("No validate command defined in fedn.yaml") + #log_messages = [call[0][0] for call in mock_logger.error.call_args_list] + #print("Captured log messages:", log_messages) + mock_exit.assert_called_once_with(-1) + + #test missing fedn yaml file + @patch('run_cmd.os.path.exists') + def test_missing_fedn_yaml(self, mock_exists): + mock_exists.return_value = False + result = self.runner.invoke(run_cmd, [ + 'vaidate', + '--path', 'fedn/examples/mnist-pytorch/client', + '--input', 'client.npz', + '--output', 'client' + ]) + self.assertEqual(result.exit_code, -1) + self.assertIn("", result.output) + + #Test validate cmd with venv false + @patch('run_cmd.os.path.exists') + @patch('run_cmd.logger') + @patch('run_cmd.Dispatcher') + def test_validate_cmd_with_venv_false(self, MockDispatcher,mock_exists,mock_logger): + mock_exists.return_value = True + mock_dispatcher = MockDispatcher.return_value + mock_dispatcher.run_cmd.return_value = None + result = self.runner.invoke(run_cmd, [ + 'validate', + '--path', '../../.././fedn/examples/mnist-pytorch/client', + '--input', 'client.npz', + '--output', 'client', + '--remove-venv', 'False' + ]) + + self.assertEqual(result.exit_code, 0) + mock_dispatcher.run_cmd.assert_called_once_with("validate client.npz client") + #print(mock_dispatcher.run_cmd.call_count) + +#build cmd test cases + @patch('run_cmd._read_yaml_file') + @patch('run_cmd.logger') + @patch('run_cmd.exit') + @patch('run_cmd.check_yaml_exists') + def test_startup_not_defined(self, mock_check_yaml_exists, mock_exit, mock_logger, mock_read_yaml_file): + mock_read_yaml_file.return_value = { + "entry_points": { + "train": "some_train_command" + } + } + mock_check_yaml_exists.return_value = '/fake/path/fedn.yaml' + runner = CliRunner() + result = runner.invoke(run_cmd, [ + 'startup', + '--path', '/fake/path', + '--remove-venv', 'True' + ]) + + + # Verify that the error was logged + mock_logger.error.assert_called_once_with("No startup command defined in fedn.yaml") + log_messages = [call[0][0] for call in mock_logger.error.call_args_list] + #print("Captured log messages:", log_messages) + mock_exit.assert_called_once_with(-1) + + #test missing fedn yaml file + @patch('run_cmd.os.path.exists') + def test_missing_fedn_yaml(self, mock_exists): + mock_exists.return_value = False + result = self.runner.invoke(run_cmd, [ + 'startup', + '--path', 'fedn/examples/mnist-pytorch/client' + ]) + self.assertEqual(result.exit_code, -1) + self.assertIn("", result.output) + + @patch('run_cmd.os.path.exists') + @patch('run_cmd.logger') + @patch('run_cmd.Dispatcher') + def test_startup_cmd_with_venv_false(self, MockDispatcher,mock_exists,mock_logger): + mock_exists.return_value = True + mock_dispatcher = MockDispatcher.return_value + mock_dispatcher.run_cmd.return_value = None + result = self.runner.invoke(run_cmd, [ + 'startup', + '--path', '../../.././fedn/examples/mnist-pytorch/client', + '--remove-venv', 'False' + ]) + + self.assertEqual(result.exit_code, 0) + mock_dispatcher.run_cmd.assert_called_once_with("startup") + #print(mock_dispatcher.run_cmd.call_count) + + #to test controller start + @patch('fedn.network.api.server.start_server_api') + def test_controller_start(self, mock_start_server_api): + runner = CliRunner() + result = runner.invoke(main, ['controller', 'start']) + + # Check that the command exits with a status code of 0 + self.assertEqual(result.exit_code, 0) + + # Check that the start_server_api function was called + mock_start_server_api.assert_called_once() + #print("hereeee",mock_start_server_api.call_count) def test_check_helper_config_file(self): self.assertEqual(check_helper_config_file(