diff --git a/config/test.json b/config/test.json deleted file mode 100644 index c215df28..00000000 --- a/config/test.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "subcontroller": { - "name": "top" - }, - "plugins": { - "logger": { - "name": "stdouterr", - "conf": { - "loglevel": 10 - } - } - } -} diff --git a/config/tests/issue309.data.xml b/config/tests/issue309.data.xml new file mode 100644 index 00000000..3e4083ee --- /dev/null +++ b/config/tests/issue309.data.xml @@ -0,0 +1,193 @@ + + + + + + + + + + + + + + + + + + + + + + + + +]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/FAQ.md b/docs/FAQ.md index 481eb28b..4f5bb700 100644 --- a/docs/FAQ.md +++ b/docs/FAQ.md @@ -19,5 +19,13 @@ This will tell you which server you cannot `ssh` to. ## What SSH commands are actually run? The simplest to know how the processes are started is to add the option `--log-level debug` for the process manager shell or the unified shell. +## Do you have unit tests? +Sure, +```bash +cd drunc/ +pytest +``` +All of the tests are in `tests` and follow the same hierarchy as the code (so for example, the unit tests of the module `drunc.utils.utils` is in `tests/utils/test_utils.py`). + ## So empty... If you have a question, please reach out to developers or fill an issue [here](https://github.com/DUNE-DAQ/drunc/issues). diff --git a/src/drunc/fsm/action_factory.py b/src/drunc/fsm/action_factory.py index 299896c4..33b843e5 100644 --- a/src/drunc/fsm/action_factory.py +++ b/src/drunc/fsm/action_factory.py @@ -61,8 +61,8 @@ def get_action(self, action_name, configuration): from drunc.fsm.actions.usvc_provided_run_number import UsvcProvidedRunNumber iface = UsvcProvidedRunNumber(configuration) case 'test-action': - from drunc.fsm.actions.test_action import TestAction - iface = TestAction(configuration) + from drunc.fsm.actions.some_test_action import SomeTestAction + iface = SomeTestAction(configuration) case "file-logbook": from drunc.fsm.actions.file_logbook import FileLogbook iface = FileLogbook(configuration) diff --git a/src/drunc/fsm/actions/test_action.py b/src/drunc/fsm/actions/some_test_action.py similarity index 94% rename from src/drunc/fsm/actions/test_action.py rename to src/drunc/fsm/actions/some_test_action.py index f3c00a25..c299b918 100644 --- a/src/drunc/fsm/actions/test_action.py +++ b/src/drunc/fsm/actions/some_test_action.py @@ -5,7 +5,7 @@ class an_enum(Enum): ONE=1 TWO=2 -class TestAction(FSMAction): +class SomeTestAction(FSMAction): def __init__(self, configuration): super().__init__( name = "test-action" diff --git a/src/drunc/tests/__main_fsm__.py b/src/drunc/tests/__main_fsm__.py deleted file mode 100644 index cd3a2052..00000000 --- a/src/drunc/tests/__main_fsm__.py +++ /dev/null @@ -1,77 +0,0 @@ -import sys -import os -import json -from .fake_controller import FakeController - -def request_args(controller, name, i_name=None): - if i_name: - interface = controller.fsm.config.interfaces[i_name] - sig = interface.get_transition_arguments(name) #The signature of the function - else: - sig = controller.fsm.get_transition_arguments(name) - p_list = [] - for p in sig.parameters.keys(): - if p not in ("self", "data"): - p_list.append(p) - if p_list == []: - return None - if i_name: - print(f"Enter the following parameters for {name} of {i_name}:") - else: - print(f"Enter the following parameters for {name}:") - print(*p_list) - inp = input("|DRUNC> ") - return dict(zip(p_list, inp.split())) - -def main(): - #Args should be drunc-fsm-tests, then the config filename - filename = sys.argv[1] - f = open(filename, 'r') - config = json.loads(f.read()) - f.close() - controller = FakeController(config) - while True: - cmd = input("|DRUNC> ") - if cmd == "quit": - break - if cmd == "ls": - print(controller.fsm.get_executable_transitions()) - continue - if cmd == "here": - print(controller.fsm.get_current_state()) - continue - - if not controller.fsm.can_execute_transition(cmd): - print(f"\"{cmd}\" is not allowed") - continue - tr_args = request_args(controller, cmd) - if tr_args: - all_args = {'tr':tr_args} - else: - all_args = {'tr':{}} - - pre = controller.fsm.config.pre_transitions - if cmd in pre: #If there are any pre-transitions for this command - name = "pre_"+cmd - for i_name in pre[cmd]['order']: #For each interface with a transition (in order) - data = request_args(controller, name, i_name) - if data: - arg_name = "pre_"+i_name - all_args[arg_name] = data - - post = controller.fsm.config.post_transitions - if cmd in post: - name = "post_"+cmd - for i_name in post[cmd]['order']: - data = request_args(controller, name, i_name) - if data: - arg_name = "post_"+i_name - all_args[arg_name] = data - try: - print(f"Sending command \"{cmd}\"") - controller.do_command(cmd, all_args) - except Exception as e: - print(e) - -if __name__ == '__main__': - main() \ No newline at end of file diff --git a/tests/__init__.py b/src/drunc/tests/authoriser/__init__.py similarity index 100% rename from tests/__init__.py rename to src/drunc/tests/authoriser/__init__.py diff --git a/src/drunc/tests/authoriser/test_configuration.py b/src/drunc/tests/authoriser/test_configuration.py new file mode 100644 index 00000000..e69de29b diff --git a/src/drunc/tests/authoriser/test_decorators.py b/src/drunc/tests/authoriser/test_decorators.py new file mode 100644 index 00000000..e69de29b diff --git a/src/drunc/tests/authoriser/test_dummy_authoriser.py b/src/drunc/tests/authoriser/test_dummy_authoriser.py new file mode 100644 index 00000000..e69de29b diff --git a/src/drunc/tests/authoriser/test_exceptions.py b/src/drunc/tests/authoriser/test_exceptions.py new file mode 100644 index 00000000..e69de29b diff --git a/src/drunc/tests/broadcast/__init__.py b/src/drunc/tests/broadcast/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/src/drunc/tests/broadcast/client/__init__.py b/src/drunc/tests/broadcast/client/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/src/drunc/tests/broadcast/client/test_broadcast_handler.py b/src/drunc/tests/broadcast/client/test_broadcast_handler.py new file mode 100644 index 00000000..e69de29b diff --git a/src/drunc/tests/broadcast/client/test_broadcast_handler_implementation.py b/src/drunc/tests/broadcast/client/test_broadcast_handler_implementation.py new file mode 100644 index 00000000..e69de29b diff --git a/src/drunc/tests/broadcast/client/test_configuration.py b/src/drunc/tests/broadcast/client/test_configuration.py new file mode 100644 index 00000000..e69de29b diff --git a/src/drunc/tests/broadcast/client/test_grpc_stdout_broadcast_handler.py b/src/drunc/tests/broadcast/client/test_grpc_stdout_broadcast_handler.py new file mode 100644 index 00000000..e69de29b diff --git a/src/drunc/tests/broadcast/client/test_kafka_stdout_broadcast_handler.py b/src/drunc/tests/broadcast/client/test_kafka_stdout_broadcast_handler.py new file mode 100644 index 00000000..e69de29b diff --git a/src/drunc/tests/broadcast/server/__init__.py b/src/drunc/tests/broadcast/server/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/src/drunc/tests/broadcast/server/test_broadcast_sender.py b/src/drunc/tests/broadcast/server/test_broadcast_sender.py new file mode 100644 index 00000000..e69de29b diff --git a/src/drunc/tests/broadcast/server/test_broadcast_sender_implementation.py b/src/drunc/tests/broadcast/server/test_broadcast_sender_implementation.py new file mode 100644 index 00000000..e69de29b diff --git a/src/drunc/tests/broadcast/server/test_configuration.py b/src/drunc/tests/broadcast/server/test_configuration.py new file mode 100644 index 00000000..e69de29b diff --git a/src/drunc/tests/broadcast/server/test_decorators.py b/src/drunc/tests/broadcast/server/test_decorators.py new file mode 100644 index 00000000..e69de29b diff --git a/src/drunc/tests/broadcast/server/test_grpc_servicer.py b/src/drunc/tests/broadcast/server/test_grpc_servicer.py new file mode 100644 index 00000000..e69de29b diff --git a/src/drunc/tests/broadcast/server/test_kafka_sender.py b/src/drunc/tests/broadcast/server/test_kafka_sender.py new file mode 100644 index 00000000..e69de29b diff --git a/src/drunc/tests/broadcast/test_types.py b/src/drunc/tests/broadcast/test_types.py new file mode 100644 index 00000000..e69de29b diff --git a/src/drunc/tests/broadcast/test_utils.py b/src/drunc/tests/broadcast/test_utils.py new file mode 100644 index 00000000..e69de29b diff --git a/src/drunc/tests/connectivity_service/__init__.py b/src/drunc/tests/connectivity_service/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/src/drunc/tests/connectivity_service/test_client.py b/src/drunc/tests/connectivity_service/test_client.py new file mode 100644 index 00000000..e69de29b diff --git a/src/drunc/tests/controller/__init__.py b/src/drunc/tests/controller/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/src/drunc/tests/controller/children_interface/__init__.py b/src/drunc/tests/controller/children_interface/__init__.py new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/src/drunc/tests/controller/children_interface/__init__.py @@ -0,0 +1 @@ + diff --git a/src/drunc/tests/controller/children_interface/test_child_node.py b/src/drunc/tests/controller/children_interface/test_child_node.py new file mode 100644 index 00000000..e69de29b diff --git a/src/drunc/tests/controller/children_interface/test_grpc_child.py b/src/drunc/tests/controller/children_interface/test_grpc_child.py new file mode 100644 index 00000000..e69de29b diff --git a/src/drunc/tests/controller/children_interface/test_rest_api_child.py b/src/drunc/tests/controller/children_interface/test_rest_api_child.py new file mode 100644 index 00000000..e69de29b diff --git a/src/drunc/tests/controller/interface/__init__.py b/src/drunc/tests/controller/interface/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/src/drunc/tests/controller/interface/test_commands.py b/src/drunc/tests/controller/interface/test_commands.py new file mode 100644 index 00000000..e69de29b diff --git a/src/drunc/tests/controller/interface/test_context.py b/src/drunc/tests/controller/interface/test_context.py new file mode 100644 index 00000000..e69de29b diff --git a/src/drunc/tests/controller/interface/test_controller.py b/src/drunc/tests/controller/interface/test_controller.py new file mode 100644 index 00000000..e69de29b diff --git a/src/drunc/tests/controller/interface/test_shell.py b/src/drunc/tests/controller/interface/test_shell.py new file mode 100644 index 00000000..e69de29b diff --git a/src/drunc/tests/controller/interface/test_shell_utils.py b/src/drunc/tests/controller/interface/test_shell_utils.py new file mode 100644 index 00000000..e69de29b diff --git a/src/drunc/tests/controller/test_configuration.py b/src/drunc/tests/controller/test_configuration.py new file mode 100644 index 00000000..e69de29b diff --git a/src/drunc/tests/controller/test_controller.py b/src/drunc/tests/controller/test_controller.py new file mode 100644 index 00000000..e69de29b diff --git a/src/drunc/tests/controller/test_controller_driver.py b/src/drunc/tests/controller/test_controller_driver.py new file mode 100644 index 00000000..e69de29b diff --git a/src/drunc/tests/controller/test_decorators.py b/src/drunc/tests/controller/test_decorators.py new file mode 100644 index 00000000..e69de29b diff --git a/src/drunc/tests/controller/test_exceptions.py b/src/drunc/tests/controller/test_exceptions.py new file mode 100644 index 00000000..e69de29b diff --git a/src/drunc/tests/controller/test_stateful_node.py b/src/drunc/tests/controller/test_stateful_node.py new file mode 100644 index 00000000..e69de29b diff --git a/src/drunc/tests/controller/test_utils.py b/src/drunc/tests/controller/test_utils.py new file mode 100644 index 00000000..e69de29b diff --git a/src/drunc/tests/create_skeleton_test b/src/drunc/tests/create_skeleton_test new file mode 100755 index 00000000..1d723396 --- /dev/null +++ b/src/drunc/tests/create_skeleton_test @@ -0,0 +1,42 @@ +#!/usr/bin/env python3 +import os +from pathlib import Path +from rich import print + +drunc_srcs = (Path(os.path.abspath(__file__)) / ".." / "..").resolve() +test_dir = (Path(os.path.abspath(__file__)) / "..").resolve() +print(f"test_dir {test_dir}") +ignore_prefix_dirs = [drunc_srcs/"apps", drunc_srcs/"tests", drunc_srcs/"data", drunc_srcs/"apps"] +ignore_prefix_dirs = list(map(str, ignore_prefix_dirs)) +ignore_dirs = ['__pycache__'] + +for root, directories, files in os.walk(drunc_srcs): + + ignored_dir = any([ignore_dir in root for ignore_dir in ignore_prefix_dirs]) + ignored_dir |= any([ignore_dir in root for ignore_dir in ignore_dirs]) + + if ignored_dir: + continue + print(f"Processing {root}") + + for fi in files: + if not fi.endswith(".py") or fi == '__init__.py': + continue + + if root == str(drunc_srcs): + test_root_dir = test_dir + else: + test_root_dir = test_dir / root.replace(str(drunc_srcs)+"/", "") + + if not test_root_dir.exists(): + print(f"Creating {test_root_dir}, based on {root}") + test_root_dir.mkdir(parents=True) + init_file = test_root_dir/"__init__.py" + init_file.touch() + + test_file = test_root_dir / f"test_{fi}" + + if not test_file.exists(): + print(f"Creating {test_file}, based on {fi}") + test_file.touch() + diff --git a/src/drunc/tests/fake_controller.py b/src/drunc/tests/fake_controller.py deleted file mode 100644 index 9cf37c8e..00000000 --- a/src/drunc/tests/fake_controller.py +++ /dev/null @@ -1,56 +0,0 @@ -import os -import sys -top_dir = os.environ['DRUNC_DIR'] -fsm_dir = os.path.join(top_dir, 'src', 'drunc', 'fsm') -sys.path.append(fsm_dir) -from drunc.fms.core import FSM - -class FakeController: - def __init__(self, config): - self.name = "controller" - self.fsm = FSM(configuration=config) - methods = [attr for attr in dir(self) if callable(getattr(self, attr))] #Get every callable attribute (i.e methods) - unmangled= [m for m in methods if m[0] != '_'] #Filters out methods starting with a _ - unwanted = ["do_command", "get_state"] - cmds = [c for c in unmangled if c not in unwanted] #Filters out non-FSM methods - for command in cmds: - self.fsm.register_transition(command, getattr(self, command)) #Passes every command to the FSM - - def do_command(self, transition, transition_data): - self.fsm.execute_transition(transition, transition_data) - - def get_state(self): - return self.fsm.get_current_state() - - def boot(self, data): - pass - - def conf(self, data, a_number:int): - pass - - def start(self, data): - pass - - def enable_triggers(self, data): - pass - - def disable_triggers(self, data): - pass - - def drain_dataflow(self, data): - pass - - def stop_trigger_sources(self, data): - pass - - def stop(self, data): - pass - - def scrap(self, data): - pass - - def terminate(self, data): - pass - - def abort(self, data): - pass \ No newline at end of file diff --git a/src/drunc/tests/fsm/__init__.py b/src/drunc/tests/fsm/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/src/drunc/tests/fsm/actions/__init__.py b/src/drunc/tests/fsm/actions/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/src/drunc/tests/fsm/actions/test_db_run_registry.py b/src/drunc/tests/fsm/actions/test_db_run_registry.py new file mode 100644 index 00000000..e69de29b diff --git a/src/drunc/tests/fsm/actions/test_file_logbook.py b/src/drunc/tests/fsm/actions/test_file_logbook.py new file mode 100644 index 00000000..e69de29b diff --git a/src/drunc/tests/fsm/actions/test_file_run_registry.py b/src/drunc/tests/fsm/actions/test_file_run_registry.py new file mode 100644 index 00000000..e69de29b diff --git a/src/drunc/tests/fsm/actions/test_some_test_action.py b/src/drunc/tests/fsm/actions/test_some_test_action.py new file mode 100644 index 00000000..e69de29b diff --git a/src/drunc/tests/fsm/actions/test_thread_pinning.py b/src/drunc/tests/fsm/actions/test_thread_pinning.py new file mode 100644 index 00000000..e69de29b diff --git a/src/drunc/tests/fsm/actions/test_trigger_rate_specifier.py b/src/drunc/tests/fsm/actions/test_trigger_rate_specifier.py new file mode 100644 index 00000000..e69de29b diff --git a/src/drunc/tests/fsm/actions/test_user_provided_run_number.py b/src/drunc/tests/fsm/actions/test_user_provided_run_number.py new file mode 100644 index 00000000..e69de29b diff --git a/src/drunc/tests/fsm/actions/test_usvc_elisa_logbook.py b/src/drunc/tests/fsm/actions/test_usvc_elisa_logbook.py new file mode 100644 index 00000000..e69de29b diff --git a/src/drunc/tests/fsm/actions/test_usvc_provided_run_number.py b/src/drunc/tests/fsm/actions/test_usvc_provided_run_number.py new file mode 100644 index 00000000..e69de29b diff --git a/src/drunc/tests/fsm/actions/test_utils.py b/src/drunc/tests/fsm/actions/test_utils.py new file mode 100644 index 00000000..e69de29b diff --git a/src/drunc/tests/fsm/actions/timing/__init__.py b/src/drunc/tests/fsm/actions/timing/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/src/drunc/tests/fsm/actions/timing/test_master_send_fl_command.py b/src/drunc/tests/fsm/actions/timing/test_master_send_fl_command.py new file mode 100644 index 00000000..e69de29b diff --git a/src/drunc/tests/fsm/test_action_factory.py b/src/drunc/tests/fsm/test_action_factory.py new file mode 100644 index 00000000..e69de29b diff --git a/src/drunc/tests/fsm/test_configuration.py b/src/drunc/tests/fsm/test_configuration.py new file mode 100644 index 00000000..e69de29b diff --git a/src/drunc/tests/fsm/test_core.py b/src/drunc/tests/fsm/test_core.py new file mode 100644 index 00000000..e69de29b diff --git a/src/drunc/tests/fsm/test_exceptions.py b/src/drunc/tests/fsm/test_exceptions.py new file mode 100644 index 00000000..e69de29b diff --git a/src/drunc/tests/fsm/test_transition.py b/src/drunc/tests/fsm/test_transition.py new file mode 100644 index 00000000..e69de29b diff --git a/src/drunc/tests/fsm/test_utils.py b/src/drunc/tests/fsm/test_utils.py new file mode 100644 index 00000000..e69de29b diff --git a/src/drunc/tests/issues/__init__.py b/src/drunc/tests/issues/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/src/drunc/tests/issues/issue_fixtures.py b/src/drunc/tests/issues/issue_fixtures.py new file mode 100644 index 00000000..ecb2b260 --- /dev/null +++ b/src/drunc/tests/issues/issue_fixtures.py @@ -0,0 +1,14 @@ +import pytest +import os +from pathlib import Path + +@pytest.fixture +def load_test_config(): + DUNEDAQ_DB_PATH = os.getenv("DUNEDAQ_DB_PATH") + if DUNEDAQ_DB_PATH is None: + DUNEDAQ_DB_PATH = '' + cwd = Path(os.path.abspath(__file__)) + test_configs = cwd.parent / ".." / ".." / ".." / ".." / "config" / "tests" + test_configs = test_configs.resolve() + DUNEDAQ_DB_PATH += f":{str(test_configs)}" + os.environ["DUNEDAQ_DB_PATH"] = DUNEDAQ_DB_PATH \ No newline at end of file diff --git a/src/drunc/tests/issues/test_issue309.py b/src/drunc/tests/issues/test_issue309.py new file mode 100644 index 00000000..f4f32e05 --- /dev/null +++ b/src/drunc/tests/issues/test_issue309.py @@ -0,0 +1,23 @@ +# https://github.com/DUNE-DAQ/drunc/issues/309 + +from drunc.controller.configuration import ControllerConfHandler +from drunc.tests.issues.issue_fixtures import load_test_config + +def test_issue309(load_test_config): + from drunc.utils.configuration import parse_conf_url, OKSKey + import os + print(f"{os.getenv('DUNEDAQ_DB_PATH')=}") + conf_path, conf_type = parse_conf_url(f'oksconflibs://issue309.data.xml') + controller_id = "controller-3" + controller_configuration = ControllerConfHandler( + type = conf_type, + data = conf_path, + oks_key = OKSKey( + schema_file = 'schema/confmodel/dunedaq.schema.xml', + class_name = "RCApplication", + obj_uid = controller_id, + session = "deep-segments-config", # some of the function for enable/disable require the full dal of the session + ), + ) + + assert(controller_configuration.data.controller.id == controller_id) \ No newline at end of file diff --git a/src/drunc/tests/process_manager/__init__.py b/src/drunc/tests/process_manager/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/src/drunc/tests/process_manager/interface/__init__.py b/src/drunc/tests/process_manager/interface/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/src/drunc/tests/process_manager/interface/test_cli_argument.py b/src/drunc/tests/process_manager/interface/test_cli_argument.py new file mode 100644 index 00000000..e69de29b diff --git a/src/drunc/tests/process_manager/interface/test_commands.py b/src/drunc/tests/process_manager/interface/test_commands.py new file mode 100644 index 00000000..e69de29b diff --git a/src/drunc/tests/process_manager/interface/test_context.py b/src/drunc/tests/process_manager/interface/test_context.py new file mode 100644 index 00000000..e69de29b diff --git a/src/drunc/tests/process_manager/interface/test_process_manager.py b/src/drunc/tests/process_manager/interface/test_process_manager.py new file mode 100644 index 00000000..e69de29b diff --git a/src/drunc/tests/process_manager/interface/test_shell.py b/src/drunc/tests/process_manager/interface/test_shell.py new file mode 100644 index 00000000..e69de29b diff --git a/src/drunc/tests/process_manager/test_boot_json_parser.py b/src/drunc/tests/process_manager/test_boot_json_parser.py new file mode 100644 index 00000000..e69de29b diff --git a/src/drunc/tests/process_manager/test_configuration.py b/src/drunc/tests/process_manager/test_configuration.py new file mode 100644 index 00000000..e69de29b diff --git a/src/drunc/tests/process_manager/test_exceptions.py b/src/drunc/tests/process_manager/test_exceptions.py new file mode 100644 index 00000000..e69de29b diff --git a/src/drunc/tests/process_manager/test_k8s_process_manager.py b/src/drunc/tests/process_manager/test_k8s_process_manager.py new file mode 100644 index 00000000..e69de29b diff --git a/src/drunc/tests/process_manager/test_oks_parser.py b/src/drunc/tests/process_manager/test_oks_parser.py new file mode 100644 index 00000000..e69de29b diff --git a/src/drunc/tests/process_manager/test_process_manager.py b/src/drunc/tests/process_manager/test_process_manager.py new file mode 100644 index 00000000..e69de29b diff --git a/src/drunc/tests/process_manager/test_process_manager_driver.py b/src/drunc/tests/process_manager/test_process_manager_driver.py new file mode 100644 index 00000000..e69de29b diff --git a/src/drunc/tests/process_manager/test_ssh_process_manager.py b/src/drunc/tests/process_manager/test_ssh_process_manager.py new file mode 100644 index 00000000..e69de29b diff --git a/src/drunc/tests/process_manager/test_utils.py b/src/drunc/tests/process_manager/test_utils.py new file mode 100644 index 00000000..e69de29b diff --git a/src/drunc/tests/test_exceptions.py b/src/drunc/tests/test_exceptions.py new file mode 100644 index 00000000..e69de29b diff --git a/src/drunc/tests/test_fsm.py b/src/drunc/tests/test_fsm.py deleted file mode 100644 index 48842e45..00000000 --- a/src/drunc/tests/test_fsm.py +++ /dev/null @@ -1,62 +0,0 @@ -import pytest -import os -import json -from .fake_controller import FakeController - -#Some command sequences for the controller to run -fsm_loop = ["boot", "conf", "start", "enable_triggers", "disable_triggers", - "drain_dataflow", "stop_trigger_sources", "stop", "scrap", "terminate"] -repeat = ["boot", "terminate", "boot", "terminate", "boot", "terminate", "boot", "terminate", "boot", "terminate"] -sequences = ["boot", "start_run", "stop_run", "shutdown"] -#A list of config files that the test should be run on -filelist = ["fsm_configuration", "no_interfaces"] - -#Sets of arguments are defined here to avoid repetition -argsets = { - "no_args": {"tr": {}}, - "fsm_conf": {"tr": {"a_number":77}, "pre_test-interface": {}}, - "noint_conf": {"tr": {"a_number":77}}, - "fsm_start": {"tr": {}, "post_run-number": {}, "post_logbook": {"message": "hello!"}}, - "fsm_stop": {"tr": {}, "post_logbook": {}} -} - -path = os.path.join(os.environ['DRUNC_DIR'], 'data', 'fsm') -args_filepath = path + '/fsm_test_args.json' -f = open(args_filepath, 'r') -all_args_data = json.loads(f.read()) -f.close() - -@pytest.fixture(params = filelist) -def make_controller(request): - '''Generate a controller for each config provided.''' - conf_filename = f"{request.param}.json" - conf_filepath = path + '/' + conf_filename - f = open(conf_filepath, 'r') - config = json.loads(f.read()) - f.close() - return FakeController(config), request.param - -@pytest.fixture(params = [fsm_loop, repeat, sequences]) -def run_commands(make_controller, request): - err_list = [] - controller = make_controller[0] - this_conf = make_controller[1] - config_args_data = all_args_data[this_conf] - for cmd in request.param: - try: - if cmd in config_args_data: - to_send = config_args_data[cmd] - if type(to_send) == str: #If the value for the listed command is a string... - controller.do_command(cmd, argsets[to_send]) #...send the relevent data. - else: #Otherwise, it must be a sequence. - #Take the dict and replace the names of the argsets with the actual values. - sequence_data = {k:argsets[v] for (k,v) in to_send.items()} - controller.do_command(cmd, sequence_data) - else: - controller.do_command(cmd, argsets['no_args']) - except Exception as e: - err_list.append(e) - return err_list - -def test_runtime(run_commands): - assert run_commands == [] \ No newline at end of file diff --git a/src/drunc/tests/test_k8s_exceptions.py b/src/drunc/tests/test_k8s_exceptions.py new file mode 100644 index 00000000..e69de29b diff --git a/src/drunc/tests/unified_shell/__init__.py b/src/drunc/tests/unified_shell/__init__.py new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/src/drunc/tests/unified_shell/__init__.py @@ -0,0 +1 @@ + diff --git a/src/drunc/tests/unified_shell/test_commands.py b/src/drunc/tests/unified_shell/test_commands.py new file mode 100644 index 00000000..e69de29b diff --git a/src/drunc/tests/unified_shell/test_context.py b/src/drunc/tests/unified_shell/test_context.py new file mode 100644 index 00000000..e69de29b diff --git a/src/drunc/tests/unified_shell/test_shell.py b/src/drunc/tests/unified_shell/test_shell.py new file mode 100644 index 00000000..e69de29b diff --git a/src/drunc/tests/utils/__init__.py b/src/drunc/tests/utils/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/src/drunc/tests/utils/test_configuration.py b/src/drunc/tests/utils/test_configuration.py new file mode 100644 index 00000000..e69de29b diff --git a/src/drunc/tests/utils/test_flask_manager.py b/src/drunc/tests/utils/test_flask_manager.py new file mode 100644 index 00000000..e69de29b diff --git a/src/drunc/tests/utils/test_grpc_utils.py b/src/drunc/tests/utils/test_grpc_utils.py new file mode 100644 index 00000000..e69de29b diff --git a/src/drunc/tests/utils/test_shell_utils.py b/src/drunc/tests/utils/test_shell_utils.py new file mode 100644 index 00000000..e69de29b diff --git a/src/drunc/tests/utils/test_utils.py b/src/drunc/tests/utils/test_utils.py new file mode 100644 index 00000000..f40cebac --- /dev/null +++ b/src/drunc/tests/utils/test_utils.py @@ -0,0 +1,364 @@ +import pytest + + +def test_get_random_string(): + from drunc.utils.utils import get_random_string + string = get_random_string(8) + + # Check that the string is a string + assert isinstance(string, str) + + # Check that the string is of the correct length + assert len(string) == 8 + + # Check that the string is random + string2 = get_random_string(8) + assert string != string2 + + +def test_regex_match(): + from drunc.utils.utils import regex_match + assert regex_match(".*", "absc") + assert regex_match(".*", "1234") + assert regex_match("123.", "1234") + + +def test_print_traceback(capsys): + from drunc.utils.utils import print_traceback + try: + raise ValueError("Test error") + except ValueError as e: + print_traceback() + captured = capsys.readouterr() + assert "ValueError" in captured.out + assert "Test error" in captured.out + + +@pytest.mark.xfail ## I don't understand why this one doesn't work??? +def test_update_log_level(capsys): + from drunc.utils.utils import update_log_level + import logging + update_log_level("DEBUG") + assert logging.getLogger().getEffectiveLevel() == logging.DEBUG + assert logging.getLogger("tester0").getEffectiveLevel() == logging.DEBUG + + update_log_level("INFO") + assert logging.getLogger().getEffectiveLevel() == logging.INFO + assert logging.getLogger("tester1").getEffectiveLevel() == logging.INFO + + update_log_level("WARNING") + assert logging.getLogger().getEffectiveLevel() == logging.WARNING + assert logging.getLogger("tester2").getEffectiveLevel() == logging.WARNING + + update_log_level("ERROR") + assert logging.getLogger().getEffectiveLevel() == logging.ERROR + assert logging.getLogger("tester3").getEffectiveLevel() == logging.ERROR + + update_log_level("CRITICAL") + assert logging.getLogger().getEffectiveLevel() == logging.CRITICAL + assert logging.getLogger("tester4").getEffectiveLevel() == logging.CRITICAL + + logger = logging.getLogger("tester5") + logger.debug ("invisible") + logger.info ("invisible") + logger.warning ("invisible") + logger.error ("invisible") + logger.critical("VISIBLE") + captured = capsys.readouterr() + assert "VISIBLE" in captured.out + assert "invisible" not in captured.out + + +def test_get_new_port(): + from drunc.utils.utils import get_new_port + port = get_new_port() + + # Check that the port is free + import socket + with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: + assert s.connect_ex(('localhost', port)) != 0 + + # Check that the port is an integer + assert isinstance(port, int) + + # Check the range of the port + assert port > 0 + assert port < 65535 + + +def test_run_coroutine(): + from drunc.utils.utils import run_coroutine + import asyncio + + @run_coroutine + async def test_this_coroutine(val): + return val + + result = test_this_coroutine('abc') + + assert result == 'abc' + + +@pytest.mark.xfail +def test_interrupt_run_coroutine(capsys): + # if __name__ == "__main__": + from drunc.utils.utils import run_coroutine + import asyncio + + @run_coroutine + async def test_this_coroutine(val): + await asyncio.sleep(1) + print(val) + return val + + from threading import Thread + from multiprocessing import Process + import signal + import os + pid = os.getpid() + + process = Thread(target=test_this_coroutine, kwargs={"val":'abcdef'}) + # process = Process(target=test_this_coroutine, kwargs={"val":'abcdef'}) + process.start() + # pid = process.pid + # os.kill(pid, signal.SIGINT) + + captured = capsys.readouterr() + assert "Command cancelled" in captured.out + + +def test_now_str(): + from drunc.utils.utils import now_str + now = now_str() + # not much to check here, other than it just being a string + assert isinstance(now, str) + + now = now_str(posix_friendly=True) + # Check that the string is in the correct format and don't contain any annoying characters + assert isinstance(now, str) + assert ":" not in now + assert "," not in now + assert " " not in now + assert "\n" not in now + + +def test_expand_path(): + from drunc.utils.utils import expand_path + import os + + # Pass a relative path, and check that it behaves correctly + path = expand_path("./", turn_to_abs_path=False) + assert os.path.samefile(path, os.path.normpath("./")) + + path = expand_path("./", turn_to_abs_path=True) + assert os.path.samefile(path, os.path.abspath("./")) + + # Pass home, the turn_to_abs_path flag should not matter + path = expand_path("~/", turn_to_abs_path=False) + assert os.path.samefile(path, os.path.expanduser("~/")) + + path = expand_path("~/", turn_to_abs_path=True) + assert os.path.samefile(path, os.path.expanduser("~/")) + + # Pass an absolute path, the turn_to_abs_path flag should not matter + path = expand_path("/tmp", turn_to_abs_path=False) + assert os.path.samefile(path, os.path.normpath("/tmp")) + + path = expand_path("/tmp", turn_to_abs_path=False) + assert os.path.samefile(path, os.path.normpath("/tmp")) + + # Pass a path with a variable in it, the turn_to_abs_path flag should not matter + path = expand_path("${HOME}", turn_to_abs_path=False) + assert os.path.samefile(path, os.path.expanduser("~/")) + + path = expand_path("${HOME}", turn_to_abs_path=True) + assert os.path.samefile(path, os.path.expanduser("~/")) + + +def test_validate_command_facility(): +# if True: + from drunc.utils.utils import validate_command_facility + from click import BadParameter + + # Check that the function raises an exception + with pytest.raises(BadParameter): + validate_command_facility(None, None, "test test") + + # with pytest.raises(BadParameter): + # validate_command_facility(None, None, "grpc://mal_formed:123") + + # with pytest.raises(BadParameter): + # validate_command_facility(None, None, "grpc://malformed:abs") + + with pytest.raises(BadParameter): + validate_command_facility(None, None, "grpc://malformed:1234/123") + + with pytest.raises(BadParameter): + validate_command_facility(None, None, "grpccc://malformed:1234") + + ret = validate_command_facility(None, None, "grpc://good:1234") + + assert ret == "good:1234" + + + +def generate_address(text): + return "grpc://" + text + ":1234/whatver" + +def test_resolve_localhost_to_hostname(): + from drunc.utils.utils import resolve_localhost_to_hostname + from socket import gethostbyname, gethostname + hostname = gethostname() + + resolved = resolve_localhost_to_hostname(generate_address("localhost")) + assert resolved == generate_address(hostname) + + resolved = resolve_localhost_to_hostname(generate_address("127.0.0.1")) + assert resolved == generate_address(hostname) + + resolved = resolve_localhost_to_hostname(generate_address("0.1.90.0")) + assert resolved == generate_address(hostname) + + +def test_resolve_localhost_and_127_ip_to_network_ip(): + from drunc.utils.utils import resolve_localhost_and_127_ip_to_network_ip + from socket import gethostbyname, gethostname + this_ip = gethostbyname(gethostname()) + + resolved = resolve_localhost_and_127_ip_to_network_ip(generate_address("localhost")) + assert resolved == generate_address(this_ip) + + resolved = resolve_localhost_and_127_ip_to_network_ip(generate_address("127.0.0.1")) + assert resolved == generate_address(this_ip) + + resolved = resolve_localhost_and_127_ip_to_network_ip(generate_address("0.1.90.0")) + assert resolved == generate_address(this_ip) + + +def test_host_is_local(): + from drunc.utils.utils import host_is_local + from socket import gethostbyname, gethostname + this_ip = gethostbyname(gethostname()) + hostname = gethostname() + + assert host_is_local(hostname) + assert host_is_local("localhost") + assert host_is_local(this_ip) + assert host_is_local("0.1.23.4") + assert host_is_local('127.1.3.6') + assert not host_is_local("google.com") + assert not host_is_local("8.8.8.8") + + +def test_parent_death_pact(): + from drunc.utils.utils import parent_death_pact + from os import fork, getpid, kill, waitpid + from multiprocessing import Process + from time import sleep + + def child_process(): + parent_death_pact() # We're testing this one + child_pid = getpid() + print(f'Child PID: {child_pid}') + sleep(10) + + def parent_process(): + parent_death_pact() # This isn't the one that we are testing + # The purpose for this one is if someone ctrl+C the test, then this process should also die + parent_pid = getpid() + print(f'Parent PID: {parent_pid}') + child_process = Process(target=child_process, name="tester_child_process") + child_process.start() + sleep(10) + + process = Process(target=parent_process, name="tester_parent_process") + process.start() + sleep(0.1) # Let it run for a while... + process.kill() + + # Check that the child process is dead + assert process.is_alive() == False + import psutil + pids = psutil.pids() + child_pid_still_exists = False + for pid in pids: + if psutil.Process(pid).name() == "tester_child_process": + child_pid_still_exists = True + break + + assert not child_pid_still_exists + + +def test_https_or_https_present(): + from drunc.utils.utils import https_or_http_present, IncorrectAddress + assert https_or_http_present("http://google.com") == None + assert https_or_http_present("https://google.com") == None + + with pytest.raises(IncorrectAddress): + https_or_http_present("ftp://google.com") + + with pytest.raises(IncorrectAddress): + https_or_http_present("google.com") + + with pytest.raises(IncorrectAddress): + https_or_http_present("httpss://google.com") + + +@pytest.mark.xfail +def test_http_post(): + raise NotImplementedError() + + +@pytest.mark.xfail +def test_http_get(): + raise NotImplementedError() + + +@pytest.mark.xfail +def test_http_patch(): + raise NotImplementedError() + +@pytest.mark.xfail +def test_http_delete(): + raise NotImplementedError() + +def test_get_control_type_and_uri_from_cli(): + from drunc.utils.utils import get_control_type_and_uri_from_cli, ControlType + from socket import gethostbyname, gethostname + from drunc.exceptions import DruncSetupException + this_address = gethostbyname(gethostname())+":1234" + def generate_cli(control_type, uri): + return [f"{control_type}://{uri}:1234", "--something-else", "--drunc"] + + control_type, uri = get_control_type_and_uri_from_cli(generate_cli("grpc", "localhost")) + assert control_type == ControlType.gRPC + assert uri == this_address + + control_type, uri = get_control_type_and_uri_from_cli(generate_cli("grpc", "0.0.0.0")) + assert control_type == ControlType.gRPC + assert uri == this_address + + control_type, uri = get_control_type_and_uri_from_cli(generate_cli("grpc", "np04-srv-123")) + assert control_type == ControlType.gRPC + assert uri == "np04-srv-123:1234" + + control_type, uri = get_control_type_and_uri_from_cli(generate_cli("rest", "localhost")) + assert control_type == ControlType.REST_API + assert uri == this_address + + control_type, uri = get_control_type_and_uri_from_cli(generate_cli("rest", "0.0.0.0")) + assert control_type == ControlType.REST_API + assert uri == this_address + + control_type, uri = get_control_type_and_uri_from_cli(generate_cli("rest", "np04-srv-123")) + assert control_type == ControlType.REST_API + assert uri == "np04-srv-123:1234" + + with pytest.raises(DruncSetupException): + get_control_type_and_uri_from_cli(generate_cli("restt", "bla")) + + +@pytest.mark.xfail +def test_get_control_type_and_uri_from_connectivity_service(): + raise NotImplementedError() + diff --git a/src/drunc/utils/utils.py b/src/drunc/utils/utils.py index 5ae92666..eb7c3f99 100644 --- a/src/drunc/utils/utils.py +++ b/src/drunc/utils/utils.py @@ -134,6 +134,7 @@ def wrapper(*args, **kwargs): return wrapper + def expand_path(path, turn_to_abs_path=False): from os.path import abspath, expanduser, expandvars if turn_to_abs_path: @@ -161,6 +162,7 @@ def validate_command_facility(ctx, param, value): case _: raise BadParameter(message=f'Command factory for drunc-controller only allows \'grpc\'', ctx=ctx, param=param) + def resolve_localhost_to_hostname(address): from socket import gethostbyname, gethostname hostname = gethostname() @@ -213,10 +215,10 @@ def resolve_localhost_and_127_ip_to_network_ip(address): def host_is_local(host): from socket import gethostname, gethostbyname - if host in ['localhost', '0.0.0.0', gethostname(), gethostbyname(gethostname())]: + if host in ['localhost', gethostname(), gethostbyname(gethostname())]: return True - if host.startswith('127.'): + if host.startswith('127.') or host.startswith('0.'): return True return False diff --git a/tests/test_dummy_authoriser.py b/tests/test_dummy_authoriser.py deleted file mode 100644 index 8eee6842..00000000 --- a/tests/test_dummy_authoriser.py +++ /dev/null @@ -1,16 +0,0 @@ - -def test(): - from drunc.authoriser.dummy_authoriser import DummyAuthoriser - from drunc.communication.controller_pb2 import Token - import random, string - - da = DummyAuthoriser() # should always assert to True for any action - for i in range(10): - tok_str = ''.join(random.choice(string.ascii_letters) for il in range(i+10)) - token = Token(text = tok_str) - - action = ''.join(random.choice(string.ascii_letters) for il in range(i+10)) - - assert da.is_authorised(token, action) - - assert da.authorised_actions(token) == []