diff --git a/.gitignore b/.gitignore index c2a0397..e45c141 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ *.pyc *.pyo *.swp +*.sock build/ dist/ calculate_lib.egg-info/ diff --git a/calculate/commands/commands.py b/calculate/commands/commands.py index d14ac5a..563008f 100644 --- a/calculate/commands/commands.py +++ b/calculate/commands/commands.py @@ -1,14 +1,13 @@ -from types import FunctionType from typing import Union, Callable, List -from calculate.scripts.scripts import Script -from calculate.variables.parameters import Parameters -from calculate.variables.datavars import NamespaceNode, DependenceAPI,\ - DependenceError, VariableNotFoundError -from calculate.variables.loader import Datavars -from calculate.utils.io_module import IOModule +from ..scripts.scripts import Script +from ..parameters.parameters import BaseParameter, Parameters +from ..variables.datavars import NamespaceNode, DependenceAPI,\ + VariableNotFoundError +from ..variables.loader import Datavars +from ..utils.io_module import IOModule -class CommandCreationError(Exception): +class CommandDescriptionError(Exception): '''Исключение кидаемое при наличии ошибок во время создания объекта команды.''' def __init__(self, message: str, command_id: str = '', title: str = ''): @@ -38,103 +37,182 @@ class CommandInitializationError(Exception): class Command: - '''Класс команды, предназначен для хранения информации о команде и привязки ее к модулю ввода/вывода''' - def __init__(self, command_id: str = '', category: str = '', + '''Класс описания команды, предназначен для хранения информации о команде + и создания по данному описанию объекта лаунчера команды.''' + def __init__(self, command_id: str = '', + category: str = '', title: str = '', script: Union[Callable, Script, None] = None, - parameters: Union[Parameters, None] = None, + args: Union[tuple, list] = tuple(), + parameters: Union[List[BaseParameter], None] = None, namespace: Union[str, NamespaceNode, None] = None, - command: str = '', gui: bool = False, + command: str = '', + gui: bool = False, icon: Union[str, List[str]] = '', - setvars: dict = {}, rights: List[str] = []): - self._datavars: Union[Datavars, NamespaceNode, None] = None - + setvars: dict = {}, + rights: List[str] = []): + # Идентификатор команды обязателен. if not command_id: - raise CommandCreationError('command ID is not set') - self._id: str = command_id + raise CommandDescriptionError('command ID is not set') + self.__id: str = command_id # Если собственно команда не была указана, получаем ее из ID. if command: - self._command: str = command + self.__command: str = command else: - self._command: str = f'cl_{self._id}' + self.__command: str = f'cl_{self.__id}' + # Название команды. if not title: - raise CommandCreationError("title is not set", - command_id=command_id) - self._title: str = title + raise CommandDescriptionError("title is not set", + command_id=command_id) + self.__title: str = title + # Категория, к которой относится команда. if not category: - raise CommandCreationError("category is not set", - command_title=title) - self._category: str = category + raise CommandDescriptionError("category is not set", + command_title=title) + self.__category: str = category # Пространство имен относительно которого, будет выполняться скрипт. - self._namespace: Union[str, NamespaceNode, None] = namespace + self.__namespace: Union[str, NamespaceNode, None] = namespace # Параметры, указываемые при вызове этой команды. if parameters is None: - raise CommandCreationError("parameters is not set", - command_title=title) - self._parameters: Parameters = parameters + raise CommandDescriptionError("parameters is not set", + command_title=title) + self.__parameters: List[BaseParameter] = parameters # Скрипт выполняемый при вызове этой команды. if not script: - raise CommandCreationError("script is not set", - command_title=title) - elif isinstance(script, FunctionType): - # Поддержка способа описания скрипта в функции. - self._script: Script = script() - else: - self._script: Script = script + raise CommandDescriptionError("script is not set", + command_title=title) + self.__script: Script = script + + # Аргументы, с которыми будет запущен скрипт. Пока только статичные + # значения. + self.__args = args # Параметр указывающий, должена ли данная команда отображаться в # графическом интерфейсе. - self._gui: bool = gui + self.__gui: bool = gui # Устанавливаем название иконки. - if not icon and self._gui: - raise CommandCreationError("icon is not set", - command_title=title) - self._icon: Union[str, List[str]] = icon + if not icon and self.__gui: + raise CommandDescriptionError("icon is not set", + command_title=title) + self.__icon: Union[str, List[str]] = icon # Словарь с переменными и значениями, которые нужно им присвоить. - self._setvars = setvars + self.__setvars: dict = setvars # Права, необходимые данной команде. + # TODO разобраться с тем, как использовать. if not rights: - raise CommandCreationError("rights is not set", - title=title) - self._rights = rights + raise CommandDescriptionError("rights is not set", + title=title) + self.__rights = rights + + def make_runner(self, datavars: Union[Datavars, NamespaceNode], + output: IOModule): + '''Метод создающий на основе данного описания команды экземпляр раннера. + ''' + return CommandRunner(self, datavars, output) + + # Интерфейс иммутабельного объекта описания команды. + @property + def id(self) -> str: + return self.__id + + @property + def command(self) -> str: + return self.__command + + @property + def title(self) -> str: + return self.__title + + @property + def category(self) -> str: + return self.__category + + @property + def namespace(self) -> str: + return self.__namespace + + @property + def parameters(self) -> str: + return self.__parameters @property def script(self) -> Script: - return self._script + return self.__script - def initialize(self, datavars: Union[Datavars, NamespaceNode], - output: IOModule) -> 'Command': - '''Метод для инициализации всего, что нужно инициализировать в команде. - ''' + @property + def args(self) -> tuple: + return self.__args + + @property + def gui(self) -> bool: + return self.__gui + + @property + def icon(self) -> Union[str, List[str]]: + return self.__icon + + @property + def setvars(self) -> dict: + return self.__setvars + + @property + def rights(self) -> List[str]: + return self.__rights + + def __repr__(self): + return f"" + + +class CommandRunner: + def __init__(self, command: Command, + datavars: Union[Datavars, NamespaceNode], + output: IOModule): + '''Класс инкапулирующий все данные о команде, а также необходимые для + нее параметры, модуль ввода-вывода, переменные и прочее. Предназначен + для конфигурации команды и запуска ее в воркере.''' + self._command = command self._datavars = datavars self._output = output - # Сначала найдем пространство имен. - if self._namespace is not None: - if isinstance(self._namespace, str): - self._namespace = self._find_namespace(self._namespace, - datavars) - + # Ищем пространство имен. + if self._command.namespace is not None: + if isinstance(self._command.namespace, str): + self._namespace = self._find_namespace( + self._command.namespace, + datavars) # Инициализируем параметры. - self._parameters.initialize(datavars) + self._parameters = Parameters(self._datavars) + self._parameters.add(*self._command.parameters) + + # Получаем запускатель скрипта. + self._script_launcher = self._command.script.make_launcher( + output, + datavars, + self._namespace) + # Устанавливаем переменные, если нужно. + if self._command.setvars: + self._set_variables(self._command.setvars, + datavars, self._namespace) - # Инициализируем скрипт. - self._script.initialize(output, datavars, self._namespace) + def run_command(self): + args = self._command.args + self._script_launcher(*args) - # Устанавливаем переменные, если нужно. - if self._setvars: - self._set_variables(self._setvars, datavars, self._namespace) + def set_parameters(self, values: dict): + pass - return self + def get_parameters(self, group: Union[str, None] = None): + '''Метод для установки параметров.''' + pass def _find_namespace(self, namespace_path: str, datavars: Union[Datavars, NamespaceNode] diff --git a/calculate/logging.py b/calculate/logging.py new file mode 100644 index 0000000..64eed3b --- /dev/null +++ b/calculate/logging.py @@ -0,0 +1,22 @@ +from logging import DEBUG + +dictLogConfig = { + "version": 1, + "formatters": { + "form_1": { + "format": + '%(asctime)s %(levelname)s: %(message)s' + } + }, + "handlers": { + "console": { + "class": "logging.StreamHandler", + "formatter": "form_1", + "level": DEBUG + } + }, + "root": { + "handlers": ['console'], + "level": DEBUG + } +} diff --git a/calculate/variables/parameters.py b/calculate/parameters/parameters.py similarity index 97% rename from calculate/variables/parameters.py rename to calculate/parameters/parameters.py index 04faa42..492684e 100644 --- a/calculate/variables/parameters.py +++ b/calculate/parameters/parameters.py @@ -1,10 +1,10 @@ # vim: fileencoding=utf-8 # -from .datavars import DependenceAPI, VariableWrapper, NamespaceNode -from .loader import Datavars +from ..variables.datavars import DependenceAPI, VariableWrapper, NamespaceNode +from ..variables.loader import Datavars from collections import OrderedDict from contextlib import contextmanager -from typing import Tuple, Union +from typing import Tuple, Union, Any class ParameterError(Exception): @@ -541,7 +541,7 @@ class GroupWrapper: class Parameters: '''Класс контейнера параметров.''' - def __init__(self, datavars: Datavars = None, check_order=[]): + def __init__(self, datavars: Datavars, check_order=[]): self._datavars = datavars self._parameters = OrderedDict() self._validation_dict = OrderedDict() @@ -558,24 +558,8 @@ class Parameters: # параметров. self._gui_helpers = {} - self._initialized = False - - def initialize(self, datavars: Union[Datavars, NamespaceNode]): - if not self._initialized: - self._datavars = datavars - if self._parameters: - parameters = self._parameters - self._parameters = OrderedDict() - self._add(parameters) - self._initialized = True - return self - def add(self, *parameters: Tuple[BaseParameter]): '''Метод для добавления некоторой совокупности параметров.''' - if not self._initialized: - self._parameters = [] - self._parameters.extend(parameters) - for parameter in parameters: self.add_parameter(parameter) @@ -671,12 +655,12 @@ class Parameters: self._validation = False self._validation_dict = OrderedDict() - def get_group_parameters(self, group_name): + def get_group_parameters(self, group_name: str): '''Метод для получения списка параметров, относящихся к указанной группе.''' return self._parameters[group_name] - def get_descriptions(self): + def get_descriptions(self) -> dict: '''Метод для получения словаря с описанием параметров.''' output = OrderedDict() for group, parameters in self._parameters.items(): @@ -700,10 +684,10 @@ class Parameters: return output @property - def datavars(self): + def datavars(self) -> Union[Datavars, NamespaceNode]: return self._datavars - def __getitem__(self, name): + def __getitem__(self, name: str) -> Any: for group, parameters in self._parameters.items(): for parameter in parameters: if parameter._name == name or parameter._shortname == name: diff --git a/calculate/scripts/scripts.py b/calculate/scripts/scripts.py index d778929..ea6d32d 100644 --- a/calculate/scripts/scripts.py +++ b/calculate/scripts/scripts.py @@ -3,9 +3,10 @@ import re import inspect from typing import Callable, Any, Union, List, Generator +from calculate.templates.template_processor import DirectoryProcessor from calculate.variables.datavars import DependenceAPI, DependenceError,\ VariableNode, NamespaceNode,\ - HashType, TableType + HashType, TableType, StringType from calculate.variables.loader import Datavars from calculate.utils.io_module import IOModule from collections.abc import Iterable, Mapping @@ -35,79 +36,112 @@ class ConditionError(Exception): class Script: - '''Класс скрипта, собирает задачи, обработчики, блоки и прочее. Принимает - аргументы.''' - def __init__(self, script_id: str, args: List[Any] = [], + '''Класс скрипта, собирает задачи, обработчики, блоки и прочее, хранит их + в себе. Создает экземпляры лаунчеров.''' + def __init__(self, script_id: str, + args: List[Any] = [], success_message: str = None, failed_message: str = None, interrupt_message: str = None): self._id: str = script_id - self._items: List[Union['Task', 'Block', 'Handler', 'Run']] = None + self.__items: List[Union['Task', 'Block', 'Handler', 'Run']] = None + self.__tasks_is_set: bool = False - self._args_names: list = args - self._args_vars: list = [] + self.__args: list = args - self._success_message: str = success_message - self._failed_message: str = failed_message - self._interrupt_message: str = interrupt_message + self.__success_message: str = success_message + self.__failed_message: str = failed_message + self.__interrupt_message: str = interrupt_message - self._output: IOModule = None - self._datavars: Union[Datavars, NamespaceNode] = None - self._namespace: Union[NamespaceNode, None] = None + @property + def id(self) -> str: + return self._id - self._handlers: set = set() - self._initialized: bool = False + @property + def args(self) -> list: + return self.__args + + @property + def items(self) -> list: + return self.__items + + @property + def success_message(self) -> str: + return self.__success_message + + @property + def failed_message(self) -> str: + return self.__failed_message + + @property + def interrupt_message(self) -> str: + return self.__interrupt_message def tasks(self, *items: List[Union['Task', 'Block', 'Handler', 'Run']] ) -> 'Script': '''Метод для указания задач и контейнеров, из которых состоит скрипт. ''' - self._items = items + if self.__tasks_is_set: + raise ScriptError("Script object is immutable.") + + self.__items = items + self.__tasks_is_set = bool(self.__items) return self - def initialize(self, output: IOModule, - datavars: Union[Datavars, NamespaceNode], - namespace: NamespaceNode = None) -> 'Script': + def make_launcher(self, output: IOModule, + datavars: Union[Datavars, NamespaceNode], + namespace: NamespaceNode = None) -> 'ScriptLauncher': + '''Метод для создания экземпляра объекта, для запуска данного + скрипта.''' + return ScriptLauncher(self, output, datavars, namespace) + + +class ScriptLauncher: + def __init__(self, script: Script, + output: IOModule, + datavars: Union[Datavars, NamespaceNode], + namespace: NamespaceNode): '''Метод для инициализации, состоящей в установке модулей вывода, модуля переменных, текущего пространства имен, а также создании переменных скрипта.''' + self._script = script + self._output = output self._datavars = datavars self._namespace = namespace - if not self._initialized: - self._script_namespace, self._args_vars =\ - self.make_script_variables(self._id, - self._args_names, - self._datavars) - self._initialized = True - return self + self._script_namespace, self._args_vars = self.make_script_variables( + script.id, + script.args, + datavars) def run(self) -> None: '''Метод для запуска задач, содержащихся в данном скрипте.''' essential_error = None - handlers_to_run = [] + founded_handlers = [] + handlers_to_run = set() - for task_item in self._items: + for task_item in self._script.items: if isinstance(task_item, Handler): - if task_item.id in self._handlers: - handlers_to_run.append(task_item) + founded_handlers.append(task_item) elif essential_error is None: try: output = task_item.run(self._output, self._datavars, self._script_namespace, self._namespace) - self._handlers.update(output) + handlers_to_run.update(output) except Exception as error: if isinstance(error, TaskError): - self._handlers.update(error.handlers) + handlers_to_run.update(error.handlers) essential_error = error - for handler in handlers_to_run: + for handler in founded_handlers: + if handler.id not in handlers_to_run: + continue try: - task_item.run(self._output, self._datavars, - self._script_namespace, self._namespace) + handler.run(self._output, self._datavars, + self._script_namespace, self._namespace) except Exception as error: # TODO Разобраться что делать с ошибками в обработчике. self._output.set_error(f"error in handler '{task_item.id}':" @@ -123,7 +157,7 @@ class Script: '''Метод для создания переменных скрипта. Создает пространство имен скрипта и переменных аргументов.''' if 'scripts' not in datavars: - scripts = Script.make_scripts_namespace(datavars) + scripts = ScriptLauncher.make_scripts_namespace(datavars) else: scripts = datavars.scripts @@ -132,11 +166,14 @@ class Script: scripts.add_namespace(current_script) else: current_script = scripts[script_id] - current_script.clear() + # current_script.clear() args_vars = [] for arg in args: - args_vars.append(VariableNode(arg, current_script)) + if arg not in current_script.variables: + args_vars.append(VariableNode(arg, current_script)) + else: + args_vars.append(current_script.variables[arg]) return current_script, args_vars @staticmethod @@ -157,14 +194,15 @@ class Script: def __call__(self, *args): '''Метод для запуска скрипта с аргументами.''' - if len(args) < len(self._args_names): - raise ScriptError((f"script '{self._id}' missing" - f" {len(self._args_names) - len(args)} required" - " arguments: '") + - "', '".join(self._args_names[len(args):]) + "'") - elif len(args) > len(self._args_names): - raise ScriptError(f"script '{self._id}' takes" - f" {len(self._args_names)} arguments, but" + if len(args) < len(self._script.args): + raise ScriptError( + (f"script '{self._script.id}' missing" + f" {len(self._script.args) - len(args)} required" + " arguments: '") + + "', '".join(self._script.args[len(args):]) + "'") + elif len(args) > len(self._script.args): + raise ScriptError(f"script '{self._script.id}' takes" + f" {len(self._script.args)} arguments, but" f" {len(args)} were given") args_values = self._get_args_values(args, self._datavars, @@ -191,10 +229,106 @@ class Script: return args_values +class RunTemplate: + '''Класс запускателя наложения шаблонов.''' + def __init__(self, id: str = '', + action: str = '', + package: str = '', + chroot_path: str = '', + root_path: str = '', + dbpkg: bool = True, + essential: bool = True, + **group_packages): + self._id: str = id + self._action: str = action + self._package: str = package or None + self._chroot_path: str = chroot_path or None + self._root_path: str = root_path or None + + self._dbpkg = dbpkg + self._essential = essential + self._groups: dict = group_packages + + def _initialize(self, output: IOModule, + datavars: Union[Datavars, NamespaceNode]): + # Проверяем наличие идентификатора. + if not self._id: + error_msg = "id is not set for templates runner" + if self._essential: + raise TaskError(error_msg) + else: + output.set_error(error_msg) + return set() + + # Проверяем наличие параметра action, который обязателен. + if not self._action: + error_msg = ("action parameter is not set for templates runner" + f" '{self._id}'") + if self._essential: + raise TaskError(error_msg) + else: + output.set_error(error_msg) + return set() + + # Если установлен chroot_path -- устанавливаем значение соответствующей + # переменной. + if self._chroot_path is not None: + if 'cl_chroot_path' in datavars.main: + datavars.main['cl_chroot_path'].source = self._chroot_path + else: + VariableNode("cl_chroot_path", datavars.main, + variable_type=StringType, + source=self._chroot_path) + + # Если установлен root_path -- устанавливаем значение соответствующей + # переменной. + if self._root_path is not None: + if 'cl_root_path' in datavars.main: + datavars.main['cl_root_path'].source = self._root_path + else: + VariableNode("cl_root_path", datavars.main, + variable_type=StringType, + source=self._chroot_path) + + if self._groups: + groups = list(self._groups.keys()) + for group, atoms in groups: + if isinstance(atoms, str): + self._groups[group] = [name.strip() for name + in atoms.split(',')] + + def run(self, output: IOModule, + datavars: Union[Datavars, NamespaceNode], + script_namespace: NamespaceNode, + namespace: NamespaceNode) -> set: + '''Метод для запуска наложения шаблонов.''' + self._initialize(output, datavars) + template_processor = DirectoryProcessor(self._action, + datavars_module=datavars, + package=self._package, + output_module=output, + dbpkg=self._dbpkg, + **self._groups) + changed_files = template_processor.process_template_directories() + self._create_result_var(script_namespace, + changed_files=changed_files) + return set() + + def _create_result_var(self, script_namespace: NamespaceNode, + changed_files: dict = {}, + skipped: list = []) -> None: + '''Метод для создания переменной задачи, в которую отправляются + результаты вычислений, имеющихся в функции action.''' + VariableNode(self._id, script_namespace, variable_type=HashType, + source={"changed": changed_files, + "skipped": skipped}) + + class Run: '''Класс запускателя скриптов.''' def __init__(self, script: Script, namespace: str = None, - args: List[Any] = [], when: 'Var' = None, + args: List[Any] = [], + when: 'Var' = None, essential: bool = True): self._script: Script = script self._namespace: str = namespace @@ -204,9 +338,11 @@ class Run: self._essential = essential - def run(self, output: IOModule, datavars: Union[Datavars, NamespaceNode], - parent_namespace: NamespaceNode, namespace: NamespaceNode) -> set: - '''Метод для запуска скрипта, указанного имеющегося в запускателе.''' + def run(self, output: IOModule, + datavars: Union[Datavars, NamespaceNode], + parent_namespace: NamespaceNode, + namespace: NamespaceNode) -> set: + '''Метод для запуска скрипта, указанного в запускателе.''' if self._condition is None or self._condition(datavars, namespace, parent_namespace): @@ -222,8 +358,10 @@ class Run: try: # if not self._script._initialized: - self._script.initialize(output, datavars, self._namespace) - self._script(*self._args) + launcher = self._script.make_launcher( + output, datavars, + namespace=self._namespace) + launcher(*self._args) except (ScriptError, TaskError) as error: if self._essential: raise ScriptError(f"essential script '{self._script._id}'" @@ -330,8 +468,6 @@ class Task: else: self._args = self._update_arguments(self._args_sources) - return self - def run(self, output: IOModule, datavars: Union[Datavars, NamespaceNode], script_namespace: NamespaceNode, @@ -664,7 +800,8 @@ class Until(Loop): class Block: '''Класс блока задач.''' - def __init__(self, *tasks: List[Task], when: Union['Var', None] = None, + def __init__(self, *tasks: List[Task], + when: Union['Var', None] = None, loop: Loop = Loop()): self._tasks: List[Task] = tasks self._rescue_tasks: List[Task] = None @@ -736,7 +873,8 @@ class Handler: def id(self) -> str: return self._id - def run(self, output: IOModule, datavars: Union[Datavars, NamespaceNode], + def run(self, output: IOModule, + datavars: Union[Datavars, NamespaceNode], script_namespace: NamespaceNode, namespace: NamespaceNode) -> None: '''Метод для запуска выполнения задач, содержащихся в обработчике.''' diff --git a/calculate/server/server.py b/calculate/server/server.py new file mode 100644 index 0000000..efb530d --- /dev/null +++ b/calculate/server/server.py @@ -0,0 +1,155 @@ +from ..variables.loader import Datavars +from ..commands.commands import Command +from ..logging import dictLogConfig +from logging.config import dictConfig +from logging import getLogger +from typing import Callable +from fastapi import FastAPI +from .worker import Worker +import importlib +import uvicorn +import asyncio +import os + + +# TODO +# 1. Разобраться с описанием команд как ресурсов и со всем, что от них зависит. +# 2. Разобраться с объектами воркеров. И способом их функционирования. + + +class Server: + def __init__(self, socket_path='./input.sock', + datavars_path: str = 'calculate/vars/', + commands_path: str = 'calculate/commands'): + self._app = FastAPI() + self._socket_path = socket_path + self._event_loop = asyncio.get_event_loop() + + # Конфигурируем логгирование. + dictConfig(dictLogConfig) + self._logger = getLogger("main") + self.log_msg = {'DEBUG': self._logger.debug, + 'INFO': self._logger.info, + 'WARNING': self._logger.warning, + 'ERROR': self._logger.error, + 'CRITICAL': self._logger.critical} + + self._datavars = Datavars(variables_path=datavars_path, + logger=self._logger) + + # Словарь описаний команд. + self._commands = self._get_commands_list(commands_path) + + # Словарь CID и экземпляров команд, передаваемых воркерам. + self._commands_instances = {} + + # Словарь WID и экземпляров процессов-воркеров, передаваемых воркерам. + self._workers = {} + + # Соответствие путей обработчикам запросов для HTTP-метода GET. + self._add_routes(self._app.get, + {"/": self._get_root, + "/commands": self._get_commands, + "/commands/{cid}": self._get_command, + "/workers/{wid}": self._get_worker}) + self._add_routes(self._app.post, + {"/commands/{command_id}": self._post_command}) + + def _get_commands_list(self, commands_path: str) -> list: + '''Метод для получения совокупности описаний команд.''' + output = {} + package = ".".join(commands_path.split("/")) + + for entry in os.scandir(commands_path): + if (not entry.name.endswith('.py') + or entry.name in {"commands.py", "__init__.py"}): + continue + module_name = entry.name[:-3] + try: + module = importlib.import_module("{}.{}".format(package, + module_name)) + for obj in dir(module): + if type(module.__getattribute__(obj)) == Command: + command_object = module.__getattribute__(obj) + output[command_object.id] = command_object + except Exception: + continue + return output + + async def _get_root(self) -> dict: + '''Обработчик корневых запросов.''' + return {'msg': 'root msg'} + + async def _get_commands(self) -> dict: + '''Обработчик, отвечающий на запросы списка команд.''' + response = {} + for command_id, command_object in self._commands.items(): + response.update({command_id: {"title": command_object.title, + "category": command_object.category, + "icon": command_object.icon, + "command": command_object.command}}) + return response + + async def _get_command(self, cid: int) -> dict: + '''Обработчик запросов списка команд.''' + if cid not in self._commands_instances: + # TODO добавить какую-то обработку ошибки. + pass + return {'id': cid, + 'name': f'command_{cid}'} + + async def _get_worker(self, wid: int): + '''Тестовый ''' + self._make_worker(wid=wid) + worker = self._workers[wid] + worker.run(None) + await worker.send({"text": "INFO"}) + data = await worker.get() + if data['type'] == 'log': + self.log_msg[data['level']](data['msg']) + return data + + async def _post_command(self, command_id: str) -> int: + if command_id not in self._commands: + # TODO добавить какую-то обработку ошибки. + pass + return + + def _add_routes(self, method: Callable, routes: dict) -> None: + '''Метод для добавления методов.''' + for path, handler in routes.items(): + router = method(path) + router(handler) + + def _make_worker(self, wid: int = None): + '''Метод для создания воркера для команды.''' + worker = Worker(self._event_loop) + if wid is None: + self._workers[wid] = worker + return wid + elif not self._workers: + self._workers[0] = worker + return 0 + else: + wid = max(self._workers.keys()) + 1 + self._workers[wid] = worker + return wid + + def _make_command(self, command_id: str) -> int: + '''Метод для создания команды по ее описанию.''' + command_description = self._commands[command] + + @property + def app(self): + return self._app + + def run(self): + '''Метод для запуска сервера.''' + # Выгружаем список команд. + uvicorn.run(self._app, + uds=self._socket_path) + + +if __name__ == '__main__': + server = Server() + server.run() diff --git a/calculate/server/worker.py b/calculate/server/worker.py new file mode 100644 index 0000000..449d2f4 --- /dev/null +++ b/calculate/server/worker.py @@ -0,0 +1,38 @@ +from multiprocessing import Queue, Process +# from time import sleep + + +class Worker: + def __init__(self, loop): + self._output_queue = Queue() + self._in_queue = Queue() + self._event_loop = loop + + async def send(self, data: dict): + self._in_queue.put(data) + + async def get(self): + data = await self._event_loop.run_in_executor(None, self._get_output, + self._output_queue) + return data + + @staticmethod + def _get_output(output_queue: Queue) -> dict: + return output_queue.get() + + @staticmethod + def _main_loop(command, in_queue: Queue, out_queue: Queue): + data = in_queue.get() + print('\nworker for command:', command) + output = {"type": "log", + "level": "INFO", + "msg": f"recieved message {data['text']}"} + out_queue.put(output) + + def run(self, command): + '''Метод для запуска процесса воркера с заданным ''' + worker_process = Process(target=self._main_loop, + args=(command, + self._in_queue, + self._output_queue)) + worker_process.start() diff --git a/calculate/templates/template_engine.py b/calculate/templates/template_engine.py index 033b950..b873313 100644 --- a/calculate/templates/template_engine.py +++ b/calculate/templates/template_engine.py @@ -429,8 +429,6 @@ class ParametersProcessor: real_path = parameter_value # Ставим True, чтобы потом проверить этот параметр в postparse - print(f'source value {parameter_value}') - print(f'source <- {real_path}') if not os.path.exists(real_path): return True @@ -592,10 +590,6 @@ class ParametersProcessor: else: groups = self._parameters_container.group - print(f'PACKAGE: {parameter_value}') - print(f'PARSED: {package_atom}') - print(f'GROUPS: {groups}') - print(f'UNINSTALL: {self._groups.get("uninstall", None)}') for group in groups: if group == 'install': try: @@ -610,7 +604,6 @@ class ParametersProcessor: self._parameters_container.remove_parameter('package') return - print('check failed') raise ConditionFailed(f"package '{parameter_value}'" " does not match the template condition", self.lineno) @@ -623,8 +616,6 @@ class ParametersProcessor: if package[parameter] is not None: if (group_package[parameter] is None or group_package[parameter] != package[parameter]): - print(f'{group_package[parameter]} !=' - f' {package[parameter]}') break else: if package['use_flags'] is not None: diff --git a/calculate/templates/template_processor.py b/calculate/templates/template_processor.py index b815fc7..e299fad 100644 --- a/calculate/templates/template_processor.py +++ b/calculate/templates/template_processor.py @@ -719,8 +719,6 @@ class TemplateExecutor: self.executor_output = {'target_path': None, 'stdout': None, 'stderr': None} - print('TARGET PATH:', target_path) - if parameters.append == 'skip': return self.executor_output @@ -1762,7 +1760,8 @@ class DirectoryTree: class DirectoryProcessor: '''Класс обработчика директорий шаблонов.''' def __init__(self, action: str, datavars_module=Variables(), package='', - output_module=IOModule(), dbpkg=True, **groups): + output_module=IOModule(), dbpkg=True, + namespace: NamespaceNode = None, **groups): if isinstance(action, list): self.action = action else: @@ -1781,7 +1780,6 @@ class DirectoryProcessor: if 'cl_root_path' in datavars_module.main: self.templates_root = join_paths(self.cl_chroot_path, datavars_module.main.cl_root_path) - print('ROOT PATH:', self.templates_root) else: self.templates_root = self.cl_chroot_path @@ -1826,7 +1824,11 @@ class DirectoryProcessor: # Разбираем atom имена пакетов, указанных для групп пакетов. if groups: for group_name, package_name in groups.items(): - self._add_package_to_group(group_name, package_name) + if isinstance(package_name, list): + for atom in package_name: + self._add_package_to_group(group_name, atom) + else: + self._add_package_to_group(group_name, package_name) # Инициализируем шаблонизатор. self.template_engine = TemplateEngine( @@ -1998,6 +2000,7 @@ class DirectoryProcessor: self._run_exec_files() self.template_executor.save_changes() + return self.template_executor.changed_files def _execute_handlers(self): '''Метод для запуска обработчиков добавленных в очередь обработчиков @@ -2159,7 +2162,6 @@ class DirectoryProcessor: необходимости, заполнения деревьев директорий шаблонов, с помощью которых далее выполняются шаблоны пакетов из merge.''' directory_name = os.path.basename(current_directory_path) - print('CURRENT TARGET PATH =', current_target_path) # Если включено заполнение дерева создаем пустой словарь для сбора # содержимого текущей директории. diff --git a/calculate/variables/loader.py b/calculate/variables/loader.py index 29d9ae0..93e317a 100644 --- a/calculate/variables/loader.py +++ b/calculate/variables/loader.py @@ -1,6 +1,7 @@ # vim: fileencoding=utf-8 # import os +import logging import importlib import importlib.util from jinja2 import Environment, FileSystemLoader @@ -12,7 +13,6 @@ from calculate.variables.datavars import NamespaceNode, VariableNode,\ from calculate.utils.gentoo import ProfileWalker from calculate.utils.files import read_file, FilesError from calculate.utils.tools import Singleton -from calculate.utils.io_module import IOModule from pyparsing import Literal, Word, ZeroOrMore, Group, Optional, restOfLine,\ empty, printables, OneOrMore, lineno, line, SkipTo,\ LineEnd, Combine, nums @@ -489,7 +489,7 @@ class VariableLoader: def __init__(self, datavars, variables_path, repository_map=None): self.datavars = datavars - self.output = datavars.output + self.logger = datavars.logger self.ini_filler = NamespaceIniFiller() self.variables_path = variables_path @@ -519,9 +519,9 @@ class VariableLoader: if section in current_namespace: current_namespace = current_namespace[section] else: - self.output.set_error("Variable 'os.gentoo.repositories'" - " is not found. Can not load profile" - " variables.") + self.logger.error("Variable 'os.gentoo.repositories'" + " is not found. Can not load profile" + " variables.") return self.repository_map = self._get_repository_map(self.datavars) @@ -530,12 +530,12 @@ class VariableLoader: 'path' in self.datavars.os.gentoo.profile): profile_path = self.datavars.os.gentoo.profile.path else: - self.output.set_error("Variable 'os.gentoo.profile.path'" - " is not found. Can not load profile" - " variables.") + self.logger.error("Variable 'os.gentoo.profile.path'" + " is not found. Can not load profile" + " variables.") return - self.output.set_info("Load variables from profile: '{}'.".format( + self.logger.info("Load variables from profile: '{}'.".format( profile_path)) self._fill_from_profile_ini(profile_path) @@ -546,20 +546,20 @@ class VariableLoader: env_order = self.datavars.system.env_order env_path = self.datavars.system.env_path except VariableNotFoundError as error: - self.output.set_warning("Can not load additional variables: {}". - format(str(error))) + self.logger.warning("Can not load additional variables: {}". + format(str(error))) return for ini_file in env_order: - self.output.set_info("Loading variables from file: '{}'".format( + self.logger.info("Loading variables from file: '{}'".format( ini_file)) if ini_file in env_path: self.fill_from_custom_ini(env_path[ini_file].value) - self.output.set_success("Variables from '{}' are loaded". - format(ini_file)) + self.logger.info("Variables from '{}' are loaded".format( + ini_file)) else: - self.output.set_warning("File '{}' is not found. Variables are" - " not loaded".format(ini_file)) + self.logger.warning("File '{}' is not found. Variables are" + " not loaded".format(ini_file)) def _fill_from_package(self, current_namespace: NamespaceNode, directory_path: str, package: str) -> None: @@ -575,6 +575,8 @@ class VariableLoader: # Сначала загружаем переменные из файлов. for file_node in file_nodes: + if not file_node.name.endswith('.py'): + continue file_name = file_node.name[:-3] Namespace.set_current_namespace(current_namespace) # with self.test(file_name, current_namespace): @@ -603,8 +605,8 @@ class VariableLoader: ini_file_text = read_file(file_path) self.ini_filler.fill(self.datavars, ini_file_text) except FilesError: - self.output.set_error("Can not load profile variables from" - " unexisting file: {}".format(file_path)) + self.logger.error("Can not load profile variables from" + " unexisting file: {}".format(file_path)) def _get_repository_map(self, datavars): '''Метод для получения из переменной словаря с репозиториями и путями @@ -621,13 +623,13 @@ class VariableLoader: parsing_errors = self.ini_filler.errors if parsing_errors: for error in parsing_errors: - self.output.set_error(error) - self.output.set_warning('Some variables was not loaded.') + self.logger.error(error) + self.logger.warning('Some variables was not loaded.') else: - self.output.set_success('All variables are loaded.') + self.logger.info('All variables are loaded.') else: - self.output.set_error("Variables are not loaded. File '{}' does" - " not exist.".format(file_path)) + self.logger.error("Variables are not loaded. File '{}' does" + " not exist.".format(file_path)) @contextmanager def test(self, file_name, namespace): @@ -704,10 +706,16 @@ class CalculateIniSaver: class Datavars: '''Класс для хранения переменных и управления ими.''' def __init__(self, variables_path='calculate/vars', repository_map=None, - io_module=IOModule()): + logger=None): self._variables_path = variables_path self._available_packages = self._get_available_packages() - self.output = io_module + if logger is not None: + self.logger = logger + else: + logger = logging.getLogger("main") + # stream_handler = logging.StreamHandler() + # logger.addHandler(stream_handler) + self.logger = logger self.root = NamespaceNode('') self._loader = VariableLoader(self, self._variables_path, @@ -749,8 +757,7 @@ class Datavars: def _load_package(self, package_name): '''Метод для загрузки переменных содержащихся в указанном пакете.''' - self.output.set_info("Loading datavars package '{}'".format( - package_name)) + self.logger.info("Loading datavars package '{}'".format(package_name)) try: self._loader.load_variables_package(package_name) except Exception as error: @@ -843,5 +850,5 @@ class Datavars: dict_to_save = self.variables_to_save[target] target_path = target_paths[target].value saver.save_to_ini(target_path, dict_to_save) - self.output.set_info("Variables for '{}' is saved in the" - " file: {}".format(target, target_path)) + self.logger.info("Variables for '{}' is saved in the" + " file: {}".format(target, target_path)) diff --git a/client.py b/client.py new file mode 100644 index 0000000..a8ff745 --- /dev/null +++ b/client.py @@ -0,0 +1,33 @@ +import asyncio +import aiohttp + + +async def get_root(client): + async with client.get('http://localhost/') as resp: + assert resp.status == 200 + return await resp.json() + + +async def main(): + unix_conn = aiohttp.UnixConnector(path='./input.sock') + + try: + async with aiohttp.ClientSession(connector=unix_conn) as client: + print('---------------------------') + print('Request GET "/" HTTP/1.1:') + response = await get_root(client) + print(f'Response: {response}') + print('---------------------------') + except KeyboardInterrupt: + raise + finally: + print('\nClosing connection...') + await unix_conn.close() + + +if __name__ == '__main__': + loop = asyncio.new_event_loop() + try: + loop.run_until_complete(main()) + except KeyboardInterrupt: + loop.close() diff --git a/pytest.ini b/pytest.ini index 90cd471..57ba61c 100644 --- a/pytest.ini +++ b/pytest.ini @@ -36,5 +36,6 @@ markers = vars: marker for testing of the datavars module. parameters: marker for testing of the parameters module. - tasks: marker for testing of the tasks. + scripts: marker for testing of the scripts. commands: marker for testing of the commands. + server: marker for testing of the server. diff --git a/run_server.py b/run_server.py new file mode 100644 index 0000000..f9850b8 --- /dev/null +++ b/run_server.py @@ -0,0 +1,6 @@ +from calculate.server.server import Server + + +if __name__ == "__main__": + server = Server() + server.run() diff --git a/run_templates.py b/run_templates.py index 859d415..dd788ed 100644 --- a/run_templates.py +++ b/run_templates.py @@ -40,7 +40,8 @@ def main(): datavars_module=datavars, package=package, output_module=io_module, - dbpkg=args.dbpkg) + dbpkg=args.dbpkg, + **group_packages) template_processor.process_template_directories() diff --git a/tests/commands/parameters.py b/tests/commands/parameters.py new file mode 100644 index 0000000..703e657 --- /dev/null +++ b/tests/commands/parameters.py @@ -0,0 +1,39 @@ +from calculate.parameters.parameters import BaseParameter, Integer,\ + String, ValidationError + + +class MyShinyParameter(BaseParameter): + type = Integer() + + def validate(self, var): + if var.value < 10: + raise ValidationError("The value must be greater than 10") + + def bind_method(self, var): + return var.value, None + + +class AnotherParameter(BaseParameter): + type = String() + + def bind_method(self): + return 'default string', None + + def validate(self, value): + if not value.startswith('/var/lib'): + raise ValidationError("The value must starts with a" + " '/var/lib'") + + +class OneMoreParameter(BaseParameter): + type = String() + + def bind_method(self): + return 'default string', None + + def validate(self, value): + available_set = {'mystery', 'horror', 'weird'} + if value not in available_set: + raise ValidationError(f"The value '{value}' is not in" + f" available. Available values:" + f" {', '.join(available_set)}") diff --git a/tests/commands/scripts.py b/tests/commands/scripts.py new file mode 100644 index 0000000..e262b6a --- /dev/null +++ b/tests/commands/scripts.py @@ -0,0 +1,14 @@ +from calculate.scripts.scripts import Script, Task + + +def action(output, arg1: str) -> str: + '''Задача выполняемая скриптом ниже.''' + return f'os.calculate = {arg1}' + + +# Тестовый скрипт. +test_script = Script('test_script' + ).tasks(Task(id='task', + name="Task", + action=action, + args=["os.calculate"])) diff --git a/tests/commands/test_commands.py b/tests/commands/test_commands.py index 7f316ca..f2f5725 100644 --- a/tests/commands/test_commands.py +++ b/tests/commands/test_commands.py @@ -1,14 +1,15 @@ import os import shutil import pytest + from calculate.commands.commands import Command -from calculate.scripts.scripts import Script, Task +from calculate.parameters.parameters import Description from calculate.variables.loader import Datavars -from calculate.variables.parameters import Parameters, BaseParameter, Integer,\ - String, ValidationError,\ - Description from calculate.utils.io_module import IOModule +from .parameters import MyShinyParameter, OneMoreParameter, AnotherParameter +from .scripts import test_script + TESTFILES_PATH = os.path.join(os.getcwd(), 'tests/commands/testfiles') @@ -24,78 +25,37 @@ class TestCommands: datavars = Datavars(variables_path=os.path.join(TESTFILES_PATH, 'variables')) - # Скрипт выполняемый командой. - def action(output: IOModule, arg1: str) -> str: - return f'os.calculate = {arg1}' - - # Для обеспечения многопоточности вероятно придется делать так. - def test_script(): - return Script('test_script' - ).tasks(Task(id='task', - name="Task", - action=action, - args=["os.calculate"]) - ) - - # Параметры данной команды. - test_parameters = Parameters().initialize(datavars) - - class MyShinyParameter(BaseParameter): - type = Integer() - - def validate(self, var): - if var.value < 10: - raise ValidationError("The value must be greater than 10") - - def bind_method(self, var): - return var.value, None - - class AnotherParameter(BaseParameter): - type = String() - - def bind_method(self): - return 'default string', None - - def validate(self, value): - if not value.startswith('/var/lib'): - raise ValidationError("The value must starts with a" - " '/var/lib'") - - class OneMoreParameter(BaseParameter): - type = String() - - def bind_method(self): - return 'default string', None - - def validate(self, value): - available_set = {'mystery', 'horror', 'weird'} - if value not in available_set: - raise ValidationError(f"The value '{value}' is not in" - f" available. Available values:" - f" {', '.join(available_set)}") - - test_parameters.add( - MyShinyParameter('my-shiny', 'The Shiniest ones', - Description( - short='The shiny parameter', - full='The shiniest thing known to science.', - usage='-S COUNT, --my-shiny COUNT'), - shortname='S').bind('os.linux.test_5'), - AnotherParameter('my-other', 'The Others', - Description(short='Not from this world.'), - shortname='o'), - OneMoreParameter('one-more', 'The Others', - Description(full='Plan 9 from outer space.'))) - command = Command(command_id='test', category='Test Category', title='Test', - script=test_script(), - parameters=test_parameters, + script=test_script, namespace='os', - rights=['group']) - command.initialize(datavars, IOModule()) - command.script.run() + rights=['group'], + parameters=[ + MyShinyParameter + ( + 'my-shiny', 'The Shiniest ones', + Description( + short='The shiny parameter', + full='The shiniest thing known to science.', + usage='-S COUNT, --my-shiny COUNT'), + shortname='S' + ).bind('os.linux.test_5'), + AnotherParameter + ( + 'my-other', 'The Others', + Description( + short='Not from this world.'), + shortname='o' + ), + OneMoreParameter + ( + 'one-more', 'The Others', + Description(full='Plan 9 from outer space.') + )]) + + command_runner = command.make_runner(datavars, IOModule()) + command_runner.run_command() assert datavars.scripts.test_script.task.result ==\ 'os.calculate = test1 test2' @@ -104,57 +64,7 @@ class TestCommands: datavars = Datavars(variables_path=os.path.join(TESTFILES_PATH, 'variables')) - # Скрипт выполняемый командой. - def action(output: IOModule, arg1: str) -> str: - return f'os.calculate = {arg1}' - - # Для обеспечения многопоточности вероятно придется делать так. - def test_script(): - return Script('test_script' - ).tasks(Task(id='task', - name="Task", - action=action, - args=["os.calculate"]) - ) - - # Параметры данной команды. - test_parameters = Parameters().initialize(datavars) - - class MyShinyParameter(BaseParameter): - type = Integer() - - def validate(self, var): - if var.value < 10: - raise ValidationError("The value must be greater than 10") - - def bind_method(self, var): - return var.value, None - - class AnotherParameter(BaseParameter): - type = String() - - def bind_method(self): - return 'default string', None - - def validate(self, value): - if not value.startswith('/var/lib'): - raise ValidationError("The value must starts with a" - " '/var/lib'") - - class OneMoreParameter(BaseParameter): - type = String() - - def bind_method(self): - return 'default string', None - - def validate(self, value): - available_set = {'mystery', 'horror', 'weird'} - if value not in available_set: - raise ValidationError(f"The value '{value}' is not in" - f" available. Available values:" - f" {', '.join(available_set)}") - - test_parameters.add( + test_parameters = [ MyShinyParameter('my-shiny', 'The Shiniest ones', Description( short='The shiny parameter', @@ -165,23 +75,24 @@ class TestCommands: Description(short='Not from this world.'), shortname='o'), OneMoreParameter('one-more', 'The Others', - Description(full='Plan 9 from outer space.'))) + Description(full='Plan 9 from outer space.'))] command = Command(command_id='test', category='Test Category', title='Test', - script=test_script(), + script=test_script, parameters=test_parameters, namespace='os', gui=True, icon=['icon_1', 'icon_2'], - setvars={'os.hashvar_0': {'value1': 'new_1', - 'value2': 'new_2'}, + setvars={'os.hashvar_0': + {'value1': 'new_1', + 'value2': 'new_2'}, '.linux.test_5': 1349}, rights=['install']) - command.initialize(datavars, IOModule()) - command.script.run() + command_runner = command.make_runner(datavars, IOModule()) + command_runner.run_command() assert datavars.os.hashvar_0.get_hash() == {'value1': 'new_1', 'value2': 'new_2'} diff --git a/tests/parameters/__init__.py b/tests/parameters/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/variables/test_parameters.py b/tests/parameters/test_parameters.py similarity index 96% rename from tests/variables/test_parameters.py rename to tests/parameters/test_parameters.py index dc67153..8a9cfc7 100644 --- a/tests/variables/test_parameters.py +++ b/tests/parameters/test_parameters.py @@ -2,29 +2,29 @@ import os import shutil import pytest from collections import OrderedDict -from calculate.variables.parameters import BaseParameter, Integer, String,\ - Description, Parameters,\ - ValidationError, Choice, Bool,\ - List, CyclicValidationError,\ - ParameterError, Table, TableValue +from calculate.parameters.parameters import BaseParameter, Integer, String,\ + Description, Parameters,\ + ValidationError, Choice, Bool,\ + List, CyclicValidationError,\ + ParameterError, Table, TableValue from calculate.variables.loader import Datavars -TESTFILES_PATH = os.path.join(os.getcwd(), 'tests/variables/testfiles') +TESTFILES_PATH = os.path.join(os.getcwd(), 'tests/parameters/testfiles') +GENTOO_PATH = os.path.join(TESTFILES_PATH, 'gentoo') @pytest.mark.parameters class TestParameters: def test_to_make_testfiles(self): shutil.copytree(os.path.join(TESTFILES_PATH, 'gentoo.backup'), - os.path.join(TESTFILES_PATH, 'gentoo'), - symlinks=True) + os.path.join(TESTFILES_PATH, 'gentoo'), symlinks=True) def test_if_some_parameters_are_created_using_classes_inheriting_the_BaseParameter_class_and_its_types_is_set_in_the_parameter_s_classes__the_parameters_can_be_created_using_this_classes_and_their_instances_types_are_types_from_their_classes(self): datavars = Datavars(variables_path=os.path.join(TESTFILES_PATH, - 'variables_17')) + 'variables')) - PARAMS = Parameters().initialize(datavars) + PARAMS = Parameters(datavars) # Описание классов параметров. class MyShinyParameter(BaseParameter): @@ -75,6 +75,17 @@ class TestParameters: OneMoreParameter('one-more', 'The Others', Description(full='Plan 9 from outer space.'))) + class AnotherParameter(BaseParameter): + type = String() + + def bind_method(self): + return 'default string', None + + def validate(self, value): + if not value.startswith('/var/lib'): + raise ValidationError("The value must starts with a" + " '/var/lib'") + shiny_one, another_one, weird_one = PARAMS shiny_one.set(9) @@ -88,9 +99,9 @@ class TestParameters: def test_if_parameter_is_created_with_bind_method_with_a_variable_in_its_arguments__the_default_parameter_value_is_calculated_using_this_method_and_a_variable_from_arguments_can_invalidate_the_parameter(self): datavars = Datavars(variables_path=os.path.join(TESTFILES_PATH, - 'variables_17')) + 'variables')) - PARAMS = Parameters().initialize(datavars) + PARAMS = Parameters(datavars) # Описание классов параметров. class TestParameter(BaseParameter): @@ -120,9 +131,9 @@ class TestParameters: def test_if_bind_method_is_set_for_parameter_and_then_the_set_method_is_used_to_change_value__the_parameters_value_is_changed_and_a_variable_from_a_bounded_variable_is_not_able_to_invalidate_parameter_s_value(self): datavars = Datavars(variables_path=os.path.join(TESTFILES_PATH, - 'variables_17')) + 'variables')) - PARAMS = Parameters().initialize(datavars) + PARAMS = Parameters(datavars) # Описание классов параметров. class TestParameter(BaseParameter): @@ -151,9 +162,9 @@ class TestParameters: def test_if_the_bind_method_is_set_for_two_variables__the_bind_method_calculates_parameter_s_default_value__variables_can_invalidate_parameter_s_value_before_the_set_method_is_used__the_set_parameter_can_change_value_of_the_parameter(self): datavars = Datavars(variables_path=os.path.join(TESTFILES_PATH, - 'variables_17')) + 'variables')) - PARAMS = Parameters().initialize(datavars) + PARAMS = Parameters(datavars) # Описание классов параметров. class TestParameter(BaseParameter): @@ -193,9 +204,9 @@ class TestParameters: def test_if_hash_value_is_in_the_set_variables_list__the_parameter_is_able_to_change_that_hash_s_value(self): datavars = Datavars(variables_path=os.path.join(TESTFILES_PATH, - 'variables_17')) + 'variables')) - PARAMS = Parameters().initialize(datavars) + PARAMS = Parameters(datavars) # Описание классов параметров. class TestParameter(BaseParameter): @@ -227,9 +238,9 @@ class TestParameters: def test_if_bind_method_is_set_for_parameter__the_method_can_return_as_second_value_of_the_return_tuple_disactivity_comment_witch_disactivates_the_parameter_even_if_parameters_values_is_set_by_user(self): datavars = Datavars(variables_path=os.path.join(TESTFILES_PATH, - 'variables_17')) + 'variables')) - PARAMS = Parameters().initialize(datavars) + PARAMS = Parameters(datavars) # Описание классов параметров. class BoolTestParameter(BaseParameter): @@ -282,8 +293,8 @@ class TestParameters: def test_Choice_type_is_set_for_parameter_and_bind_method_is_set_too__the_bind_method_can_define_available_values_for_the_choice_parameter__choice_availables_is_invalidatable_even_if_the_value_is_set_by_user__choice_type_checks_if_the_new_value_is_the_availables_list(self): datavars = Datavars(variables_path=os.path.join(TESTFILES_PATH, - 'variables_17')) - PARAMS = Parameters().initialize(datavars) + 'variables')) + PARAMS = Parameters(datavars) # Описание классов параметров. class TestParameter(BaseParameter): @@ -312,8 +323,8 @@ class TestParameters: def test_if_some_parameters_are_created_with_some_types_and_there_are_attempts_to_assign_some_values_which_type_is_not_correct_to_this_parameters__the_parameters_types_checks_this_values_and_raises_ValidationError_exception(self): datavars = Datavars(variables_path=os.path.join(TESTFILES_PATH, - 'variables_17')) - PARAMS = Parameters().initialize(datavars) + 'variables')) + PARAMS = Parameters(datavars) # Описание классов параметров. class FirstTestParameter(BaseParameter): @@ -365,8 +376,8 @@ class TestParameters: def test_if_some_parameters_is_created_with_the_validate_methods__the_validate_methods_are_used_for_validating_all_values_that_is_set_to_the_parameter(self): datavars = Datavars(variables_path=os.path.join(TESTFILES_PATH, - 'variables_17')) - PARAMS = Parameters().initialize(datavars) + 'variables')) + PARAMS = Parameters(datavars) # Описание классов параметров. class FirstTestParameter(BaseParameter): @@ -456,8 +467,8 @@ class TestParameters: def test_if_some_parameters_are_created_with_validation_methods_that_use_parameters_forming_cyclic_validation_process__the_parameters_throw_the_CyclicValidationError_exception(self): datavars = Datavars(variables_path=os.path.join(TESTFILES_PATH, - 'variables_17')) - PARAMS = Parameters().initialize(datavars) + 'variables')) + PARAMS = Parameters(datavars) # Описание классов параметров. class FirstTestParameter(BaseParameter): @@ -540,8 +551,8 @@ class TestParameters: def test_if_two_parameters_is_created_with_the_bind_methods_and_one_of_them_can_be_disactivated_depending_on_the_variable_and_other_one_can_change_this_variable_s_value__the_second_parameter_can_disactivate_the_first_one_through_variable(self): datavars = Datavars(variables_path=os.path.join(TESTFILES_PATH, - 'variables_17')) - PARAMS = Parameters().initialize(datavars) + 'variables')) + PARAMS = Parameters(datavars) # Описание классов параметров. class FirstTestParameter(BaseParameter): @@ -586,8 +597,8 @@ class TestParameters: def test_if_there_is_an_attempt_to_add_in_the_parameters_container_new_parameter_but_the_container_already_has_parameter_with_the_same_fullname__the_parameters_container_throws_ParameterError_exception(self): datavars = Datavars(variables_path=os.path.join(TESTFILES_PATH, - 'variables_17')) - PARAMS = Parameters().initialize(datavars) + 'variables')) + PARAMS = Parameters(datavars) # Описание классов параметров. class FirstTestParameter(BaseParameter): @@ -617,8 +628,8 @@ class TestParameters: def test_if_there_is_an_attempt_to_add_in_the_parameters_container_new_parameter_but_the_container_already_has_parameter_with_the_same_shortname__the_parameters_container_throws_ParameterError_exception(self): datavars = Datavars(variables_path=os.path.join(TESTFILES_PATH, - 'variables_17')) - PARAMS = Parameters().initialize(datavars) + 'variables')) + PARAMS = Parameters(datavars) # Описание классов параметров. class FirstTestParameter(BaseParameter): @@ -650,8 +661,8 @@ class TestParameters: def test_if_some_parameters_are_created_with_different_argv_values__their_position_number_will_be_saved_in_the_parameters_container(self): datavars = Datavars(variables_path=os.path.join(TESTFILES_PATH, - 'variables_17')) - PARAMS = Parameters().initialize(datavars) + 'variables')) + PARAMS = Parameters(datavars) # Описание классов параметров. class FirstTestParameter(BaseParameter): @@ -695,8 +706,8 @@ class TestParameters: def test_if_there_is_an_attempt_to_add_in_the_parameters_container_new_parameter_but_the_container_already_has_parameter_with_the_same_argv_value__the_parameters_container_throws_ParameterError_exception(self): datavars = Datavars(variables_path=os.path.join(TESTFILES_PATH, - 'variables_17')) - PARAMS = Parameters().initialize(datavars) + 'variables')) + PARAMS = Parameters(datavars) # Описание классов параметров. class FirstTestParameter(BaseParameter): @@ -728,8 +739,8 @@ class TestParameters: def test_if_parameter_is_created_with_the_bind_method__the_bind_method_can_get_access_to_the_current_parameter_value_during_the_value_calculation(self): datavars = Datavars(variables_path=os.path.join(TESTFILES_PATH, - 'variables_17')) - PARAMS = Parameters().initialize(datavars) + 'variables')) + PARAMS = Parameters(datavars) # Описание классов параметров. class FirstTestParameter(BaseParameter): @@ -773,8 +784,8 @@ class TestParameters: def test_if_parameter_is_created_with_table_type_and_bind_method_is_set_for_this_parameter__the_bind_method_can_be_used_for_setting_of_the_table_fields_and_its_types(self): datavars = Datavars(variables_path=os.path.join(TESTFILES_PATH, - 'variables_17')) - PARAMS = Parameters().initialize(datavars) + 'variables')) + PARAMS = Parameters(datavars) # Описание классов параметров. class FirstTestParameter(BaseParameter): @@ -810,8 +821,8 @@ class TestParameters: def test_if_parameter_is_created_with_table_type_and_types_of_its_fields_is_set__this_parameter_uses_this_types_for_invalidating_of_all_fields_values(self): datavars = Datavars(variables_path=os.path.join(TESTFILES_PATH, - 'variables_17')) - PARAMS = Parameters().initialize(datavars) + 'variables')) + PARAMS = Parameters(datavars) # Описание классов параметров. class FirstTestParameter(BaseParameter): @@ -870,8 +881,8 @@ class TestParameters: def test_if_parameter_is_created_with_table_type_and_expandable_flag_is_True__new_rows_can_be_added_to_the_created_table_and_existing_rows_can_be_modified(self): datavars = Datavars(variables_path=os.path.join(TESTFILES_PATH, - 'variables_17')) - PARAMS = Parameters().initialize(datavars) + 'variables')) + PARAMS = Parameters(datavars) # Описание классов параметров. class FirstTestParameter(BaseParameter): @@ -914,8 +925,8 @@ class TestParameters: def test_if_parameter_is_created_with_table_type_and_expandable_flag_is_False__existing_rows_can_be_modified_but_attempt_to_add_new_will_call_set_error_method_that_can_be_set_for_table(self): datavars = Datavars(variables_path=os.path.join(TESTFILES_PATH, - 'variables_17')) - PARAMS = Parameters().initialize(datavars) + 'variables')) + PARAMS = Parameters(datavars) # Описание классов параметров. class FirstTestParameter(BaseParameter): @@ -967,8 +978,8 @@ class TestParameters: def test_if_parameter_is_created_with_table_type_and_to_set_method_is_used_to_add_variables_to_set_value__the_table_parameter_will_set_its_value_to_the_variable_from_set_list(self): datavars = Datavars(variables_path=os.path.join(TESTFILES_PATH, - 'variables_17')) - PARAMS = Parameters().initialize(datavars) + 'variables')) + PARAMS = Parameters(datavars) # Описание классов параметров. class FirstTestParameter(BaseParameter): @@ -1010,8 +1021,8 @@ class TestParameters: def test_if_parameter_is_created_with_table_type_and_fill_method_is_set__the_parameter_will_use_fill_method_to_fill_empty_fields_of_the_table(self): datavars = Datavars(variables_path=os.path.join(TESTFILES_PATH, - 'variables_17')) - PARAMS = Parameters().initialize(datavars) + 'variables')) + PARAMS = Parameters(datavars) # Описание классов параметров. class FirstTestParameter(BaseParameter): diff --git a/tests/parameters/testfiles/gentoo.backup/ini_vars_0.backup b/tests/parameters/testfiles/gentoo.backup/ini_vars_0.backup new file mode 100644 index 0000000..e69de29 diff --git a/tests/parameters/testfiles/gentoo.backup/portage/calculate.ini b/tests/parameters/testfiles/gentoo.backup/portage/calculate.ini new file mode 100644 index 0000000..e69de29 diff --git a/tests/parameters/testfiles/gentoo.backup/portage/profiles/calculate.ini b/tests/parameters/testfiles/gentoo.backup/portage/profiles/calculate.ini new file mode 100644 index 0000000..e69de29 diff --git a/tests/parameters/testfiles/gentoo.backup/portage/profiles/main/calculate.ini b/tests/parameters/testfiles/gentoo.backup/portage/profiles/main/calculate.ini new file mode 100644 index 0000000..e69de29 diff --git a/tests/parameters/testfiles/gentoo.backup/repos/calculate/profiles/calculate.ini b/tests/parameters/testfiles/gentoo.backup/repos/calculate/profiles/calculate.ini new file mode 100644 index 0000000..e69de29 diff --git a/tests/parameters/testfiles/gentoo.backup/repos/calculate/profiles/default/20/calculate.ini b/tests/parameters/testfiles/gentoo.backup/repos/calculate/profiles/default/20/calculate.ini new file mode 100644 index 0000000..e69de29 diff --git a/tests/parameters/testfiles/gentoo.backup/repos/calculate/profiles/default/amd64/20/calculate.ini b/tests/parameters/testfiles/gentoo.backup/repos/calculate/profiles/default/amd64/20/calculate.ini new file mode 100644 index 0000000..e69de29 diff --git a/tests/parameters/testfiles/gentoo.backup/repos/calculate/profiles/default/amd64/20/desktop/calculate.ini b/tests/parameters/testfiles/gentoo.backup/repos/calculate/profiles/default/amd64/20/desktop/calculate.ini new file mode 100644 index 0000000..e69de29 diff --git a/tests/parameters/testfiles/gentoo.backup/repos/calculate/profiles/default/amd64/20/desktop/parent b/tests/parameters/testfiles/gentoo.backup/repos/calculate/profiles/default/amd64/20/desktop/parent new file mode 100644 index 0000000..08bf1a2 --- /dev/null +++ b/tests/parameters/testfiles/gentoo.backup/repos/calculate/profiles/default/amd64/20/desktop/parent @@ -0,0 +1,3 @@ +gentoo:main +.. +../../../desktop diff --git a/tests/parameters/testfiles/gentoo.backup/repos/calculate/profiles/default/amd64/20/parent b/tests/parameters/testfiles/gentoo.backup/repos/calculate/profiles/default/amd64/20/parent new file mode 100644 index 0000000..0c34ef3 --- /dev/null +++ b/tests/parameters/testfiles/gentoo.backup/repos/calculate/profiles/default/amd64/20/parent @@ -0,0 +1,2 @@ +.. +../../20 diff --git a/tests/parameters/testfiles/gentoo.backup/repos/calculate/profiles/default/amd64/calculate.ini b/tests/parameters/testfiles/gentoo.backup/repos/calculate/profiles/default/amd64/calculate.ini new file mode 100644 index 0000000..e69de29 diff --git a/tests/parameters/testfiles/gentoo.backup/repos/calculate/profiles/default/amd64/parent b/tests/parameters/testfiles/gentoo.backup/repos/calculate/profiles/default/amd64/parent new file mode 100644 index 0000000..f3229c5 --- /dev/null +++ b/tests/parameters/testfiles/gentoo.backup/repos/calculate/profiles/default/amd64/parent @@ -0,0 +1 @@ +.. diff --git a/tests/parameters/testfiles/gentoo.backup/repos/calculate/profiles/default/calculate.ini b/tests/parameters/testfiles/gentoo.backup/repos/calculate/profiles/default/calculate.ini new file mode 100644 index 0000000..e69de29 diff --git a/tests/parameters/testfiles/gentoo.backup/repos/calculate/profiles/default/desktop/calculate.ini b/tests/parameters/testfiles/gentoo.backup/repos/calculate/profiles/default/desktop/calculate.ini new file mode 100644 index 0000000..e69de29 diff --git a/tests/parameters/testfiles/gentoo.backup/repos/calculate/profiles/default/parent b/tests/parameters/testfiles/gentoo.backup/repos/calculate/profiles/default/parent new file mode 100644 index 0000000..f3229c5 --- /dev/null +++ b/tests/parameters/testfiles/gentoo.backup/repos/calculate/profiles/default/parent @@ -0,0 +1 @@ +.. diff --git a/tests/parameters/testfiles/gentoo.backup/repos/distros/profiles/CLD/amd64/calculate.ini b/tests/parameters/testfiles/gentoo.backup/repos/distros/profiles/CLD/amd64/calculate.ini new file mode 100644 index 0000000..ae500d1 --- /dev/null +++ b/tests/parameters/testfiles/gentoo.backup/repos/distros/profiles/CLD/amd64/calculate.ini @@ -0,0 +1,2 @@ +[os][linux] +arch = amd64 diff --git a/tests/parameters/testfiles/gentoo.backup/repos/distros/profiles/CLD/amd64/parent b/tests/parameters/testfiles/gentoo.backup/repos/distros/profiles/CLD/amd64/parent new file mode 100644 index 0000000..06dfeaf --- /dev/null +++ b/tests/parameters/testfiles/gentoo.backup/repos/distros/profiles/CLD/amd64/parent @@ -0,0 +1,2 @@ +calculate:default/amd64/20/desktop +.. diff --git a/tests/parameters/testfiles/gentoo.backup/repos/distros/profiles/CLD/calculate.ini b/tests/parameters/testfiles/gentoo.backup/repos/distros/profiles/CLD/calculate.ini new file mode 100644 index 0000000..7e78d71 --- /dev/null +++ b/tests/parameters/testfiles/gentoo.backup/repos/distros/profiles/CLD/calculate.ini @@ -0,0 +1,21 @@ +[os][linux] +ver = 20 +shortname = CLD +fullname = Calculate Linux Desktop +subname = KDE + +[os][hashvar] +value1 = new1 +value2 = new2 + +[os][tablevar][0] +dev = /dev/sda1 +mount = swap + +[os][tablevar][1] +dev = /dev/sda2 +mount = / + +[os][tablevar][2] +dev = /dev/sda5 +mount = /var/calculate diff --git a/tests/parameters/testfiles/gentoo.backup/repos/distros/profiles/CLD/parent b/tests/parameters/testfiles/gentoo.backup/repos/distros/profiles/CLD/parent new file mode 100644 index 0000000..f3229c5 --- /dev/null +++ b/tests/parameters/testfiles/gentoo.backup/repos/distros/profiles/CLD/parent @@ -0,0 +1 @@ +.. diff --git a/tests/parameters/testfiles/gentoo.backup/repos/distros/profiles/CLDX/amd64/calculate.ini b/tests/parameters/testfiles/gentoo.backup/repos/distros/profiles/CLDX/amd64/calculate.ini new file mode 100644 index 0000000..e69de29 diff --git a/tests/parameters/testfiles/gentoo.backup/repos/distros/profiles/CLDX/amd64/parent b/tests/parameters/testfiles/gentoo.backup/repos/distros/profiles/CLDX/amd64/parent new file mode 100644 index 0000000..06dfeaf --- /dev/null +++ b/tests/parameters/testfiles/gentoo.backup/repos/distros/profiles/CLDX/amd64/parent @@ -0,0 +1,2 @@ +calculate:default/amd64/20/desktop +.. diff --git a/tests/parameters/testfiles/gentoo.backup/repos/distros/profiles/CLDX/calculate.ini b/tests/parameters/testfiles/gentoo.backup/repos/distros/profiles/CLDX/calculate.ini new file mode 100644 index 0000000..e69de29 diff --git a/tests/parameters/testfiles/gentoo.backup/repos/distros/profiles/CLDX/parent b/tests/parameters/testfiles/gentoo.backup/repos/distros/profiles/CLDX/parent new file mode 100644 index 0000000..f3229c5 --- /dev/null +++ b/tests/parameters/testfiles/gentoo.backup/repos/distros/profiles/CLDX/parent @@ -0,0 +1 @@ +.. diff --git a/tests/parameters/testfiles/gentoo.backup/repos/distros/profiles/calculate.ini b/tests/parameters/testfiles/gentoo.backup/repos/distros/profiles/calculate.ini new file mode 100644 index 0000000..e69de29 diff --git a/tests/parameters/testfiles/parameters_ini/calculate.ini b/tests/parameters/testfiles/parameters_ini/calculate.ini new file mode 100644 index 0000000..e69de29 diff --git a/tests/parameters/testfiles/variables/main/__init__.py b/tests/parameters/testfiles/variables/main/__init__.py new file mode 100644 index 0000000..43d6a38 --- /dev/null +++ b/tests/parameters/testfiles/variables/main/__init__.py @@ -0,0 +1,4 @@ +from calculate.variables.datavars import Variable, StringType + + +Variable('chroot', type=StringType.readonly, source='/') diff --git a/tests/parameters/testfiles/variables/os/__init__.py b/tests/parameters/testfiles/variables/os/__init__.py new file mode 100644 index 0000000..3b40bcb --- /dev/null +++ b/tests/parameters/testfiles/variables/os/__init__.py @@ -0,0 +1,66 @@ +from calculate.variables.datavars import Namespace, Variable, Dependence,\ + StringType, HashType, TableType,\ + BooleanType, ListType, IntegerType + +with Namespace('linux'): + Variable('shortname', source='', type=StringType) + + Variable('ver', source='', type=StringType) + + Variable('fullname', source='', type=StringType) + + Variable('subname', source='', type=StringType) + + Variable('arch', source='', type=StringType) + + Variable('test_1', source=['choice_1', + 'choice_2', + 'choice_3', + 'choice_4'], type=ListType) + + Variable('test_2', source=False, type=BooleanType) + + Variable('test_3', source='test string', type=StringType) + + Variable('test_4', source='/dev/sda', type=StringType) + + Variable('test_5', source=8, type=IntegerType) + + Variable('test_6', source="Comment", type=StringType) + + def get_title(subname, fullname, ver): + if subname.value: + return '{} {} {}'.format(fullname.value, subname.value, ver.value) + else: + return '{} {}'.format(fullname.value, ver.value) + Variable('title', type=StringType, + source=Dependence('.subname', '.fullname', '.ver', + depend=get_title)) + +Variable('hashvar', source={'value1': 'test1', + 'value2': 'test2'}, type=HashType) + +Variable('hashvar_0', source={'value1': 'test1', + 'value2': 'test2'}, type=HashType) + +Variable('hashvar_1', source={'key1': 'value1', + 'key2': 'value2'}, type=HashType) + +Variable('hashvar_2', source={'id_1': 1349, + 'id_2': 1575}, type=HashType) + +Variable('calculate', type=StringType, + source=Dependence('.hashvar_0', + depend=lambda hashvar: "{} {}".format( + hashvar.value['value1'], + hashvar.value['value2']))) + +Variable('tablevar', type=TableType, source=[{"dev": "/dev/sdb1", + "mount": "/"}, + {"dev": "/dev/sdb2", + "mount": "/var/calculate"}]) + +Variable('dev_table', type=TableType, source=[{"dev": "/dev/sdb1", + "mount": "/"}, + {"dev": "/dev/sdb2", + "mount": "/var/calculate"}]) diff --git a/tests/parameters/testfiles/variables/os/gentoo/__init__.py b/tests/parameters/testfiles/variables/os/gentoo/__init__.py new file mode 100644 index 0000000..a50ffc4 --- /dev/null +++ b/tests/parameters/testfiles/variables/os/gentoo/__init__.py @@ -0,0 +1,57 @@ +import os +from calculate.variables.datavars import Variable, Namespace, Dependence,\ + StringType, TableType +''' +gentoo: + make_profile -> string + profile: + path -> string + name -> string + repositories[*]{name, path} -> table + config -> undefined +''' + +TESTFILES_PATH = os.path.join(os.getcwd(), 'tests/parameters/testfiles') + +# Путь до файла, указывающего на активный профиль +Variable('make_profile', type=StringType, source='/etc/portage/make.profile') + +# Параметры текущего профиля. +with Namespace('profile'): + # Абсолютный путь до профиля + Variable('path', type=StringType, + source=os.path.join(TESTFILES_PATH, + "gentoo/repos/distros/profiles/CLD/amd64")) + + def get_profile_name(path, repositories): + profile_path = path.value + if not profile_path: + return "" + + for repository in repositories.value: + repository_path = repository['path'] + repository_name = repository['name'] + remove_part = os.path.normpath(os.path.join(repository_path, + "profiles")) + if profile_path.startswith(remove_part): + return "{}:{}".format(repository_name, + profile_path[len(remove_part) + 1:]) + return profile_path + # Название профиля + Variable('name', type=StringType, + source=Dependence('.path', '..repositories', + depend=get_profile_name)) + +# Информация о репозиториях +# name: имя репозитория +# path: полный путь до репозитория +Variable('repositories', type=TableType, + source=[{'name': 'distros', + 'path': os.path.join(TESTFILES_PATH, + "gentoo/repos/distros")}, + {'name': 'calculate', + 'path': os.path.join(TESTFILES_PATH, + "gentoo/repos/calculate")}, + {'name': 'gentoo', + 'path': os.path.join(TESTFILES_PATH, + "gentoo/portage")}]) diff --git a/tests/parameters/testfiles/variables/system/__init__.py b/tests/parameters/testfiles/variables/system/__init__.py new file mode 100644 index 0000000..5468297 --- /dev/null +++ b/tests/parameters/testfiles/variables/system/__init__.py @@ -0,0 +1,19 @@ +import os +from calculate.variables.datavars import Variable, ListType, HashType +''' +system: + env_order -> list + env_path -> hash +''' + + +TESTFILES_PATH = os.path.join(os.getcwd(), 'tests/parameters/testfiles') + + +# Список мест, где есть calculate.ini файлы. +Variable('env_order', type=ListType, source=['system']) + +# Отображение множества мест, где есть calculate.ini файлы, на пути к ним. +Variable('env_path', type=HashType, + source={'system': os.path.join(TESTFILES_PATH, + 'parameters_ini/calculate.ini')}) diff --git a/tests/scripts/test_scripts.py b/tests/scripts/test_scripts.py index 553813b..2be0199 100644 --- a/tests/scripts/test_scripts.py +++ b/tests/scripts/test_scripts.py @@ -1,22 +1,36 @@ +import os +import shutil import pytest from calculate.scripts.scripts import Var, Task, Static, TaskError, Done,\ DoneAny, Success, SuccessAny, Failed,\ FailedAny, Block, For, While, Until,\ Handler, Script, Run, ScriptError,\ - ActionError + ActionError, ScriptLauncher, RunTemplate from calculate.variables.datavars import Namespace, Variable, IntegerType,\ StringType, BooleanType, ListType,\ HashType +from calculate.variables.loader import Datavars from calculate.utils.io_module import IOModule -@pytest.mark.tasks +TESTFILES_PATH = os.path.join(os.getcwd(), 'tests/scripts/testfiles') + + +@pytest.mark.scripts class TestTasks(): + def test_to_make_testfiles(self): + shutil.copytree(os.path.join(TESTFILES_PATH, 'var.backup'), + os.path.join(TESTFILES_PATH, 'var'), + symlinks=True) + shutil.copytree(os.path.join(TESTFILES_PATH, 'etc.backup'), + os.path.join(TESTFILES_PATH, 'etc'), + symlinks=True) + def test_if_arguments_of_the_Var_objects_are_correct_and_they_are_called_with_datavars_namespace_and_script_namespace_arguments__this_objects_can_be_used_for_different_checks(self): Namespace.reset() datavars = Namespace.datavars - script_namespace = Script.make_script_variables('test_script', [], - datavars) + script_namespace = ScriptLauncher.make_script_variables('test_script', + [], datavars) with Namespace('os'): Variable('var_1', source='value', type=StringType) @@ -103,13 +117,15 @@ class TestTasks(): def action(output, arg1): return f'os.var = {arg1}' - Script('test_script' - ).tasks( - Task(id='task', - name="Task", - action=action, - args=["os.var"]) - ).initialize(IOModule(), datavars, None)() + script = Script('test_script' + ).tasks( + Task(id='task', + name="Task", + action=action, + args=["os.var"]) + ) + launcher = script.make_launcher(IOModule(), datavars, None) + launcher() assert 'test_script' in datavars.scripts assert 'task' in datavars.scripts.test_script @@ -139,7 +155,7 @@ class TestTasks(): action=action, args=[Static('static_value'), "os.var_1"], when=(Var('os.var_2') & Var('os.var_3'))) - ).initialize(IOModule(), datavars, None)() + ).make_launcher(IOModule(), datavars, None)() assert 'test_script' in datavars.scripts assert 'task' in datavars.scripts.test_script @@ -166,7 +182,7 @@ class TestTasks(): action=action, args=[Static('value')], when=~Var('os.linux.var_1')) - ).initialize(IOModule(), datavars, None)() + ).make_launcher(IOModule(), datavars, None)() assert 'test_script' in datavars.scripts assert 'task' not in datavars.scripts.test_script @@ -191,7 +207,7 @@ class TestTasks(): args=[Static('value')], essential=False, when=Var('os.linux.var_1')) - ).initialize(IOModule(), datavars, None)() + ).make_launcher(IOModule(), datavars, None)() assert 'test_script' in datavars.scripts assert 'task' in datavars.scripts.test_script @@ -222,7 +238,7 @@ class TestTasks(): args=[Static('value')], essential=True, when=Var('os.linux.var_1')) - ).initialize(IOModule(), datavars, None)() + ).make_launcher(IOModule(), datavars, None)() def test_if_script_object_is_created_with_some_essential_tasks_with_conditions_and_some_conditions_uses_done_to_check_if_tasks_from_Done_or_DoneAny_arguments_were_completed__the_script_executes_tasks_which_done_condition_is_fulfilled(self): Namespace.reset() @@ -267,7 +283,7 @@ class TestTasks(): action=action, args=[Static('value_4')], when=DoneAny('task_1', 'task_3')) - ).initialize(IOModule(), datavars, None)() + ).make_launcher(IOModule(), datavars, None)() assert 'test_script' in datavars.scripts assert 'task_3' not in datavars.scripts.test_script @@ -345,7 +361,7 @@ class TestTasks(): args=[Static('value_10')], when=(Var('os.linux.var_1') & SuccessAny('task_3', 'task_4'))) - ).initialize(IOModule(), datavars, None)() + ).make_launcher(IOModule(), datavars, None)() assert 'test_script' in datavars.scripts assert 'task_4' not in datavars.scripts.test_script @@ -425,7 +441,7 @@ class TestTasks(): args=[Static('value_9')], when=(Var('os.linux.var_1') & FailedAny('task_2', 'task_3'))) - ).initialize(IOModule(), datavars, None)() + ).make_launcher(IOModule(), datavars, None)() assert 'test_script' in datavars.scripts assert not datavars.scripts.test_script.task_2.success @@ -457,7 +473,7 @@ class TestTasks(): name="Task 1", action=action, args=['os.linux.var']) - ).initialize(IOModule(), datavars, None)() + ).make_launcher(IOModule(), datavars, None)() def test_if_script_object_is_created_with_essential_task_having_set_parameter_containing_a_string_with_path_to_an_existing_variable__the_task_s_execution_result_will_be_set_to_the_variable_from_set_parameter(self): Namespace.reset() @@ -480,7 +496,7 @@ class TestTasks(): action=action, args=['os.linux.var_1'], set='os.linux.var_2') - ).initialize(IOModule(), datavars, None)() + ).make_launcher(IOModule(), datavars, None)() assert 'test_script' in datavars.scripts assert 'task' in datavars.scripts.test_script @@ -510,7 +526,7 @@ class TestTasks(): action=action, args=['os.linux.var_1'], set=['os.var_1', 'os.linux.var_2']) - ).initialize(IOModule(), datavars, None)() + ).make_launcher(IOModule(), datavars, None)() assert 'test_script' in datavars.scripts assert 'task' in datavars.scripts.test_script @@ -541,7 +557,7 @@ class TestTasks(): action=action, args=['os.linux.var_1'], set=('os.var_1', 'os.linux.var_2')) - ).initialize(IOModule(), datavars, None)() + ).make_launcher(IOModule(), datavars, None)() assert 'test_script' in datavars.scripts assert 'task' in datavars.scripts.test_script @@ -571,7 +587,7 @@ class TestTasks(): action=action, args=['os.linux.var_1', 'os.linux.var_2'], set={'field_1': 'os.var_1', 'field_2': 'os.var_2'}) - ).initialize(IOModule(), datavars, None)() + ).make_launcher(IOModule(), datavars, None)() assert 'test_script' in datavars.scripts assert 'task' in datavars.scripts.test_script @@ -596,7 +612,7 @@ class TestTasks(): name="Task", action=action, args=['os.linux.var_1']) - ).initialize(IOModule(), datavars, None)() + ).make_launcher(IOModule(), datavars, None)() def test_if_script_object_is_created_with_essential_task_having_action_function_with_a_return_type_annotation_and_set_parameter_containing_variable_of_the_different_type__the_task_fails_to_set_returned_value_to_this_variable(self): Namespace.reset() @@ -618,7 +634,7 @@ class TestTasks(): action=action, args=['os.linux.var_1'], set='os.linux.var_2') - ).initialize(IOModule(), datavars, None)() + ).make_launcher(IOModule(), datavars, None)() def test_if_script_object_is_created_with_plain_block_of_correct_tasks__the_script_will_be_executed_successfully(self): Namespace.reset() @@ -641,7 +657,7 @@ class TestTasks(): name="Task 2", action=action, args=[Static('value_2')])) - ).initialize(IOModule(), datavars, None)() + ).make_launcher(IOModule(), datavars, None)() assert 'test_script' in datavars.scripts assert 'task_1' in datavars.scripts.test_script @@ -671,7 +687,7 @@ class TestTasks(): action=action, args=[Static('value_2')]), when=Var('os.linux.var_1')) - ).initialize(IOModule(), datavars, None)() + ).make_launcher(IOModule(), datavars, None)() assert 'test_script' in datavars.scripts assert 'task_1' in datavars.scripts.test_script @@ -699,7 +715,7 @@ class TestTasks(): action=action, args=[Static('value_2')]), when=~Var('os.linux.var_1')) - ).initialize(IOModule(), datavars, None)() + ).make_launcher(IOModule(), datavars, None)() assert 'task_3' not in datavars.scripts.test_script assert 'task_4' not in datavars.scripts.test_script @@ -735,7 +751,7 @@ class TestTasks(): name="Task 3", action=action, args=[Static('rescue_value')])) - ).initialize(IOModule(), datavars, None)() + ).make_launcher(IOModule(), datavars, None)() assert 'test_script' in datavars.scripts assert 'task_1' in datavars.scripts.test_script @@ -777,7 +793,7 @@ class TestTasks(): action=action_2, args=['scripts.test_script.value']), loop=For('value', ['value_1', 'value_2', 'value_3'])) - ).initialize(IOModule(), datavars, None)() + ).make_launcher(IOModule(), datavars, None)() for l_value, r_value in zip(output, expected): assert l_value == r_value @@ -818,7 +834,7 @@ class TestTasks(): action=action_2, args=['scripts.test_script.value']), loop=For('value', 'os.linux.var_1')) - ).initialize(IOModule(), datavars, None)() + ).make_launcher(IOModule(), datavars, None)() for l_value, r_value in zip(output, expected): assert l_value == r_value @@ -851,7 +867,7 @@ class TestTasks(): set={'counter': 'os.counter', 'output': 'os.output'}), loop=While(Var('os.counter') < Var('os.ceiling'))) - ).initialize(IOModule(), datavars, None)() + ).make_launcher(IOModule(), datavars, None)() assert datavars.os.output == expected @@ -893,7 +909,7 @@ class TestTasks(): args=['os.counter', 'os.ceiling'], set='os.flag'), loop=While(~Var('os.flag'))) - ).initialize(IOModule(), datavars, None)() + ).make_launcher(IOModule(), datavars, None)() assert datavars.os.output == expected @@ -920,7 +936,7 @@ class TestTasks(): set={'counter': 'os.counter', 'output': 'os.output'}), loop=Until(Var('os.flag'))) - ).initialize(IOModule(), datavars, None)() + ).make_launcher(IOModule(), datavars, None)() assert datavars.os.output == ['counter = 0'] @@ -962,7 +978,7 @@ class TestTasks(): args=['os.counter', 'os.ceiling'], set='os.flag'), loop=Until(~Var('os.flag'))) - ).initialize(IOModule(), datavars, None)() + ).make_launcher(IOModule(), datavars, None)() assert datavars.os.output == expected @@ -994,7 +1010,7 @@ class TestTasks(): action=action, args=[Static('value_2')]) ) - ).initialize(IOModule(), datavars, None)() + ).make_launcher(IOModule(), datavars, None)() assert 'task_1' in datavars.scripts.test_script assert 'task_2' in datavars.scripts.test_script @@ -1047,7 +1063,7 @@ class TestTasks(): action=action, args=[Static('value_8')]) ) - ).initialize(IOModule(), datavars, None)() + ).make_launcher(IOModule(), datavars, None)() assert 'test_script' in datavars.scripts assert 'task_1' in datavars.scripts.test_script @@ -1112,7 +1128,7 @@ class TestTasks(): action=action, args=[Static('value_8')]) ) - ).initialize(IOModule(), datavars, None)() + ).make_launcher(IOModule(), datavars, None)() assert 'test_script' in datavars.scripts assert 'task_1' in datavars.scripts.test_script @@ -1177,7 +1193,7 @@ class TestTasks(): action=action, args=[Static('value_8')]) ) - ).initialize(IOModule(), datavars, None)() + ).make_launcher(IOModule(), datavars, None)() assert 'test_script' in datavars.scripts assert 'task_1' in datavars.scripts.test_script @@ -1242,7 +1258,7 @@ class TestTasks(): action=action, args=[Static('value_8')]) ) - ).initialize(IOModule(), datavars, None)() + ).make_launcher(IOModule(), datavars, None)() assert 'test_script' in datavars.scripts assert 'task_1' in datavars.scripts.test_script @@ -1311,7 +1327,7 @@ class TestTasks(): action=action, args=[Static('value_8')]) ) - ).initialize(IOModule(), datavars, None)() + ).make_launcher(IOModule(), datavars, None)() assert 'test_script' in datavars.scripts assert 'task_1' in datavars.scripts.test_script @@ -1340,6 +1356,16 @@ class TestTasks(): Script('test_script', args=['arg1', 'arg_2'], ).tasks( + Handler('handler_1', + Task(id='task_7', + name="Task 7", + action=action, + args=[Static('value_7')]), + Task(id='task_8', + name="Task 8", + action=action, + args=[Static('value_8')]) + ), Task(id='task_1', name="Task 1", action=action, @@ -1366,18 +1392,8 @@ class TestTasks(): Task(id='task_6', name="Task 6", action=action, - args=[Static('value_6')]), - Handler('handler_1', - Task(id='task_7', - name="Task 7", - action=action, - args=[Static('value_7')]), - Task(id='task_8', - name="Task 8", - action=action, - args=[Static('value_8')]) - ) - ).initialize(IOModule(), datavars, None)(True, False) + args=[Static('value_6')]) + ).make_launcher(IOModule(), datavars, None)(True, False) assert 'test_script' in datavars.scripts assert 'task_1' in datavars.scripts.test_script @@ -1411,7 +1427,7 @@ class TestTasks(): name="Task", action=action, args=[Static('value_2')]), - ).initialize(IOModule(), datavars, None)() + ).make_launcher(IOModule(), datavars, None)() assert 'test_script_1' in datavars.scripts assert 'test_script_2' in datavars.scripts @@ -1448,7 +1464,7 @@ class TestTasks(): name="Task", action=action, args=[Static('value_2')]), - ).initialize(IOModule(), datavars, None)() + ).make_launcher(IOModule(), datavars, None)() assert 'test_script_1' in datavars.scripts assert 'test_script_2' in datavars.scripts @@ -1485,7 +1501,7 @@ class TestTasks(): name="Task", action=action, args=[Static('value_2')]), - ).initialize(IOModule(), datavars, None)() + ).make_launcher(IOModule(), datavars, None)() assert 'test_script_1' in datavars.scripts assert 'test_script_2' in datavars.scripts @@ -1527,7 +1543,7 @@ class TestTasks(): name="Task 3", action=action, args=[Static('value_3')]), - ).initialize(IOModule(), datavars, None)() + ).make_launcher(IOModule(), datavars, None)() assert 'test_script_1' in datavars.scripts assert 'test_script_2' in datavars.scripts @@ -1573,7 +1589,7 @@ class TestTasks(): name="Task 3", action=action, args=[Static('value_3')]), - ).initialize(IOModule(), datavars, None)() + ).make_launcher(IOModule(), datavars, None)() def test_if_script_object_is_created_with_any_number_of_tasks_and_Run_object_is_used_to_run_other_script_with_excess_number_of_variables_as_its_arguments__the_outer_script_interrupts_its_execution_with_error(self): Namespace.reset() @@ -1607,7 +1623,7 @@ class TestTasks(): name="Task 3", action=action, args=[Static('value_3')]), - ).initialize(IOModule(), datavars, None)() + ).make_launcher(IOModule(), datavars, None)() def test_if_script_object_is_created_with_any_number_of_tasks_and_two_Run_objects_that_are_used_to_run_the_same_scripts_with_different_arguments__the_outer_script_runs_script_from_Run_objects_two_times_with_different_arguments(self): Namespace.reset() @@ -1637,7 +1653,7 @@ class TestTasks(): args=[Static('value_2')]), Run(script_1, namespace='os', args=[Static(13)]) - ).initialize(IOModule(), datavars, None)() + ).make_launcher(IOModule(), datavars, None)() assert 'test_script_1' in datavars.scripts assert 'test_script_2' in datavars.scripts @@ -1681,7 +1697,7 @@ class TestTasks(): name="Task 2", action=action, args=[Static('value_2')]) - ).initialize(IOModule(), datavars, None)() + ).make_launcher(IOModule(), datavars, None)() def test_if_script_object_is_created_with_any_number_of_tasks_and_not_essential_Run_object_is_used_to_run_other_failing_script__the_outer_script_skips_failing_script_and_continues_to_execute_its_own_tasks(self): Namespace.reset() @@ -1719,7 +1735,7 @@ class TestTasks(): name="Task 3", action=action, args=[Static('value_3')]) - ).initialize(IOModule(), datavars, None)() + ).make_launcher(IOModule(), datavars, None)() assert 'task_1' in datavars.scripts.test_script_1 assert not datavars.scripts.test_script_1.task_1.success @@ -1748,11 +1764,10 @@ class TestTasks(): name="Task 1", action=action, args=['os.var_1']) - ).initialize(IOModule(), datavars, None)() + ).make_launcher(IOModule(), datavars, None)() assert 'test_script' in datavars.scripts assert 'task_1' in datavars.scripts.test_script - assert 'task_1' in datavars.scripts.test_script def test_if_script_object_is_created_with_not_essential_task_which_action_raises_ActionError_exception_or_an_exception_inheriting_it__the_outer_script_skips_failing_task(self): Namespace.reset() @@ -1776,7 +1791,7 @@ class TestTasks(): essential=False, action=action, args=['os.var_1']) - ).initialize(IOModule(), datavars, None)() + ).make_launcher(IOModule(), datavars, None)() assert 'test_script' in datavars.scripts assert 'task_1' in datavars.scripts.test_script @@ -1797,18 +1812,19 @@ class TestTasks(): def action(arg1): return f'value = {arg1}' + tasks_1 = [Task(id='task_1', + name="Task 1", + action=action, + args=['.var_1'], + when=Var('scripts.test_script_1.arg')), + Task(id='task_2', + name="Task 2", + action=action, + args=['.var_1'], + when=~Var('scripts.test_script_1.arg'))] script_1 = Script('test_script_1', args=['arg'] - ).tasks(Task(id='task_1', - name="Task 1", - action=action, - args=['.var_1'], - when=Var('scripts.test_script_1.arg')), - Task(id='task_2', - name="Task 2", - action=action, - args=['.var_1'], - when=~Var('scripts.test_script_1.arg'))) + ).tasks(*tasks_1) Script('test_script_2', ).tasks(Task(id='task_1', @@ -1831,7 +1847,7 @@ class TestTasks(): when=Var('.linux.var_4')), Run(script_1, namespace='os', args=[False], when=Var('.linux.var_4')) - ).initialize(IOModule(), datavars, datavars.os)() + ).make_launcher(IOModule(), datavars, datavars.os)() assert 'test_script_1' in datavars.scripts assert 'test_script_2' in datavars.scripts @@ -1852,3 +1868,53 @@ class TestTasks(): assert 'task_2' in datavars.scripts.test_script_1 assert datavars.scripts.test_script_1.task_2.result == 'value = 1349' + + def test_run_templates_using_script(self): + datavars = Datavars(variables_path=os.path.join(TESTFILES_PATH, + 'variables')) + + Script('test_script', + ).tasks(RunTemplate(id="templates_1", + action='action_1', + package="test-category/test-package", + chroot_path=TESTFILES_PATH, + root_path="/etc"), + ).make_launcher(IOModule(), datavars, None)() + + assert 'test_script' in datavars.scripts + assert 'templates_1' in datavars.scripts.test_script + + assert datavars.scripts.test_script.templates_1.get_hash() ==\ + {"changed": {os.path.join(TESTFILES_PATH, + 'etc/dir_0'): 'N', + os.path.join(TESTFILES_PATH, + 'etc/dir_0/file_0'): 'N'}, + "skipped": []} + assert os.path.exists(os.path.join(TESTFILES_PATH, 'etc/dir_0/file_0')) + + def test_run_templates_using_script_and_namespace_is_set(self): + datavars = Datavars(variables_path=os.path.join(TESTFILES_PATH, + 'variables')) + + Script('test_script', + ).tasks(RunTemplate(id="templates_1", + action='action_2', + package="test-category/test-package", + chroot_path=TESTFILES_PATH, + root_path="/etc"), + ).make_launcher(IOModule(), datavars, datavars.os)() + + assert 'test_script' in datavars.scripts + assert 'templates_1' in datavars.scripts.test_script + + assert datavars.scripts.test_script.templates_1.get_hash() ==\ + {"changed": {os.path.join(TESTFILES_PATH, + 'etc/dir_1'): 'N', + os.path.join(TESTFILES_PATH, + 'etc/dir_1/file_0'): 'N'}, + "skipped": []} + assert os.path.exists(os.path.join(TESTFILES_PATH, 'etc/dir_1/file_0')) + + def test_for_removing_testfiles(self): + shutil.rmtree(os.path.join(TESTFILES_PATH, 'var')) + shutil.rmtree(os.path.join(TESTFILES_PATH, 'etc')) diff --git a/tests/scripts/testfiles/calculate.ini b/tests/scripts/testfiles/calculate.ini new file mode 100644 index 0000000..e69de29 diff --git a/tests/scripts/testfiles/templates/action_1/.calculate_directory b/tests/scripts/testfiles/templates/action_1/.calculate_directory new file mode 100644 index 0000000..7450383 --- /dev/null +++ b/tests/scripts/testfiles/templates/action_1/.calculate_directory @@ -0,0 +1,2 @@ +{% calculate action = "action_1", append = "skip", +package = "test-category/test-package" %} diff --git a/tests/scripts/testfiles/templates/action_1/dir_0/.calculate_directory b/tests/scripts/testfiles/templates/action_1/dir_0/.calculate_directory new file mode 100644 index 0000000..ee445f1 --- /dev/null +++ b/tests/scripts/testfiles/templates/action_1/dir_0/.calculate_directory @@ -0,0 +1 @@ +{% calculate append = "join" %} diff --git a/tests/scripts/testfiles/templates/action_1/dir_0/file_0 b/tests/scripts/testfiles/templates/action_1/dir_0/file_0 new file mode 100644 index 0000000..ca3ccfb --- /dev/null +++ b/tests/scripts/testfiles/templates/action_1/dir_0/file_0 @@ -0,0 +1,4 @@ +{% calculate append = "join", format = "kde" %} +[section][first] + parameter_1 = value_1 + parameter_2 = no diff --git a/tests/scripts/testfiles/templates/action_2/.calculate_directory b/tests/scripts/testfiles/templates/action_2/.calculate_directory new file mode 100644 index 0000000..441f3ca --- /dev/null +++ b/tests/scripts/testfiles/templates/action_2/.calculate_directory @@ -0,0 +1,2 @@ +{% calculate action = "action_2", append = "skip", +package = "test-category/test-package" %} diff --git a/tests/scripts/testfiles/templates/action_2/dir_1/.calculate_directory b/tests/scripts/testfiles/templates/action_2/dir_1/.calculate_directory new file mode 100644 index 0000000..ee445f1 --- /dev/null +++ b/tests/scripts/testfiles/templates/action_2/dir_1/.calculate_directory @@ -0,0 +1 @@ +{% calculate append = "join" %} diff --git a/tests/scripts/testfiles/templates/action_2/dir_1/file_0 b/tests/scripts/testfiles/templates/action_2/dir_1/file_0 new file mode 100644 index 0000000..e66fec0 --- /dev/null +++ b/tests/scripts/testfiles/templates/action_2/dir_1/file_0 @@ -0,0 +1,4 @@ +{% calculate append = "join", format = "kde" %} +[section][first] + parameter_1 = value + parameter_2 = no diff --git a/tests/scripts/testfiles/var.backup/db/pkg/test-category/other-package-1.1/CONTENTS b/tests/scripts/testfiles/var.backup/db/pkg/test-category/other-package-1.1/CONTENTS new file mode 100644 index 0000000..e69de29 diff --git a/tests/scripts/testfiles/var.backup/db/pkg/test-category/test-package-1.0/CONTENTS b/tests/scripts/testfiles/var.backup/db/pkg/test-category/test-package-1.0/CONTENTS new file mode 100644 index 0000000..e69de29 diff --git a/tests/scripts/testfiles/var.backup/db/pkg/test-category/test-package-1.0/SLOT b/tests/scripts/testfiles/var.backup/db/pkg/test-category/test-package-1.0/SLOT new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/tests/scripts/testfiles/var.backup/db/pkg/test-category/test-package-1.0/SLOT @@ -0,0 +1 @@ +1 diff --git a/tests/scripts/testfiles/var.backup/lib/calculate/.config.swo b/tests/scripts/testfiles/var.backup/lib/calculate/.config.swo new file mode 100644 index 0000000..01e1a35 Binary files /dev/null and b/tests/scripts/testfiles/var.backup/lib/calculate/.config.swo differ diff --git a/tests/scripts/testfiles/var.backup/lib/calculate/config b/tests/scripts/testfiles/var.backup/lib/calculate/config new file mode 100644 index 0000000..e69de29 diff --git a/tests/scripts/testfiles/var.backup/lib/calculate/config-archive/etc/dir_6/file_0 b/tests/scripts/testfiles/var.backup/lib/calculate/config-archive/etc/dir_6/file_0 new file mode 100644 index 0000000..4bb4151 --- /dev/null +++ b/tests/scripts/testfiles/var.backup/lib/calculate/config-archive/etc/dir_6/file_0 @@ -0,0 +1,3 @@ +options { + parameter-0 yes; +}; diff --git a/tests/scripts/testfiles/var.backup/lib/calculate/config-archive/etc/file_1 b/tests/scripts/testfiles/var.backup/lib/calculate/config-archive/etc/file_1 new file mode 100644 index 0000000..4bb4151 --- /dev/null +++ b/tests/scripts/testfiles/var.backup/lib/calculate/config-archive/etc/file_1 @@ -0,0 +1,3 @@ +options { + parameter-0 yes; +}; diff --git a/tests/scripts/testfiles/var.backup/lib/calculate/config-archive/etc/file_12 b/tests/scripts/testfiles/var.backup/lib/calculate/config-archive/etc/file_12 new file mode 100644 index 0000000..b441fd2 --- /dev/null +++ b/tests/scripts/testfiles/var.backup/lib/calculate/config-archive/etc/file_12 @@ -0,0 +1,3 @@ +section-name { + parameter-1 no; +}; diff --git a/tests/scripts/testfiles/var.backup/lib/calculate/config-archive/etc/file_2 b/tests/scripts/testfiles/var.backup/lib/calculate/config-archive/etc/file_2 new file mode 100644 index 0000000..4bb4151 --- /dev/null +++ b/tests/scripts/testfiles/var.backup/lib/calculate/config-archive/etc/file_2 @@ -0,0 +1,3 @@ +options { + parameter-0 yes; +}; diff --git a/tests/scripts/testfiles/var.backup/lib/gentoo/ini_vars_0.backup b/tests/scripts/testfiles/var.backup/lib/gentoo/ini_vars_0.backup new file mode 100644 index 0000000..e69de29 diff --git a/tests/scripts/testfiles/var.backup/lib/gentoo/portage/calculate.ini b/tests/scripts/testfiles/var.backup/lib/gentoo/portage/calculate.ini new file mode 100644 index 0000000..e69de29 diff --git a/tests/scripts/testfiles/var.backup/lib/gentoo/portage/profiles/calculate.ini b/tests/scripts/testfiles/var.backup/lib/gentoo/portage/profiles/calculate.ini new file mode 100644 index 0000000..e69de29 diff --git a/tests/scripts/testfiles/var.backup/lib/gentoo/portage/profiles/main/calculate.ini b/tests/scripts/testfiles/var.backup/lib/gentoo/portage/profiles/main/calculate.ini new file mode 100644 index 0000000..e69de29 diff --git a/tests/scripts/testfiles/var.backup/lib/gentoo/repos/calculate/profiles/calculate.ini b/tests/scripts/testfiles/var.backup/lib/gentoo/repos/calculate/profiles/calculate.ini new file mode 100644 index 0000000..e69de29 diff --git a/tests/scripts/testfiles/var.backup/lib/gentoo/repos/calculate/profiles/default/20/calculate.ini b/tests/scripts/testfiles/var.backup/lib/gentoo/repos/calculate/profiles/default/20/calculate.ini new file mode 100644 index 0000000..e69de29 diff --git a/tests/scripts/testfiles/var.backup/lib/gentoo/repos/calculate/profiles/default/amd64/20/calculate.ini b/tests/scripts/testfiles/var.backup/lib/gentoo/repos/calculate/profiles/default/amd64/20/calculate.ini new file mode 100644 index 0000000..e69de29 diff --git a/tests/scripts/testfiles/var.backup/lib/gentoo/repos/calculate/profiles/default/amd64/20/desktop/calculate.ini b/tests/scripts/testfiles/var.backup/lib/gentoo/repos/calculate/profiles/default/amd64/20/desktop/calculate.ini new file mode 100644 index 0000000..e69de29 diff --git a/tests/scripts/testfiles/var.backup/lib/gentoo/repos/calculate/profiles/default/amd64/20/desktop/parent b/tests/scripts/testfiles/var.backup/lib/gentoo/repos/calculate/profiles/default/amd64/20/desktop/parent new file mode 100644 index 0000000..08bf1a2 --- /dev/null +++ b/tests/scripts/testfiles/var.backup/lib/gentoo/repos/calculate/profiles/default/amd64/20/desktop/parent @@ -0,0 +1,3 @@ +gentoo:main +.. +../../../desktop diff --git a/tests/scripts/testfiles/var.backup/lib/gentoo/repos/calculate/profiles/default/amd64/20/parent b/tests/scripts/testfiles/var.backup/lib/gentoo/repos/calculate/profiles/default/amd64/20/parent new file mode 100644 index 0000000..0c34ef3 --- /dev/null +++ b/tests/scripts/testfiles/var.backup/lib/gentoo/repos/calculate/profiles/default/amd64/20/parent @@ -0,0 +1,2 @@ +.. +../../20 diff --git a/tests/scripts/testfiles/var.backup/lib/gentoo/repos/calculate/profiles/default/amd64/calculate.ini b/tests/scripts/testfiles/var.backup/lib/gentoo/repos/calculate/profiles/default/amd64/calculate.ini new file mode 100644 index 0000000..e69de29 diff --git a/tests/scripts/testfiles/var.backup/lib/gentoo/repos/calculate/profiles/default/amd64/parent b/tests/scripts/testfiles/var.backup/lib/gentoo/repos/calculate/profiles/default/amd64/parent new file mode 100644 index 0000000..f3229c5 --- /dev/null +++ b/tests/scripts/testfiles/var.backup/lib/gentoo/repos/calculate/profiles/default/amd64/parent @@ -0,0 +1 @@ +.. diff --git a/tests/scripts/testfiles/var.backup/lib/gentoo/repos/calculate/profiles/default/calculate.ini b/tests/scripts/testfiles/var.backup/lib/gentoo/repos/calculate/profiles/default/calculate.ini new file mode 100644 index 0000000..e69de29 diff --git a/tests/scripts/testfiles/var.backup/lib/gentoo/repos/calculate/profiles/default/desktop/calculate.ini b/tests/scripts/testfiles/var.backup/lib/gentoo/repos/calculate/profiles/default/desktop/calculate.ini new file mode 100644 index 0000000..e69de29 diff --git a/tests/scripts/testfiles/var.backup/lib/gentoo/repos/calculate/profiles/default/parent b/tests/scripts/testfiles/var.backup/lib/gentoo/repos/calculate/profiles/default/parent new file mode 100644 index 0000000..f3229c5 --- /dev/null +++ b/tests/scripts/testfiles/var.backup/lib/gentoo/repos/calculate/profiles/default/parent @@ -0,0 +1 @@ +.. diff --git a/tests/scripts/testfiles/var.backup/lib/gentoo/repos/distros/profiles/CLD/amd64/calculate.ini b/tests/scripts/testfiles/var.backup/lib/gentoo/repos/distros/profiles/CLD/amd64/calculate.ini new file mode 100644 index 0000000..ae500d1 --- /dev/null +++ b/tests/scripts/testfiles/var.backup/lib/gentoo/repos/distros/profiles/CLD/amd64/calculate.ini @@ -0,0 +1,2 @@ +[os][linux] +arch = amd64 diff --git a/tests/scripts/testfiles/var.backup/lib/gentoo/repos/distros/profiles/CLD/amd64/parent b/tests/scripts/testfiles/var.backup/lib/gentoo/repos/distros/profiles/CLD/amd64/parent new file mode 100644 index 0000000..06dfeaf --- /dev/null +++ b/tests/scripts/testfiles/var.backup/lib/gentoo/repos/distros/profiles/CLD/amd64/parent @@ -0,0 +1,2 @@ +calculate:default/amd64/20/desktop +.. diff --git a/tests/scripts/testfiles/var.backup/lib/gentoo/repos/distros/profiles/CLD/calculate.ini b/tests/scripts/testfiles/var.backup/lib/gentoo/repos/distros/profiles/CLD/calculate.ini new file mode 100644 index 0000000..7e78d71 --- /dev/null +++ b/tests/scripts/testfiles/var.backup/lib/gentoo/repos/distros/profiles/CLD/calculate.ini @@ -0,0 +1,21 @@ +[os][linux] +ver = 20 +shortname = CLD +fullname = Calculate Linux Desktop +subname = KDE + +[os][hashvar] +value1 = new1 +value2 = new2 + +[os][tablevar][0] +dev = /dev/sda1 +mount = swap + +[os][tablevar][1] +dev = /dev/sda2 +mount = / + +[os][tablevar][2] +dev = /dev/sda5 +mount = /var/calculate diff --git a/tests/scripts/testfiles/var.backup/lib/gentoo/repos/distros/profiles/CLD/parent b/tests/scripts/testfiles/var.backup/lib/gentoo/repos/distros/profiles/CLD/parent new file mode 100644 index 0000000..f3229c5 --- /dev/null +++ b/tests/scripts/testfiles/var.backup/lib/gentoo/repos/distros/profiles/CLD/parent @@ -0,0 +1 @@ +.. diff --git a/tests/scripts/testfiles/var.backup/lib/gentoo/repos/distros/profiles/CLDX/amd64/calculate.ini b/tests/scripts/testfiles/var.backup/lib/gentoo/repos/distros/profiles/CLDX/amd64/calculate.ini new file mode 100644 index 0000000..e69de29 diff --git a/tests/scripts/testfiles/var.backup/lib/gentoo/repos/distros/profiles/CLDX/amd64/parent b/tests/scripts/testfiles/var.backup/lib/gentoo/repos/distros/profiles/CLDX/amd64/parent new file mode 100644 index 0000000..06dfeaf --- /dev/null +++ b/tests/scripts/testfiles/var.backup/lib/gentoo/repos/distros/profiles/CLDX/amd64/parent @@ -0,0 +1,2 @@ +calculate:default/amd64/20/desktop +.. diff --git a/tests/scripts/testfiles/var.backup/lib/gentoo/repos/distros/profiles/CLDX/calculate.ini b/tests/scripts/testfiles/var.backup/lib/gentoo/repos/distros/profiles/CLDX/calculate.ini new file mode 100644 index 0000000..e69de29 diff --git a/tests/scripts/testfiles/var.backup/lib/gentoo/repos/distros/profiles/CLDX/parent b/tests/scripts/testfiles/var.backup/lib/gentoo/repos/distros/profiles/CLDX/parent new file mode 100644 index 0000000..f3229c5 --- /dev/null +++ b/tests/scripts/testfiles/var.backup/lib/gentoo/repos/distros/profiles/CLDX/parent @@ -0,0 +1 @@ +.. diff --git a/tests/scripts/testfiles/var.backup/lib/gentoo/repos/distros/profiles/calculate.ini b/tests/scripts/testfiles/var.backup/lib/gentoo/repos/distros/profiles/calculate.ini new file mode 100644 index 0000000..e69de29 diff --git a/tests/scripts/testfiles/variables/main/__init__.py b/tests/scripts/testfiles/variables/main/__init__.py new file mode 100644 index 0000000..8600521 --- /dev/null +++ b/tests/scripts/testfiles/variables/main/__init__.py @@ -0,0 +1,12 @@ +import os +from calculate.variables.datavars import Variable, StringType + + +TESTFILES_PATH = os.path.join(os.getcwd(), 'tests/scripts/testfiles') + +Variable('cl_chroot_path', type=StringType.readonly, source='/') + +Variable('cl_root_path', type=StringType.readonly, source='/') + +Variable('cl_template_path', type=StringType.readonly, + source=os.path.join(TESTFILES_PATH, 'templates')) diff --git a/tests/scripts/testfiles/variables/os/__init__.py b/tests/scripts/testfiles/variables/os/__init__.py new file mode 100644 index 0000000..3b40bcb --- /dev/null +++ b/tests/scripts/testfiles/variables/os/__init__.py @@ -0,0 +1,66 @@ +from calculate.variables.datavars import Namespace, Variable, Dependence,\ + StringType, HashType, TableType,\ + BooleanType, ListType, IntegerType + +with Namespace('linux'): + Variable('shortname', source='', type=StringType) + + Variable('ver', source='', type=StringType) + + Variable('fullname', source='', type=StringType) + + Variable('subname', source='', type=StringType) + + Variable('arch', source='', type=StringType) + + Variable('test_1', source=['choice_1', + 'choice_2', + 'choice_3', + 'choice_4'], type=ListType) + + Variable('test_2', source=False, type=BooleanType) + + Variable('test_3', source='test string', type=StringType) + + Variable('test_4', source='/dev/sda', type=StringType) + + Variable('test_5', source=8, type=IntegerType) + + Variable('test_6', source="Comment", type=StringType) + + def get_title(subname, fullname, ver): + if subname.value: + return '{} {} {}'.format(fullname.value, subname.value, ver.value) + else: + return '{} {}'.format(fullname.value, ver.value) + Variable('title', type=StringType, + source=Dependence('.subname', '.fullname', '.ver', + depend=get_title)) + +Variable('hashvar', source={'value1': 'test1', + 'value2': 'test2'}, type=HashType) + +Variable('hashvar_0', source={'value1': 'test1', + 'value2': 'test2'}, type=HashType) + +Variable('hashvar_1', source={'key1': 'value1', + 'key2': 'value2'}, type=HashType) + +Variable('hashvar_2', source={'id_1': 1349, + 'id_2': 1575}, type=HashType) + +Variable('calculate', type=StringType, + source=Dependence('.hashvar_0', + depend=lambda hashvar: "{} {}".format( + hashvar.value['value1'], + hashvar.value['value2']))) + +Variable('tablevar', type=TableType, source=[{"dev": "/dev/sdb1", + "mount": "/"}, + {"dev": "/dev/sdb2", + "mount": "/var/calculate"}]) + +Variable('dev_table', type=TableType, source=[{"dev": "/dev/sdb1", + "mount": "/"}, + {"dev": "/dev/sdb2", + "mount": "/var/calculate"}]) diff --git a/tests/scripts/testfiles/variables/os/gentoo/__init__.py b/tests/scripts/testfiles/variables/os/gentoo/__init__.py new file mode 100644 index 0000000..6e202d5 --- /dev/null +++ b/tests/scripts/testfiles/variables/os/gentoo/__init__.py @@ -0,0 +1,59 @@ +import os +from calculate.variables.datavars import Variable, Namespace, Dependence,\ + StringType, TableType +''' +gentoo: + make_profile -> string + profile: + path -> string + name -> string + repositories[*]{name, path} -> table + config -> undefined +''' + +TESTFILES_PATH = os.path.join(os.getcwd(), 'tests/scripts/testfiles') + +# Путь до файла, указывающего на активный профиль +Variable('make_profile', type=StringType, source='/etc/portage/make.profile') + +# Параметры текущего профиля. +with Namespace('profile'): + # Абсолютный путь до профиля + Variable('path', type=StringType, + source=os.path.join( + TESTFILES_PATH, + "var/lib/gentoo/repos/distros/profiles/CLD/amd64") + ) + + def get_profile_name(path, repositories): + profile_path = path.value + if not profile_path: + return "" + + for repository in repositories.value: + repository_path = repository['path'] + repository_name = repository['name'] + remove_part = os.path.normpath(os.path.join(repository_path, + "profiles")) + if profile_path.startswith(remove_part): + return "{}:{}".format(repository_name, + profile_path[len(remove_part) + 1:]) + return profile_path + # Название профиля + Variable('name', type=StringType, + source=Dependence('.path', '..repositories', + depend=get_profile_name)) + +# Информация о репозиториях +# name: имя репозитория +# path: полный путь до репозитория +Variable('repositories', type=TableType, + source=[{'name': 'distros', + 'path': os.path.join(TESTFILES_PATH, + "var/lib/gentoo/repos/distros")}, + {'name': 'calculate', + 'path': os.path.join(TESTFILES_PATH, + "var/lib/gentoo/repos/calculate")}, + {'name': 'gentoo', + 'path': os.path.join(TESTFILES_PATH, + "var/lib/gentoo/portage")}]) diff --git a/tests/scripts/testfiles/variables/system/__init__.py b/tests/scripts/testfiles/variables/system/__init__.py new file mode 100644 index 0000000..5468297 --- /dev/null +++ b/tests/scripts/testfiles/variables/system/__init__.py @@ -0,0 +1,19 @@ +import os +from calculate.variables.datavars import Variable, ListType, HashType +''' +system: + env_order -> list + env_path -> hash +''' + + +TESTFILES_PATH = os.path.join(os.getcwd(), 'tests/parameters/testfiles') + + +# Список мест, где есть calculate.ini файлы. +Variable('env_order', type=ListType, source=['system']) + +# Отображение множества мест, где есть calculate.ini файлы, на пути к ним. +Variable('env_path', type=HashType, + source={'system': os.path.join(TESTFILES_PATH, + 'parameters_ini/calculate.ini')}) diff --git a/tests/server/test_server.py b/tests/server/test_server.py new file mode 100644 index 0000000..c7e400a --- /dev/null +++ b/tests/server/test_server.py @@ -0,0 +1,58 @@ +import os +import pytest +import shutil +from fastapi.testclient import TestClient +from calculate.server.server import Server + + +TESTFILES_PATH = os.path.join(os.getcwd(), 'tests/server/testfiles') +VARS_PATH = os.path.join(TESTFILES_PATH, 'variables') +COMMANDS_PATH = 'tests/server/testfiles/commands' +server = Server(datavars_path=VARS_PATH, commands_path=COMMANDS_PATH) +test_client = TestClient(server.app) + + +@pytest.mark.server +class TestServer: + def test_to_make_testfiles(self): + shutil.copytree(os.path.join(TESTFILES_PATH, 'gentoo.backup'), + os.path.join(TESTFILES_PATH, 'gentoo'), + symlinks=True) + + def test_get_root_message(self): + response = test_client.get("/") + assert response.status_code == 200 + assert response.json() == {"msg": "root msg"} + + def test_get_commands_list(self): + response = test_client.get("/commands") + assert response.status_code == 200 + assert response.json() == {"test_1": + {"title": "Test 1", + "category": "Test Category", + "icon": "/path/to/icon_1.png", + "command": "test_1"}, + "test_2": + {"title": "Test 2", + "category": "Test Category", + "icon": "/path/to/icon_2.png", + "command": "cl_test_2"}} + + def test_post_command(self): + response = test_client.get("/commands/") + assert response.status_code == 200 + + def test_get_command_by_cid(self): + response = test_client.get("/commands/0") + assert response.status_code == 200 + assert response.json() == {"id": 0, "name": "command_0"} + + def test_get_worker_message_by_wid(self): + response = test_client.get("/workers/0") + assert response.status_code == 200 + data = response.json() + assert data == {'type': 'log', 'level': 'INFO', + 'msg': 'recieved message INFO'} + + def test_for_removing_testfiles(self): + shutil.rmtree(os.path.join(TESTFILES_PATH, 'gentoo')) diff --git a/tests/server/testfiles/calculate.ini b/tests/server/testfiles/calculate.ini new file mode 100644 index 0000000..e69de29 diff --git a/tests/server/testfiles/commands/cmd_module.py b/tests/server/testfiles/commands/cmd_module.py new file mode 100644 index 0000000..8858728 --- /dev/null +++ b/tests/server/testfiles/commands/cmd_module.py @@ -0,0 +1,54 @@ +from calculate.parameters.parameters import Description +from calculate.commands.commands import Command +from ..parameters.parameters import Parameter1, Parameter2 +from ..scripts.scripts import script_1, script_2 + + +command_1 = Command(command_id='test_1', + category='Test Category', + title='Test 1', + command="test_1", + script=script_1, + namespace='os', + icon="/path/to/icon_1.png", + rights=['group'], + parameters=[ + Parameter1 + ( + 'first-param', 'Test', + Description( + short='First parameter', + full='First parameter, but who cares'), + shortname='f' + ).bind('os.linux.test_5'), + Parameter2 + ( + 'second-param', 'Test', + Description( + short='Second parameter'), + shortname='s' + )]) + +command_2 = Command(command_id='test_2', + category='Test Category', + title='Test 2', + script=script_2, + namespace='os', + icon="/path/to/icon_2.png", + rights=['group'], + parameters=[ + Parameter1 + ( + 'first-param', 'Test', + Description( + short='First parameter', + full='First parameter, but who cares'), + shortname='f' + ).bind('os.linux.test_5'), + Parameter2 + ( + 'second-param', 'Test', + Description( + short='Second parameter'), + shortname='s' + )]) diff --git a/tests/server/testfiles/gentoo.backup/ini_vars_0.backup b/tests/server/testfiles/gentoo.backup/ini_vars_0.backup new file mode 100644 index 0000000..e69de29 diff --git a/tests/server/testfiles/gentoo.backup/portage/calculate.ini b/tests/server/testfiles/gentoo.backup/portage/calculate.ini new file mode 100644 index 0000000..e69de29 diff --git a/tests/server/testfiles/gentoo.backup/portage/profiles/calculate.ini b/tests/server/testfiles/gentoo.backup/portage/profiles/calculate.ini new file mode 100644 index 0000000..e69de29 diff --git a/tests/server/testfiles/gentoo.backup/portage/profiles/main/calculate.ini b/tests/server/testfiles/gentoo.backup/portage/profiles/main/calculate.ini new file mode 100644 index 0000000..e69de29 diff --git a/tests/server/testfiles/gentoo.backup/repos/calculate/profiles/calculate.ini b/tests/server/testfiles/gentoo.backup/repos/calculate/profiles/calculate.ini new file mode 100644 index 0000000..e69de29 diff --git a/tests/server/testfiles/gentoo.backup/repos/calculate/profiles/default/20/calculate.ini b/tests/server/testfiles/gentoo.backup/repos/calculate/profiles/default/20/calculate.ini new file mode 100644 index 0000000..e69de29 diff --git a/tests/server/testfiles/gentoo.backup/repos/calculate/profiles/default/amd64/20/calculate.ini b/tests/server/testfiles/gentoo.backup/repos/calculate/profiles/default/amd64/20/calculate.ini new file mode 100644 index 0000000..e69de29 diff --git a/tests/server/testfiles/gentoo.backup/repos/calculate/profiles/default/amd64/20/desktop/calculate.ini b/tests/server/testfiles/gentoo.backup/repos/calculate/profiles/default/amd64/20/desktop/calculate.ini new file mode 100644 index 0000000..e69de29 diff --git a/tests/server/testfiles/gentoo.backup/repos/calculate/profiles/default/amd64/20/desktop/parent b/tests/server/testfiles/gentoo.backup/repos/calculate/profiles/default/amd64/20/desktop/parent new file mode 100644 index 0000000..08bf1a2 --- /dev/null +++ b/tests/server/testfiles/gentoo.backup/repos/calculate/profiles/default/amd64/20/desktop/parent @@ -0,0 +1,3 @@ +gentoo:main +.. +../../../desktop diff --git a/tests/server/testfiles/gentoo.backup/repos/calculate/profiles/default/amd64/20/parent b/tests/server/testfiles/gentoo.backup/repos/calculate/profiles/default/amd64/20/parent new file mode 100644 index 0000000..0c34ef3 --- /dev/null +++ b/tests/server/testfiles/gentoo.backup/repos/calculate/profiles/default/amd64/20/parent @@ -0,0 +1,2 @@ +.. +../../20 diff --git a/tests/server/testfiles/gentoo.backup/repos/calculate/profiles/default/amd64/calculate.ini b/tests/server/testfiles/gentoo.backup/repos/calculate/profiles/default/amd64/calculate.ini new file mode 100644 index 0000000..e69de29 diff --git a/tests/server/testfiles/gentoo.backup/repos/calculate/profiles/default/amd64/parent b/tests/server/testfiles/gentoo.backup/repos/calculate/profiles/default/amd64/parent new file mode 100644 index 0000000..f3229c5 --- /dev/null +++ b/tests/server/testfiles/gentoo.backup/repos/calculate/profiles/default/amd64/parent @@ -0,0 +1 @@ +.. diff --git a/tests/server/testfiles/gentoo.backup/repos/calculate/profiles/default/calculate.ini b/tests/server/testfiles/gentoo.backup/repos/calculate/profiles/default/calculate.ini new file mode 100644 index 0000000..e69de29 diff --git a/tests/server/testfiles/gentoo.backup/repos/calculate/profiles/default/desktop/calculate.ini b/tests/server/testfiles/gentoo.backup/repos/calculate/profiles/default/desktop/calculate.ini new file mode 100644 index 0000000..e69de29 diff --git a/tests/server/testfiles/gentoo.backup/repos/calculate/profiles/default/parent b/tests/server/testfiles/gentoo.backup/repos/calculate/profiles/default/parent new file mode 100644 index 0000000..f3229c5 --- /dev/null +++ b/tests/server/testfiles/gentoo.backup/repos/calculate/profiles/default/parent @@ -0,0 +1 @@ +.. diff --git a/tests/server/testfiles/gentoo.backup/repos/distros/profiles/CLD/amd64/calculate.ini b/tests/server/testfiles/gentoo.backup/repos/distros/profiles/CLD/amd64/calculate.ini new file mode 100644 index 0000000..ae500d1 --- /dev/null +++ b/tests/server/testfiles/gentoo.backup/repos/distros/profiles/CLD/amd64/calculate.ini @@ -0,0 +1,2 @@ +[os][linux] +arch = amd64 diff --git a/tests/server/testfiles/gentoo.backup/repos/distros/profiles/CLD/amd64/parent b/tests/server/testfiles/gentoo.backup/repos/distros/profiles/CLD/amd64/parent new file mode 100644 index 0000000..06dfeaf --- /dev/null +++ b/tests/server/testfiles/gentoo.backup/repos/distros/profiles/CLD/amd64/parent @@ -0,0 +1,2 @@ +calculate:default/amd64/20/desktop +.. diff --git a/tests/server/testfiles/gentoo.backup/repos/distros/profiles/CLD/calculate.ini b/tests/server/testfiles/gentoo.backup/repos/distros/profiles/CLD/calculate.ini new file mode 100644 index 0000000..7e78d71 --- /dev/null +++ b/tests/server/testfiles/gentoo.backup/repos/distros/profiles/CLD/calculate.ini @@ -0,0 +1,21 @@ +[os][linux] +ver = 20 +shortname = CLD +fullname = Calculate Linux Desktop +subname = KDE + +[os][hashvar] +value1 = new1 +value2 = new2 + +[os][tablevar][0] +dev = /dev/sda1 +mount = swap + +[os][tablevar][1] +dev = /dev/sda2 +mount = / + +[os][tablevar][2] +dev = /dev/sda5 +mount = /var/calculate diff --git a/tests/server/testfiles/gentoo.backup/repos/distros/profiles/CLD/parent b/tests/server/testfiles/gentoo.backup/repos/distros/profiles/CLD/parent new file mode 100644 index 0000000..f3229c5 --- /dev/null +++ b/tests/server/testfiles/gentoo.backup/repos/distros/profiles/CLD/parent @@ -0,0 +1 @@ +.. diff --git a/tests/server/testfiles/gentoo.backup/repos/distros/profiles/CLDX/amd64/calculate.ini b/tests/server/testfiles/gentoo.backup/repos/distros/profiles/CLDX/amd64/calculate.ini new file mode 100644 index 0000000..e69de29 diff --git a/tests/server/testfiles/gentoo.backup/repos/distros/profiles/CLDX/amd64/parent b/tests/server/testfiles/gentoo.backup/repos/distros/profiles/CLDX/amd64/parent new file mode 100644 index 0000000..06dfeaf --- /dev/null +++ b/tests/server/testfiles/gentoo.backup/repos/distros/profiles/CLDX/amd64/parent @@ -0,0 +1,2 @@ +calculate:default/amd64/20/desktop +.. diff --git a/tests/server/testfiles/gentoo.backup/repos/distros/profiles/CLDX/calculate.ini b/tests/server/testfiles/gentoo.backup/repos/distros/profiles/CLDX/calculate.ini new file mode 100644 index 0000000..e69de29 diff --git a/tests/server/testfiles/gentoo.backup/repos/distros/profiles/CLDX/parent b/tests/server/testfiles/gentoo.backup/repos/distros/profiles/CLDX/parent new file mode 100644 index 0000000..f3229c5 --- /dev/null +++ b/tests/server/testfiles/gentoo.backup/repos/distros/profiles/CLDX/parent @@ -0,0 +1 @@ +.. diff --git a/tests/server/testfiles/gentoo.backup/repos/distros/profiles/calculate.ini b/tests/server/testfiles/gentoo.backup/repos/distros/profiles/calculate.ini new file mode 100644 index 0000000..e69de29 diff --git a/tests/server/testfiles/parameters/parameters.py b/tests/server/testfiles/parameters/parameters.py new file mode 100644 index 0000000..d94d2f1 --- /dev/null +++ b/tests/server/testfiles/parameters/parameters.py @@ -0,0 +1,25 @@ +from calculate.parameters.parameters import BaseParameter, Integer,\ + String, ValidationError + + +class Parameter1(BaseParameter): + type = Integer() + + def bind_method(self, var): + return var.value, None + + def validate(self, var): + if var.value < 10: + raise ValidationError("The value must be greater than 10") + + +class Parameter2(BaseParameter): + type = String() + + def bind_method(self): + return '/var/lib/calculate', None + + def validate(self, value): + if not value.startswith('/var/lib'): + raise ValidationError("The value must starts with a" + " '/var/lib'") diff --git a/tests/server/testfiles/scripts/scripts.py b/tests/server/testfiles/scripts/scripts.py new file mode 100644 index 0000000..dbf56cc --- /dev/null +++ b/tests/server/testfiles/scripts/scripts.py @@ -0,0 +1,22 @@ +from calculate.scripts.scripts import Script, Task + + +def action_1(output, arg1: str) -> str: + '''Задача выполняемая скриптом ниже.''' + return f'os.calculate = {arg1}' + + +# Тестовый скрипт. +script_1 = Script('script_1' + ).tasks(Task(id='task_1', + name="Task 1", + action=action_1, + args=["os.calculate"]) + ) + +# Тестовый скрипт. +script_2 = Script('script_2' + ).tasks(Task(id='task_2', + name="Task 2", + action=action_1, + args=["os.calculate"])) diff --git a/tests/server/testfiles/variables/main/__init__.py b/tests/server/testfiles/variables/main/__init__.py new file mode 100644 index 0000000..43d6a38 --- /dev/null +++ b/tests/server/testfiles/variables/main/__init__.py @@ -0,0 +1,4 @@ +from calculate.variables.datavars import Variable, StringType + + +Variable('chroot', type=StringType.readonly, source='/') diff --git a/tests/server/testfiles/variables/os/__init__.py b/tests/server/testfiles/variables/os/__init__.py new file mode 100644 index 0000000..3b40bcb --- /dev/null +++ b/tests/server/testfiles/variables/os/__init__.py @@ -0,0 +1,66 @@ +from calculate.variables.datavars import Namespace, Variable, Dependence,\ + StringType, HashType, TableType,\ + BooleanType, ListType, IntegerType + +with Namespace('linux'): + Variable('shortname', source='', type=StringType) + + Variable('ver', source='', type=StringType) + + Variable('fullname', source='', type=StringType) + + Variable('subname', source='', type=StringType) + + Variable('arch', source='', type=StringType) + + Variable('test_1', source=['choice_1', + 'choice_2', + 'choice_3', + 'choice_4'], type=ListType) + + Variable('test_2', source=False, type=BooleanType) + + Variable('test_3', source='test string', type=StringType) + + Variable('test_4', source='/dev/sda', type=StringType) + + Variable('test_5', source=8, type=IntegerType) + + Variable('test_6', source="Comment", type=StringType) + + def get_title(subname, fullname, ver): + if subname.value: + return '{} {} {}'.format(fullname.value, subname.value, ver.value) + else: + return '{} {}'.format(fullname.value, ver.value) + Variable('title', type=StringType, + source=Dependence('.subname', '.fullname', '.ver', + depend=get_title)) + +Variable('hashvar', source={'value1': 'test1', + 'value2': 'test2'}, type=HashType) + +Variable('hashvar_0', source={'value1': 'test1', + 'value2': 'test2'}, type=HashType) + +Variable('hashvar_1', source={'key1': 'value1', + 'key2': 'value2'}, type=HashType) + +Variable('hashvar_2', source={'id_1': 1349, + 'id_2': 1575}, type=HashType) + +Variable('calculate', type=StringType, + source=Dependence('.hashvar_0', + depend=lambda hashvar: "{} {}".format( + hashvar.value['value1'], + hashvar.value['value2']))) + +Variable('tablevar', type=TableType, source=[{"dev": "/dev/sdb1", + "mount": "/"}, + {"dev": "/dev/sdb2", + "mount": "/var/calculate"}]) + +Variable('dev_table', type=TableType, source=[{"dev": "/dev/sdb1", + "mount": "/"}, + {"dev": "/dev/sdb2", + "mount": "/var/calculate"}]) diff --git a/tests/server/testfiles/variables/os/gentoo/__init__.py b/tests/server/testfiles/variables/os/gentoo/__init__.py new file mode 100644 index 0000000..f114a6b --- /dev/null +++ b/tests/server/testfiles/variables/os/gentoo/__init__.py @@ -0,0 +1,57 @@ +import os +from calculate.variables.datavars import Variable, Namespace, Dependence,\ + StringType, TableType +''' +gentoo: + make_profile -> string + profile: + path -> string + name -> string + repositories[*]{name, path} -> table + config -> undefined +''' + +TESTFILES_PATH = os.path.join(os.getcwd(), 'tests/server/testfiles') + +# Путь до файла, указывающего на активный профиль +Variable('make_profile', type=StringType, source='/etc/portage/make.profile') + +# Параметры текущего профиля. +with Namespace('profile'): + # Абсолютный путь до профиля + Variable('path', type=StringType, + source=os.path.join(TESTFILES_PATH, + "gentoo/repos/distros/profiles/CLD/amd64")) + + def get_profile_name(path, repositories): + profile_path = path.value + if not profile_path: + return "" + + for repository in repositories.value: + repository_path = repository['path'] + repository_name = repository['name'] + remove_part = os.path.normpath(os.path.join(repository_path, + "profiles")) + if profile_path.startswith(remove_part): + return "{}:{}".format(repository_name, + profile_path[len(remove_part) + 1:]) + return profile_path + # Название профиля + Variable('name', type=StringType, + source=Dependence('.path', '..repositories', + depend=get_profile_name)) + +# Информация о репозиториях +# name: имя репозитория +# path: полный путь до репозитория +Variable('repositories', type=TableType, + source=[{'name': 'distros', + 'path': os.path.join(TESTFILES_PATH, + "gentoo/repos/distros")}, + {'name': 'calculate', + 'path': os.path.join(TESTFILES_PATH, + "gentoo/repos/calculate")}, + {'name': 'gentoo', + 'path': os.path.join(TESTFILES_PATH, + "gentoo/portage")}]) diff --git a/tests/server/testfiles/variables/system/__init__.py b/tests/server/testfiles/variables/system/__init__.py new file mode 100644 index 0000000..385716f --- /dev/null +++ b/tests/server/testfiles/variables/system/__init__.py @@ -0,0 +1,18 @@ +import os +from calculate.variables.datavars import Variable, ListType, HashType +''' +system: + env_order -> list + env_path -> hash +''' + + +TESTFILES_PATH = os.path.join(os.getcwd(), 'tests/server/testfiles') + + +# Список мест, где есть calculate.ini файлы. +Variable('env_order', type=ListType, source=['system']) + +# Отображение множества мест, где есть calculate.ini файлы, на пути к ним. +Variable('env_path', type=HashType, + source={'system': os.path.join(TESTFILES_PATH, 'calculate.ini')}) diff --git a/tests/variables/test_datavars.py b/tests/variables/test_datavars.py index c47f51a..d5972a6 100644 --- a/tests/variables/test_datavars.py +++ b/tests/variables/test_datavars.py @@ -1,6 +1,7 @@ import os import shutil import pytest +import logging from calculate.variables.datavars import NamespaceNode, VariableNode,\ Namespace, Variable, Dependence,\ CyclicVariableError, HashType,\ @@ -10,12 +11,10 @@ from calculate.variables.datavars import NamespaceNode, VariableNode,\ VariableTypeError, FloatType,\ ListType, VariableNotFoundError,\ Copy, Format, Calculate, Static -from calculate.templates.template_engine import TemplateEngine, FILE,\ - Variables, DIR +from calculate.templates.template_engine import TemplateEngine, FILE from calculate.templates.template_processor import TemplateExecutor from calculate.variables.loader import NamespaceIniFiller, Datavars from calculate.utils.files import stderr_devnull, read_file -from calculate.utils.io_module import IOModule TESTFILES_PATH = os.path.join(os.getcwd(), 'tests/variables/testfiles') @@ -26,6 +25,19 @@ APPENDS_SET = TemplateExecutor(cl_config_path=os.path.join( ).available_appends +class LoggingHandler(logging.Handler): + '''Тестовый хэндлер для логгирования в список, который затем можно + проверять в тестах.''' + def __init__(self, msg_list: list): + logging.Handler.__init__(self) + # Список для хранения сообщений логгера. + self.msg_list = msg_list + + def emit(self, record): + log_record = (record.levelname, record.getMessage()) + self.msg_list.append(log_record) + + @pytest.mark.vars class TestDatavars: # Сначала тестируем классы и методы необходимые для построения дерева @@ -1225,8 +1237,11 @@ value = another_value shutil.copytree(os.path.join(TESTFILES_PATH, 'gentoo.backup'), os.path.join(TESTFILES_PATH, 'gentoo'), symlinks=True) + assert os.path.exists(os.path.join(TESTFILES_PATH, 'gentoo')) + shutil.copytree(os.path.join(TESTFILES_PATH, 'ini_vars.backup'), os.path.join(TESTFILES_PATH, 'ini_vars')) + assert os.path.exists(os.path.join(TESTFILES_PATH, 'ini_vars')) def test_test_if_Datavars_object_is_created_with_a_specific_variables_path_and_repository_map_is_set_and_profile_path_is_set_in_the_variables__the_Datavars_object_finds_all_variables_packages_and_ini_files_from_a_profile_using_the_profile_path_variable_and_the_repository_map(self): repository_map = {'distros': os.path.join(TESTFILES_PATH, @@ -1524,45 +1539,46 @@ id_2 = 1349''' # Теперь тестируем обработку ошибок. def test_if_calculate_ini_file_has_some_syntax_errors_in_its_text__loader_skips_incorrect_lines_and_puts_some_error_messages_in_the_output(self): - io_module = IOModule(save_messages=True) + test_messages = [] + test_handler = LoggingHandler(test_messages) + test_logger = logging.getLogger("test") + test_logger.addHandler(test_handler) + Datavars(variables_path=os.path.join(TESTFILES_PATH, 'variables_12'), - io_module=io_module) + logger=test_logger) - messages = [('error', 'SyntaxError:1: [section'), - ('error', 'SyntaxError:2: varval1 = value1'), - ('error', 'SyntaxError:3: varval2 = value2'), - ('error', ("VariableError:4: variables package 'section'" + messages = [('ERROR', 'SyntaxError:1: [section'), + ('ERROR', 'SyntaxError:2: varval1 = value1'), + ('ERROR', 'SyntaxError:3: varval2 = value2'), + ('ERROR', ("VariableError:4: variables package 'section'" " is not found.")), - ('error', 'SyntaxError:6: eee'), - ('error', 'SyntaxError:8: [section2'), - ('error', ("VariableError:10: can not clear namespace" + ('ERROR', 'SyntaxError:6: eee'), + ('ERROR', 'SyntaxError:8: [section2'), + ('ERROR', ("VariableError:10: can not clear namespace" " 'section'. Variables package 'section' is not" " found.")), - ('error', 'SyntaxError:11: [section][][sub]'), - ('error', 'SyntaxError:12: [section][][sub][]'), - ('warning', 'Some variables was not loaded.'), - ('success', "Variables from 'system' are loaded"), - ('info', "Loading variables from file: 'local'"), - ('warning', ("File 'local' is not found. Variables" + ('ERROR', 'SyntaxError:11: [section][][sub]'), + ('ERROR', 'SyntaxError:12: [section][][sub][]'), + ('WARNING', 'Some variables was not loaded.'), + ('INFO', "Variables from 'system' are loaded"), + ('INFO', "Loading variables from file: 'local'"), + ('WARNING', ("File 'local' is not found. Variables" " are not loaded"))] + print('logged messages:', test_messages) for message, datavars_message in zip( messages, - io_module.messages[-len(messages):]): + test_messages[-len(messages):]): assert message == datavars_message def test_if_any_variables_module_has_syntax_error_in_its_code__the_variables_loader_raises_the_VariableError_exception(self): with pytest.raises(VariableError): - io_module = IOModule(save_messages=True) Datavars(variables_path=os.path.join(TESTFILES_PATH, - 'variables_13'), - io_module=io_module) + 'variables_13')) def test_if_datavars_object_is_used_to_get_access_to_an_unexisting_variable__the_datavars_module_raises_the_VariableNot_Found_exception(self): - io_module = IOModule(save_messages=True) datavars = Datavars(variables_path=os.path.join(TESTFILES_PATH, - 'variables_14'), - io_module=io_module) + 'variables_14')) with pytest.raises(VariableNotFoundError): datavars.level.variable @@ -1607,4 +1623,7 @@ os.linux.test_3 = {{ os.linux.test_3 }} def test_for_removing_testfiles(self): shutil.rmtree(os.path.join(TESTFILES_PATH, 'gentoo')) + assert not os.path.exists(os.path.join(TESTFILES_PATH, 'gentoo')) + shutil.rmtree(os.path.join(TESTFILES_PATH, 'ini_vars')) + assert not os.path.exists(os.path.join(TESTFILES_PATH, 'ini_vars'))