From 87f7502428fdacf8374617bfbc3c3987afa692ba Mon Sep 17 00:00:00 2001 From: Luis Gonzalez Date: Tue, 14 Sep 2021 13:12:13 +0200 Subject: [PATCH 01/15] add: Add `qa-docs` logger to script. #1879 Now it has to be used in all `qa-docs` modules. --- .../wazuh_testing/scripts/qa_docs.py | 64 +++++++++++-------- 1 file changed, 36 insertions(+), 28 deletions(-) diff --git a/deps/wazuh_testing/wazuh_testing/scripts/qa_docs.py b/deps/wazuh_testing/wazuh_testing/scripts/qa_docs.py index d836d5f470..cdad9ef400 100644 --- a/deps/wazuh_testing/wazuh_testing/scripts/qa_docs.py +++ b/deps/wazuh_testing/wazuh_testing/scripts/qa_docs.py @@ -1,5 +1,4 @@ import argparse -import logging import os from wazuh_testing.qa_docs.lib.config import Config @@ -11,43 +10,48 @@ from wazuh_testing.tools.exceptions import QAValueError VERSION = '0.1' -qactl_script_logger = Logging('QADOCS_SCRIPT', 'DEBUG', True) +qadocs_logger = Logging(QADOCS_LOGGER, 'INFO', False) CONFIG_PATH = os.path.join(os.path.dirname(os.path.realpath(__file__)), '..', 'qa_docs', 'config.yaml') OUTPUT_PATH = os.path.join(os.path.dirname(os.path.realpath(__file__)), '..', 'qa_docs', 'output') LOG_PATH = os.path.join(os.path.dirname(os.path.realpath(__file__)), '..', 'qa_docs', 'log') SEARCH_UI_PATH = os.path.join(os.path.dirname(os.path.realpath(__file__)), '..', 'qa_docs', 'search_ui') -def start_logging(folder, debug_level=logging.INFO): - LOG_PATH = os.path.join(folder, f"{os.path.splitext(os.path.basename(__file__))[0]}.log") - if not os.path.exists(folder): - os.makedirs(folder) - logging.basicConfig(filename=LOG_PATH, level=debug_level) - - def set_qadocs_logging(logging_level): + """Set the QADOCS logging depending on the level specified. + + Args: + logging_level (string): Level used to initialize the logger. + """ if not logging_level: qadocs_logger = Logging(QADOCS_LOGGER) qadocs_logger.disable() else: - qadocs_logger = Logging(QADOCS_LOGGER, logging_level, True) + qadocs_logger = Logging(QADOCS_LOGGER, logging_level, False) def validate_parameters(parameters): - qactl_script_logger.debug('Validating input parameters') + """Validate the parameters that qa-docs recieves. + + Args: + parameters (list): List of input args. + """ + qadocs_logger.debug('Validating input parameters') # Check if the directory where the tests are located exist if parameters.test_dir: if not os.path.exists(parameters.test_dir): raise QAValueError(f"{parameters.test_dir} does not exist. Tests directory not found.", - qactl_script_logger.error) + qadocs_logger.error) # Check that test_input name exists if parameters.test_input: doc_check = DocGenerator(Config(CONFIG_PATH, parameters.test_dir, '', parameters.test_input)) if doc_check.locate_test() is None: raise QAValueError(f"{parameters.test_input} not found.", - qactl_script_logger.error) + qadocs_logger.error) + + qadocs_logger.debug('Input parameters validation successfully finished') def main(): @@ -85,14 +89,11 @@ def main(): args = parser.parse_args() - validate_parameters(args) - + # Set the qa-docs logger if args.debug_level: - # set_qadocs_logging('DEBUG') - start_logging(LOG_PATH, logging.DEBUG) - else: - start_logging(LOG_PATH) - # set_qadocs_logging('INFO') + set_qadocs_logging('DEBUG') + + validate_parameters(args) if args.test_exist: doc_check = DocGenerator(Config(CONFIG_PATH, args.test_dir, '', args.test_exist)) @@ -101,36 +102,43 @@ def main(): if args.version: print(f"qa-docs v{VERSION}") + elif args.test_config: + qadocs_logger.debug('Loading qa-docs configuration') Config(CONFIG_PATH) + qadocs_logger.debug('qa-docs configuration loaded') + elif args.sanity: sanity = Sanity(Config(CONFIG_PATH)) - qactl_script_logger.debug('Running sanity check') + qadocs_logger.debug('Running sanity check') sanity.run() + elif args.index_name: - qactl_script_logger.debug(f"Indexing {args.index_name}") + qadocs_logger.debug(f"Indexing {args.index_name}") indexData = IndexData(args.index_name, Config(CONFIG_PATH, args.test_dir, OUTPUT_PATH)) indexData.run() + elif args.launch_app: - qactl_script_logger.debug(f"Indexing {args.index_name}") + qadocs_logger.debug(f"Indexing {args.index_name}") indexData = IndexData(args.launch_app, Config(CONFIG_PATH, args.test_dir, OUTPUT_PATH)) indexData.run() os.chdir(SEARCH_UI_PATH) - qactl_script_logger.debug('Running SearchUI') + qadocs_logger.debug('Running SearchUI') os.system("ELASTICSEARCH_HOST=http://localhost:9200 npm start") + else: if not args.test_exist: docs = DocGenerator(Config(CONFIG_PATH, args.test_dir, OUTPUT_PATH)) if args.test_input: - qactl_script_logger.debug(f"Parsing the following test(s) {args.test_input}") + qadocs_logger.info(f"Parsing the following test(s) {args.test_input}") if args.output_path: - qactl_script_logger.debug(f"{args.test_input}.json is going to be generated in {args.output_path}") + qadocs_logger.info(f"{args.test_input}.json is going to be generated in {args.output_path}") docs = DocGenerator(Config(CONFIG_PATH, args.test_dir, args.output_path, args.test_input)) else: docs = DocGenerator(Config(CONFIG_PATH, args.test_dir, '', args.test_input)) else: - qactl_script_logger.debug(f"Parsing all tests located in {args.test_dir}") - qactl_script_logger.debug('Running QADOCS') + qadocs_logger.info(f"Parsing all tests located in {args.test_dir}") + qadocs_logger.info('Running QADOCS') docs.run() if __name__ == '__main__': From 34db0f7dccb5ef0ec5c7f5075d9a9dd0ddf54daa Mon Sep 17 00:00:00 2001 From: Luis Gonzalez Date: Tue, 14 Sep 2021 13:56:55 +0200 Subject: [PATCH 02/15] refac: using now qa-docs logger to logging. #1879 --- .../wazuh_testing/qa_docs/lib/config.py | 46 ++++++++++--------- 1 file changed, 25 insertions(+), 21 deletions(-) diff --git a/deps/wazuh_testing/wazuh_testing/qa_docs/lib/config.py b/deps/wazuh_testing/wazuh_testing/qa_docs/lib/config.py index 386e0c3528..da00826fe7 100644 --- a/deps/wazuh_testing/wazuh_testing/qa_docs/lib/config.py +++ b/deps/wazuh_testing/wazuh_testing/qa_docs/lib/config.py @@ -8,9 +8,11 @@ """ import yaml -import logging from enum import Enum import os +from wazuh_testing.qa_docs import QADOCS_LOGGER +from wazuh_testing.tools.logging import Logging +from wazuh_testing.tools.exceptions import QAValueError class Config(): @@ -18,6 +20,8 @@ class Config(): brief: Class that parses the configuration file and exposes the available configurations. It exists two modes of execution: Normal and Single test. """ + LOGGER = Logging.get_logger(QADOCS_LOGGER) + def __init__(self, *args): # If it is called using the config file self.mode = mode.DEFAULT @@ -36,8 +40,8 @@ def __init__(self, *args): with open(args[0]) as fd: self._config_data = yaml.safe_load(fd) except: - logging.error("Cannot load config file") - raise Exception("Cannot load config file") + Config.LOGGER.error('Cannot load config file') + raise QAValueError('Cannot load config file', Config.LOGGER.error) self._read_function_regex() self._read_output_fields() @@ -91,8 +95,8 @@ def _read_include_paths(self): brief: Reads from the config file all the paths to be included in the parsing. """ if not 'Include paths' in self._config_data: - logging.error("Config include paths are empty") - raise Exception("Config include paths are empty") + Config.LOGGER.error('Config include paths are empty') + raise QAValueError('Config include paths are empty', Config.LOGGER.error) include_paths = self._config_data['Include paths'] for path in include_paths: self.include_paths.append(os.path.join(self.project_path, path)) @@ -102,8 +106,8 @@ def _read_include_regex(self): brief: Reads from the config file the regexes used to identify test files. """ if not 'Include regex' in self._config_data: - logging.error("Config include regex is empty") - raise Exception("Config include regex is empty") + Config.LOGGER.error('Config include regex is empty') + raise QAValueError('Config include regex is empty', Config.LOGGER.error) self.include_regex = self._config_data['Include regex'] def _read_group_files(self): @@ -111,8 +115,8 @@ def _read_group_files(self): brief: Reads from the config file the file name to be identified with a group. """ if not 'Group files' in self._config_data: - logging.error("Config group files is empty") - raise Exception("Config group files is empty") + Config.LOGGER.error("Config group files is empty") + raise QAValueError('Config include paths are empty', Config.LOGGER.error) self.group_files = self._config_data['Group files'] def _read_function_regex(self): @@ -120,8 +124,8 @@ def _read_function_regex(self): brief: Reads from the config file the regexes used to identify a test method. """ if not 'Function regex' in self._config_data: - logging.error("Config function regex is empty") - raise Exception("Config function regex is empty") + Config.LOGGER.error('Config function regex is empty') + raise QAValueError('Config function regex is empty', Config.LOGGER.error) self.function_regex = self._config_data['Function regex'] def _read_ignore_paths(self): @@ -138,12 +142,12 @@ def _read_module_fields(self): brief: Reads from the config file the optional and mandatory fields for the test module. """ if not 'Module' in self._config_data['Output fields']: - logging.error("Config output module fields is missing") - raise Exception("Config output module fields is missing") + Config.LOGGER.error('Config output module fields is missing') + raise QAValueError('Config output module fields is missing', Config.LOGGER.error) module_fields = self._config_data['Output fields']['Module'] if not 'Mandatory' in module_fields and not 'Optional' in module_fields: - logging.error("Config output module fields are empty") - raise Exception("Config output module fields are empty") + Config.LOGGER.error('Config output module fields are empty') + raise QAValueError('Config output module fields are empty', Config.LOGGER.error) if 'Mandatory' in module_fields: self.module_fields.mandatory = module_fields['Mandatory'] if 'Optional' in module_fields: @@ -154,12 +158,12 @@ def _read_test_fields(self): brief: Reads from the config file the optional and mandatory fields for the test functions. """ if not 'Test' in self._config_data['Output fields']: - logging.error("Config output test fields is missing") - raise Exception("Config output test fields is missing") + Config.LOGGER.error('Config output test fields is missing') + raise QAValueError('Config output test fields is missing', Config.LOGGER.error) test_fields = self._config_data['Output fields']['Test'] if not 'Mandatory' in test_fields and not 'Optional' in test_fields: - logging.error("Config output test fields are empty") - raise Exception("Config output test fields are empty") + Config.LOGGER.error('Config output test fields are empty') + raise QAValueError('Config output test fields are empty', Config.LOGGER.error) if 'Mandatory' in test_fields: self.test_fields.mandatory = test_fields['Mandatory'] if 'Optional' in test_fields: @@ -170,8 +174,8 @@ def _read_output_fields(self): brief: Reads all the mandatory and optional fields. """ if not 'Output fields' in self._config_data: - logging.error("Config output fields is missing") - raise Exception("Config output fields is missing") + Config.LOGGER.error('Config output fields is missing') + raise QAValueError('Config output fields is missing', Config.LOGGER.error) self._read_module_fields() self._read_test_fields() From 762e83e81f94477a9891c637ba055835f7195d90 Mon Sep 17 00:00:00 2001 From: Luis Gonzalez Date: Wed, 15 Sep 2021 09:35:51 +0200 Subject: [PATCH 03/15] add: add debug logging to `config.py` #1879 --- .../wazuh_testing/qa_docs/lib/config.py | 99 +++++++++++++------ 1 file changed, 71 insertions(+), 28 deletions(-) diff --git a/deps/wazuh_testing/wazuh_testing/qa_docs/lib/config.py b/deps/wazuh_testing/wazuh_testing/qa_docs/lib/config.py index da00826fe7..1684d373f6 100644 --- a/deps/wazuh_testing/wazuh_testing/qa_docs/lib/config.py +++ b/deps/wazuh_testing/wazuh_testing/qa_docs/lib/config.py @@ -37,23 +37,22 @@ def __init__(self, *args): self.test_cases_field = None try: + Config.LOGGER.debug('Loading config file') with open(args[0]) as fd: self._config_data = yaml.safe_load(fd) except: - Config.LOGGER.error('Cannot load config file') raise QAValueError('Cannot load config file', Config.LOGGER.error) self._read_function_regex() self._read_output_fields() self._read_test_cases_field() - self._read_documentation_path() self._read_include_paths() self._read_include_regex() self._read_group_files() self._read_ignore_paths() if len(args) >= 3: - self.documentation_path = args[2] + self._set_documentation_path(args[2]) if len(args) == 4: # It is called with a single test to parse self.mode = mode.SINGLE_TEST @@ -63,41 +62,66 @@ def __init__(self, *args): def _read_test_info(self): - ''' - brief: Reads from the config file the keys to be printed from test info - ''' + """Reads from the config file the keys to be printed from module info. + + This functionality is used to print any custom field(s) you want. + You can use it if you only need a few fields to parse when a single test is run. + + For example you have this in your config.yaml: + + Test info: + - test_wazuh_min_version: wazuh_min_version + """ + Config.LOGGER.debug('Reading test info from config file') if 'Test info' in self._config_data: self.test_info = self._config_data['Test info'] + else: + Config.LOGGER.warning('Cannot read test info fields') def _read_module_info(self): - ''' - brief: Reads from the config file the keys to be printed from module info - ''' + """Reads from the config file the fields to be printed from test info. + + This functionality is used to print any custom field(s) you want. + You can use it if you only need a few fields to parse when a single test is run. + + For example you have this in your config.yaml: + + Module info: + - test_system: os_platform + - test_vendor: os_vendor + - test_version: os_version + - test_target: component + """ + Config.LOGGER.debug('Reading module info from config file') + if 'Module info' in self._config_data: self.module_info = self._config_data['Module info'] + else: + Config.LOGGER.warning('Cannot read module info fields') - def _read_project_path(self): + def _set_documentation_path(self, path): """ - brief: Reads from the config file the path of the project. + brief: Sets the path of the documentation output. """ - if 'Project path' in self._config_data: - self.project_path = self._config_data['Project path'] + Config.LOGGER.debug('Setting the path documentation') - def _read_documentation_path(self): - """ - brief: Reads from the config file the path of the documentation output. - """ - if 'Output path' in self._config_data: - self.documentation_path = self._config_data['Output path'] + if path: + self.documentation_path = path + else: + Config.LOGGER.warning('You have not passed a path where the documentation data is dumped') def _read_include_paths(self): """ brief: Reads from the config file all the paths to be included in the parsing. """ + Config.LOGGER.debug('Reading include paths from config file') + + # Will be replaced by --type --module and --test , so you can run what you need if not 'Include paths' in self._config_data: - Config.LOGGER.error('Config include paths are empty') raise QAValueError('Config include paths are empty', Config.LOGGER.error) + include_paths = self._config_data['Include paths'] + for path in include_paths: self.include_paths.append(os.path.join(self.project_path, path)) @@ -105,35 +129,44 @@ def _read_include_regex(self): """ brief: Reads from the config file the regexes used to identify test files. """ + Config.LOGGER.debug('Reading the regular expressions to include files from config file') + if not 'Include regex' in self._config_data: - Config.LOGGER.error('Config include regex is empty') raise QAValueError('Config include regex is empty', Config.LOGGER.error) + self.include_regex = self._config_data['Include regex'] def _read_group_files(self): """ brief: Reads from the config file the file name to be identified with a group. """ + Config.LOGGER.debug('Reading group files from config file') + if not 'Group files' in self._config_data: - Config.LOGGER.error("Config group files is empty") raise QAValueError('Config include paths are empty', Config.LOGGER.error) + self.group_files = self._config_data['Group files'] def _read_function_regex(self): """ brief: Reads from the config file the regexes used to identify a test method. """ + Config.LOGGER.debug('Reading the regular expressions to include test methods from config file') + if not 'Function regex' in self._config_data: - Config.LOGGER.error('Config function regex is empty') raise QAValueError('Config function regex is empty', Config.LOGGER.error) + self.function_regex = self._config_data['Function regex'] def _read_ignore_paths(self): """ brief: Reads from the config file all the paths to be excluded from the parsing. """ + Config.LOGGER.debug('Reading the paths to be ignored from config file') + if 'Ignore paths' in self._config_data: ignore_paths = self._config_data['Ignore paths'] + for path in ignore_paths: self.ignore_paths.append(os.path.join(self.project_path, path)) @@ -141,15 +174,19 @@ def _read_module_fields(self): """ brief: Reads from the config file the optional and mandatory fields for the test module. """ + Config.LOGGER.debug('Reading mandatory and optional module fields from config file') + if not 'Module' in self._config_data['Output fields']: - Config.LOGGER.error('Config output module fields is missing') raise QAValueError('Config output module fields is missing', Config.LOGGER.error) + module_fields = self._config_data['Output fields']['Module'] + if not 'Mandatory' in module_fields and not 'Optional' in module_fields: - Config.LOGGER.error('Config output module fields are empty') raise QAValueError('Config output module fields are empty', Config.LOGGER.error) + if 'Mandatory' in module_fields: self.module_fields.mandatory = module_fields['Mandatory'] + if 'Optional' in module_fields: self.module_fields.optional = module_fields['Optional'] @@ -157,15 +194,19 @@ def _read_test_fields(self): """ brief: Reads from the config file the optional and mandatory fields for the test functions. """ + Config.LOGGER.debug('Reading mandatory and optional test fields from config file') + if not 'Test' in self._config_data['Output fields']: - Config.LOGGER.error('Config output test fields is missing') raise QAValueError('Config output test fields is missing', Config.LOGGER.error) + test_fields = self._config_data['Output fields']['Test'] + if not 'Mandatory' in test_fields and not 'Optional' in test_fields: - Config.LOGGER.error('Config output test fields are empty') raise QAValueError('Config output test fields are empty', Config.LOGGER.error) + if 'Mandatory' in test_fields: self.test_fields.mandatory = test_fields['Mandatory'] + if 'Optional' in test_fields: self.test_fields.optional = test_fields['Optional'] @@ -174,8 +215,8 @@ def _read_output_fields(self): brief: Reads all the mandatory and optional fields. """ if not 'Output fields' in self._config_data: - Config.LOGGER.error('Config output fields is missing') raise QAValueError('Config output fields is missing', Config.LOGGER.error) + self._read_module_fields() self._read_test_fields() @@ -183,6 +224,8 @@ def _read_test_cases_field(self): """ brief: Reads from the configuration file the key to identify a Test Case list. """ + Config.LOGGER.debug('Reading Test Case key from config file') + if 'Test cases field' in self._config_data: self.test_cases_field = self._config_data['Test cases field'] From 269e58e0dd07bf85572ae8435a0e2b61de4574b7 Mon Sep 17 00:00:00 2001 From: Luis Gonzalez Date: Wed, 15 Sep 2021 09:46:10 +0200 Subject: [PATCH 04/15] refac: add load config file method and fix private class method style. #1879 --- .../wazuh_testing/qa_docs/lib/config.py | 70 +++++++++---------- 1 file changed, 34 insertions(+), 36 deletions(-) diff --git a/deps/wazuh_testing/wazuh_testing/qa_docs/lib/config.py b/deps/wazuh_testing/wazuh_testing/qa_docs/lib/config.py index 1684d373f6..d8cd7e0092 100644 --- a/deps/wazuh_testing/wazuh_testing/qa_docs/lib/config.py +++ b/deps/wazuh_testing/wazuh_testing/qa_docs/lib/config.py @@ -36,32 +36,34 @@ def __init__(self, *args): self.test_fields = _fields() self.test_cases_field = None - try: - Config.LOGGER.debug('Loading config file') - with open(args[0]) as fd: - self._config_data = yaml.safe_load(fd) - except: - raise QAValueError('Cannot load config file', Config.LOGGER.error) - - self._read_function_regex() - self._read_output_fields() - self._read_test_cases_field() - self._read_include_paths() - self._read_include_regex() - self._read_group_files() - self._read_ignore_paths() + self.__load_config_file(args[0]) + self.__read_function_regex() + self.__read_output_fields() + self.__read_test_cases_field() + self.__read_include_paths() + self.__read_include_regex() + self.__read_group_files() + self.__read_ignore_paths() if len(args) >= 3: - self._set_documentation_path(args[2]) + self.__set_documentation_path(args[2]) if len(args) == 4: # It is called with a single test to parse self.mode = mode.SINGLE_TEST self.test_name = args[3] - self._read_test_info() - self._read_module_info() + self.__read_test_info() + self.__read_module_info() + + def __load_config_file(self, file): + try: + Config.LOGGER.debug('Loading config file') + with open(file) as config_file: + self._config_data = yaml.safe_load(config_file) + except: + raise QAValueError('Cannot load config file', Config.LOGGER.error) - def _read_test_info(self): + def __read_test_info(self): """Reads from the config file the keys to be printed from module info. This functionality is used to print any custom field(s) you want. @@ -78,7 +80,7 @@ def _read_test_info(self): else: Config.LOGGER.warning('Cannot read test info fields') - def _read_module_info(self): + def __read_module_info(self): """Reads from the config file the fields to be printed from test info. This functionality is used to print any custom field(s) you want. @@ -99,18 +101,14 @@ def _read_module_info(self): else: Config.LOGGER.warning('Cannot read module info fields') - def _set_documentation_path(self, path): + def __set_documentation_path(self, path): """ brief: Sets the path of the documentation output. """ Config.LOGGER.debug('Setting the path documentation') + self.documentation_path = path - if path: - self.documentation_path = path - else: - Config.LOGGER.warning('You have not passed a path where the documentation data is dumped') - - def _read_include_paths(self): + def __read_include_paths(self): """ brief: Reads from the config file all the paths to be included in the parsing. """ @@ -125,7 +123,7 @@ def _read_include_paths(self): for path in include_paths: self.include_paths.append(os.path.join(self.project_path, path)) - def _read_include_regex(self): + def __read_include_regex(self): """ brief: Reads from the config file the regexes used to identify test files. """ @@ -136,7 +134,7 @@ def _read_include_regex(self): self.include_regex = self._config_data['Include regex'] - def _read_group_files(self): + def __read_group_files(self): """ brief: Reads from the config file the file name to be identified with a group. """ @@ -147,7 +145,7 @@ def _read_group_files(self): self.group_files = self._config_data['Group files'] - def _read_function_regex(self): + def __read_function_regex(self): """ brief: Reads from the config file the regexes used to identify a test method. """ @@ -158,7 +156,7 @@ def _read_function_regex(self): self.function_regex = self._config_data['Function regex'] - def _read_ignore_paths(self): + def __read_ignore_paths(self): """ brief: Reads from the config file all the paths to be excluded from the parsing. """ @@ -170,7 +168,7 @@ def _read_ignore_paths(self): for path in ignore_paths: self.ignore_paths.append(os.path.join(self.project_path, path)) - def _read_module_fields(self): + def __read_module_fields(self): """ brief: Reads from the config file the optional and mandatory fields for the test module. """ @@ -190,7 +188,7 @@ def _read_module_fields(self): if 'Optional' in module_fields: self.module_fields.optional = module_fields['Optional'] - def _read_test_fields(self): + def __read_test_fields(self): """ brief: Reads from the config file the optional and mandatory fields for the test functions. """ @@ -210,17 +208,17 @@ def _read_test_fields(self): if 'Optional' in test_fields: self.test_fields.optional = test_fields['Optional'] - def _read_output_fields(self): + def __read_output_fields(self): """ brief: Reads all the mandatory and optional fields. """ if not 'Output fields' in self._config_data: raise QAValueError('Config output fields is missing', Config.LOGGER.error) - self._read_module_fields() - self._read_test_fields() + self.__read_module_fields() + self.__read_test_fields() - def _read_test_cases_field(self): + def __read_test_cases_field(self): """ brief: Reads from the configuration file the key to identify a Test Case list. """ From 2f122753a7071c5825fc0647467780e8f21a011c Mon Sep 17 00:00:00 2001 From: Luis Gonzalez Date: Wed, 15 Sep 2021 10:15:19 +0200 Subject: [PATCH 05/15] refac: add `qa-docs` logger to `DocGenerator` module. #1879 --- .../wazuh_testing/qa_docs/doc_generator.py | 80 +++++++++++++------ 1 file changed, 57 insertions(+), 23 deletions(-) diff --git a/deps/wazuh_testing/wazuh_testing/qa_docs/doc_generator.py b/deps/wazuh_testing/wazuh_testing/qa_docs/doc_generator.py index 499d92e12b..4f32da42d7 100644 --- a/deps/wazuh_testing/wazuh_testing/qa_docs/doc_generator.py +++ b/deps/wazuh_testing/wazuh_testing/qa_docs/doc_generator.py @@ -11,18 +11,20 @@ import re import json import yaml -from wazuh_testing.qa_docs.lib.config import mode +from wazuh_testing.qa_docs.lib.config import Config, mode from wazuh_testing.qa_docs.lib.code_parser import CodeParser from wazuh_testing.qa_docs.lib.utils import clean_folder -import warnings -import logging - +from wazuh_testing.qa_docs import QADOCS_LOGGER +from wazuh_testing.tools.logging import Logging +from wazuh_testing.tools.exceptions import QAValueError class DocGenerator: """ brief: Main class of DocGenerator tool. It´s in charge of walk every test file, and every group file to dump the parsed documentation. """ + LOGGER = Logging.get_logger(QADOCS_LOGGER) + def __init__(self, config): self.conf = config self.parser = CodeParser(self.conf) @@ -44,7 +46,9 @@ def is_valid_folder(self, path): """ for regex in self.ignore_regex: if regex.match(path): + DocGenerator.LOGGER.warning(f"Folder validation: {regex} not matchin with {path}") return False + return True def is_valid_file(self, file): @@ -55,12 +59,17 @@ def is_valid_file(self, file): - "file (str): File name to be controlled" returns: "boolean: False if the file should be ignored. True otherwise." """ + for regex in self.ignore_regex: if regex.match(file): + DocGenerator.LOGGER.warning(f"File validation: {regex} not matchin with {file}") return False + for regex in self.include_regex: if regex.match(file): + DocGenerator.LOGGER.warning(f"File validation: {regex} not matchin with {file}") return True + return False def is_group_file(self, path): @@ -70,9 +79,11 @@ def is_group_file(self, path): - "path (str): File location to be controlled" returns: "boolean: True if the file is a group file. False otherwise." """ + for group_file in self.conf.group_files: if path == group_file: return True + return False def get_group_doc_path(self, group): @@ -82,6 +93,7 @@ def get_group_doc_path(self, group): """ base_path = os.path.join(self.conf.documentation_path, os.path.basename(self.scan_path)) doc_path = os.path.join(base_path, group['name']+".group") + return doc_path def get_test_doc_path(self, path): @@ -94,6 +106,7 @@ def get_test_doc_path(self, path): base_path = os.path.join(self.conf.documentation_path, os.path.basename(self.scan_path)) relative_path = path.replace(self.scan_path, "") doc_path = os.path.splitext(base_path + relative_path)[0] + return doc_path def dump_output(self, content, doc_path): @@ -105,11 +118,22 @@ def dump_output(self, content, doc_path): - "doc_path (string): The path where the information should be dumped." """ if not os.path.exists(os.path.dirname(doc_path)): + DocGenerator.LOGGER.warning('Creating documentation folder') os.makedirs(os.path.dirname(doc_path)) - with open(doc_path + ".json", "w+") as outfile: - outfile.write(json.dumps(content, indent=4)) - with open(doc_path + ".yaml", "w+") as outfile: - outfile.write(yaml.dump(content)) + + try: + DocGenerator.LOGGER.debug(f"Writing {doc_path}.json") + with open(doc_path + ".json", "w+") as outfile: + outfile.write(json.dumps(content, indent=4)) + except IOError: + raise QAValueError(f"Cannot write in {doc_path}.json", DocGenerator.LOGGER.error) + + try: + DocGenerator.LOGGER.debug(f"Writing {doc_path}.yaml") + with open(doc_path + ".yaml", "w+") as outfile: + outfile.write(yaml.dump(content)) + except IOError: + raise QAValueError(f"Cannot write in {doc_path}.yaml", DocGenerator.LOGGER.error) def create_group(self, path, group_id): """ @@ -121,14 +145,14 @@ def create_group(self, path, group_id): """ self.__id_counter = self.__id_counter + 1 group = self.parser.parse_group(path, self.__id_counter, group_id) + if group: doc_path = self.get_group_doc_path(group) self.dump_output(group, doc_path) - logging.debug(f"New group file '{doc_path}' was created with ID:{self.__id_counter}") + DocGenerator.LOGGER.debug(f"New group file '{doc_path}' was created with ID:{self.__id_counter}") return self.__id_counter else: - warnings.warn(f"Content for {path} is empty, ignoring it", stacklevel=2) - logging.warning(f"Content for {path} is empty, ignoring it") + DocGenerator.LOGGER.warning(f"Content for {path} is empty, ignoring it") return None def create_test(self, path, group_id): @@ -141,19 +165,20 @@ def create_test(self, path, group_id): """ self.__id_counter = self.__id_counter + 1 test = self.parser.parse_test(path, self.__id_counter, group_id) + if test: if self.conf.mode == mode.DEFAULT: doc_path = self.get_test_doc_path(path) elif self.conf.mode == mode.SINGLE_TEST: doc_path = self.conf.documentation_path if self.print_test_info(test) is None: + # return self.dump_output(test, doc_path) - logging.debug(f"New documentation file '{doc_path}' was created with ID:{self.__id_counter}") + DocGenerator.LOGGER.debug(f"New documentation file '{doc_path}' was created with ID:{self.__id_counter}") return self.__id_counter else: - warnings.warn(f"Content for {path} is empty, ignoring it", stacklevel=2) - logging.warning(f"Content for {path} is empty, ignoring it") + DocGenerator.LOGGER.warning(f"Content for {path} is empty, ignoring it") return None def parse_folder(self, path, group_id): @@ -164,12 +189,13 @@ def parse_folder(self, path, group_id): - "group_id (string): The id of the group where the new elements belong." """ if not os.path.exists(path): - warnings.warn(f"Include path '{path}' doesn´t exist", stacklevel=2) - logging.warning(f"Include path '{path}' doesn´t exist") + DocGenerator.LOGGER.warning(f"Include path '{path}' doesn´t exist") return + if not self.is_valid_folder(path): - logging.debug(f"Ignoring files on '{path}'") + DocGenerator.LOGGER.debug(f"Ignoring files on '{path}'") return + (root, folders, files) = next(os.walk(path)) for file in files: if self.is_group_file(file): @@ -177,9 +203,11 @@ def parse_folder(self, path, group_id): if new_group: group_id = new_group break + for file in files: if self.is_valid_file(file): self.create_test(os.path.join(root, file), group_id) + for folder in folders: self.parse_folder(os.path.join(root, folder), group_id) @@ -188,7 +216,8 @@ def locate_test(self): brief: try to get the test path """ complete_test_name = f"{self.conf.test_name}.py" - logging.info(f"Looking for {complete_test_name}") + DocGenerator.LOGGER.info(f"Looking for {complete_test_name}") + for root, dirnames, filenames in os.walk(self.conf.project_path, topdown=True): for filename in filenames: if filename == complete_test_name: @@ -211,6 +240,7 @@ def print_test_info(self, test): for field in self.conf.module_info: for name, schema_field in field.items(): test_info[name] = test[schema_field] + for field in self.conf.test_info: for name, schema_field in field.items(): test_info[name] = test['tests'][0][schema_field] @@ -218,6 +248,7 @@ def print_test_info(self, test): # If output path does not exist, it is created if not os.path.exists(self.conf.documentation_path): os.mkdir(self.conf.documentation_path) + # Dump data with open(os.path.join(self.conf.documentation_path, f"{self.conf.test_name}.json"), 'w') as fp: fp.write(json.dumps(test_info, indent=4)) @@ -227,6 +258,7 @@ def print_test_info(self, test): for field in self.conf.module_info: for name, schema_field in field.items(): print(str(name)+": "+str(test[schema_field])) + for field in self.conf.test_info: for name, schema_field in field.items(): print(str(name)+": "+str(test['tests'][0][schema_field])) @@ -239,19 +271,21 @@ def run(self): Normal mode: expected behaviour, Single test mode: found the test required and par it """ if self.conf.mode == mode.DEFAULT: - logging.info("\nStarting documentation parsing") + DocGenerator.LOGGER.info("Starting documentation parsing") + DocGenerator.LOGGER.debug(f"Cleaning doc folder located in {self.conf.documentation_path}") clean_folder(self.conf.documentation_path) for path in self.conf.include_paths: self.scan_path = path - logging.debug(f"Going to parse files on '{path}'") + DocGenerator.LOGGER.debug(f"Going to parse files on '{path}'") self.parse_folder(path, self.__id_counter) + elif self.conf.mode == mode.SINGLE_TEST: - logging.info("\nStarting test documentation parsing") + DocGenerator.LOGGER.info("Starting test documentation parsing") self.test_path = self.locate_test() if self.test_path: - logging.debug(f"Parsing '{self.conf.test_name}'") + DocGenerator.LOGGER.debug(f"Parsing '{self.conf.test_name}'") self.create_test(self.test_path, 0) else: - logging.error(f"'{self.conf.test_name}' could not be found") + DocGenerator.LOGGER.error(f"'{self.conf.test_name}' could not be found") From 4b334bd6bc3b1ae4423eb7e5620dc78d815f1ace Mon Sep 17 00:00:00 2001 From: Luis Gonzalez Date: Wed, 15 Sep 2021 11:12:20 +0200 Subject: [PATCH 06/15] fix: `qa_docs` logger was not setting the level correctly". #1879 --- deps/wazuh_testing/wazuh_testing/scripts/qa_docs.py | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/deps/wazuh_testing/wazuh_testing/scripts/qa_docs.py b/deps/wazuh_testing/wazuh_testing/scripts/qa_docs.py index cdad9ef400..3aad05c3f3 100644 --- a/deps/wazuh_testing/wazuh_testing/scripts/qa_docs.py +++ b/deps/wazuh_testing/wazuh_testing/scripts/qa_docs.py @@ -10,7 +10,7 @@ from wazuh_testing.tools.exceptions import QAValueError VERSION = '0.1' -qadocs_logger = Logging(QADOCS_LOGGER, 'INFO', False) +qadocs_logger = Logging(QADOCS_LOGGER, 'INFO', True) CONFIG_PATH = os.path.join(os.path.dirname(os.path.realpath(__file__)), '..', 'qa_docs', 'config.yaml') OUTPUT_PATH = os.path.join(os.path.dirname(os.path.realpath(__file__)), '..', 'qa_docs', 'output') LOG_PATH = os.path.join(os.path.dirname(os.path.realpath(__file__)), '..', 'qa_docs', 'log') @@ -23,11 +23,10 @@ def set_qadocs_logging(logging_level): Args: logging_level (string): Level used to initialize the logger. """ - if not logging_level: - qadocs_logger = Logging(QADOCS_LOGGER) + if logging_level is None: qadocs_logger.disable() else: - qadocs_logger = Logging(QADOCS_LOGGER, logging_level, False) + qadocs_logger.set_level(logging_level) def validate_parameters(parameters): @@ -41,15 +40,13 @@ def validate_parameters(parameters): # Check if the directory where the tests are located exist if parameters.test_dir: if not os.path.exists(parameters.test_dir): - raise QAValueError(f"{parameters.test_dir} does not exist. Tests directory not found.", - qadocs_logger.error) + raise QAValueError(f"{parameters.test_dir} does not exist. Tests directory not found.", qadocs_logger.error) # Check that test_input name exists if parameters.test_input: doc_check = DocGenerator(Config(CONFIG_PATH, parameters.test_dir, '', parameters.test_input)) if doc_check.locate_test() is None: - raise QAValueError(f"{parameters.test_input} not found.", - qadocs_logger.error) + raise QAValueError(f"{parameters.test_input} not found.", qadocs_logger.error) qadocs_logger.debug('Input parameters validation successfully finished') From 7080e3f800c74d0806ac9ddd7b01f92d78b50bae Mon Sep 17 00:00:00 2001 From: Luis Gonzalez Date: Wed, 15 Sep 2021 11:25:24 +0200 Subject: [PATCH 07/15] add: now both output standard and log file working. #1879 --- deps/wazuh_testing/wazuh_testing/scripts/qa_docs.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/deps/wazuh_testing/wazuh_testing/scripts/qa_docs.py b/deps/wazuh_testing/wazuh_testing/scripts/qa_docs.py index 3aad05c3f3..ceb97542c7 100644 --- a/deps/wazuh_testing/wazuh_testing/scripts/qa_docs.py +++ b/deps/wazuh_testing/wazuh_testing/scripts/qa_docs.py @@ -1,5 +1,6 @@ import argparse import os +from datetime import datetime from wazuh_testing.qa_docs.lib.config import Config from wazuh_testing.qa_docs.lib.index_data import IndexData @@ -10,11 +11,12 @@ from wazuh_testing.tools.exceptions import QAValueError VERSION = '0.1' -qadocs_logger = Logging(QADOCS_LOGGER, 'INFO', True) CONFIG_PATH = os.path.join(os.path.dirname(os.path.realpath(__file__)), '..', 'qa_docs', 'config.yaml') OUTPUT_PATH = os.path.join(os.path.dirname(os.path.realpath(__file__)), '..', 'qa_docs', 'output') LOG_PATH = os.path.join(os.path.dirname(os.path.realpath(__file__)), '..', 'qa_docs', 'log') SEARCH_UI_PATH = os.path.join(os.path.dirname(os.path.realpath(__file__)), '..', 'qa_docs', 'search_ui') +qadocs_logger = Logging(QADOCS_LOGGER, 'INFO', True, os.path.join(LOG_PATH, + f"{datetime.today().strftime('%Y-%m-%d-%H:%M:%S')}-qa-docs.log")) def set_qadocs_logging(logging_level): From 82c95d61773dffccb4fa387e5146aa1a66008f01 Mon Sep 17 00:00:00 2001 From: Luis Gonzalez Date: Wed, 15 Sep 2021 11:50:21 +0200 Subject: [PATCH 08/15] refac: migrate logging from `logging` logger to custom `qa-docs` logger. #1879 --- .../wazuh_testing/qa_docs/lib/code_parser.py | 26 +++++++++---------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/deps/wazuh_testing/wazuh_testing/qa_docs/lib/code_parser.py b/deps/wazuh_testing/wazuh_testing/qa_docs/lib/code_parser.py index 6dee28e04b..3cb97fe819 100644 --- a/deps/wazuh_testing/wazuh_testing/qa_docs/lib/code_parser.py +++ b/deps/wazuh_testing/wazuh_testing/qa_docs/lib/code_parser.py @@ -11,10 +11,11 @@ import os import re import yaml + from wazuh_testing.qa_docs.lib.pytest_wrap import PytestWrap from wazuh_testing.qa_docs.lib.utils import remove_inexistent -import warnings -import logging +from wazuh_testing.qa_docs import QADOCS_LOGGER +from wazuh_testing.tools.logging import Logging INTERNAL_FIELDS = ['id', 'group_id', 'name'] STOP_FIELDS = ['tests', 'test_cases'] @@ -24,6 +25,8 @@ class CodeParser: """ brief: Class that parses the content of the test files. """ + LOGGER = Logging.get_logger(QADOCS_LOGGER) + def __init__(self, config): self.conf = config self.pytest = PytestWrap() @@ -70,13 +73,10 @@ def parse_comment(self, function): except Exception as inst: if hasattr(function, 'name'): - warnings.warn(f"Failed to parse comment of function '{function.name}'' from module {self.scan_file}. \ - Error: {inst}", stacklevel=2) - logging.warning(f"Failed to parse comment of function '{function.name}'' from module {self.scan_file}. \ - Error: {inst}") + CodeParser.LOGGER.warning(f"Failed to parse comment of function {function.name} " + "from module {self.scan_file}. Error: {inst}") else: - warnings.warn(f"Failed to parse comment of module {self.scan_file}. Error: {inst}", stacklevel=2) - logging.warning(f"Failed to parse comment of module {self.scan_file}. Error: {inst}") + CodeParser.LOGGER.warning(f"Failed to parse comment of module {self.scan_file}. Error: {inst}") doc = None return doc @@ -89,7 +89,7 @@ def parse_test(self, code_file, id, group_id): -"id (integer): Id of the new test document" -"group_id (integer): Id of the group where the new test document belongs." """ - logging.debug(f"Parsing test file '{code_file}'") + CodeParser.LOGGER.debug(f"Parsing test file '{code_file}'") self.scan_file = code_file with open(code_file) as fd: file_content = fd.read() @@ -117,8 +117,7 @@ def parse_test(self, code_file, id, group_id): functions_doc.append(function_doc) if not functions_doc: - warnings.warn(f"Module '{module_doc['name']}' doesn´t contain any test function", stacklevel=2) - logging.warning(f"Module '{module_doc['name']}' doesn´t contain any test function") + CodeParser.LOGGER.warning(f"Module '{module_doc['name']}' doesn´t contain any test function") else: module_doc['tests'] = functions_doc @@ -135,14 +134,13 @@ def parse_group(self, group_file, id, group_id): -"group_id (integer): Id of the group where the new group document belongs." """ MD_HEADER = "# " - logging.debug(f"Parsing group file '{group_file}'") + CodeParser.LOGGER.debug(f"Parsing group file '{group_file}'") with open(group_file) as fd: file_header = fd.readline() file_content = fd.read() if not file_header.startswith(MD_HEADER): - warnings.warn(f"Group file '{group_file}' doesn´t contain a valid header", stacklevel=2) - logging.warning(f"Group file '{group_file}' doesn´t contain a valid header") + CodeParser.LOGGER.warning(f"Group file '{group_file}' doesn´t contain a valid header") return None group_doc = {} From d0ea3912ce96bc3bfe8645bab7cdbe844f0ae482 Mon Sep 17 00:00:00 2001 From: Luis Gonzalez Date: Wed, 15 Sep 2021 11:58:58 +0200 Subject: [PATCH 09/15] refac: migrate logging from `logging` logger to custom `qa-docs` logger. #1879 --- .../wazuh_testing/qa_docs/lib/index_data.py | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/deps/wazuh_testing/wazuh_testing/qa_docs/lib/index_data.py b/deps/wazuh_testing/wazuh_testing/qa_docs/lib/index_data.py index 5b50f804a3..127ed6b717 100644 --- a/deps/wazuh_testing/wazuh_testing/qa_docs/lib/index_data.py +++ b/deps/wazuh_testing/wazuh_testing/qa_docs/lib/index_data.py @@ -11,14 +11,19 @@ import re import json import requests -import logging from elasticsearch import Elasticsearch, helpers +from wazuh_testing.qa_docs import QADOCS_LOGGER +from wazuh_testing.tools.logging import Logging +from wazuh_testing.tools.exceptions import QAValueError + class IndexData: """ brief: Class that indexes the data from JSON files into ElasticSearch. """ + LOGGER = Logging.get_logger(QADOCS_LOGGER) + def __init__(self, index, config): self.path = config.documentation_path self.index = index @@ -34,9 +39,8 @@ def test_connection(self): res = requests.get("http://localhost:9200/_cluster/health") if res.status_code == 200: return True - except Exception as e: - logging.exception(f"Connection error:\n{e}") - return False + except Exception as exception: + raise QAValueError(f"Connection error: {exception}", IndexData.LOGGER.error) def get_files(self): """ @@ -63,7 +67,7 @@ def remove_index(self): brief: Deletes an index. """ delete = self.es.indices.delete(index=self.index, ignore=[400, 404]) - logging.info(f'Delete index {self.index}\n {delete}\n') + IndexData.LOGGER.info(f'Delete index {self.index}\n {delete}\n') def run(self): """ @@ -74,7 +78,7 @@ def run(self): self.read_files_content(files) if self.test_connection(): self.remove_index() - logging.info("Indexing data...\n") + IndexData.LOGGER.info("Indexing data...\n") helpers.bulk(self.es, self.output, index=self.index) out = json.dumps(self.es.cluster.health(wait_for_status='yellow', request_timeout=1), indent=4) - logging.info(out) + IndexData.LOGGER.info(out) From d15979a3a708fb797adc07bbae96444998bb9b59 Mon Sep 17 00:00:00 2001 From: Luis Gonzalez Date: Wed, 15 Sep 2021 12:03:26 +0200 Subject: [PATCH 10/15] refac: migrate logging from `logging` logger to custom `qa-docs` logger in `PytestWrap` module. #1879 --- .../wazuh_testing/qa_docs/lib/pytest_wrap.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/deps/wazuh_testing/wazuh_testing/qa_docs/lib/pytest_wrap.py b/deps/wazuh_testing/wazuh_testing/qa_docs/lib/pytest_wrap.py index fc53fa3401..bbaeb357d7 100644 --- a/deps/wazuh_testing/wazuh_testing/qa_docs/lib/pytest_wrap.py +++ b/deps/wazuh_testing/wazuh_testing/qa_docs/lib/pytest_wrap.py @@ -8,7 +8,10 @@ """ import pytest -import logging + +from wazuh_testing.qa_docs import QADOCS_LOGGER +from wazuh_testing.tools.logging import Logging +from wazuh_testing.tools.exceptions import QAValueError class PytestPlugin: """ @@ -28,6 +31,8 @@ class PytestWrap: """ brief: Class that wraps the execution of pytest. """ + LOGGER = Logging.get_logger(QADOCS_LOGGER) + def __init__(self): self.plugin = PytestPlugin() @@ -38,7 +43,7 @@ def collect_test_cases(self, path): - "path (string): Path of the test file to extract the test cases. returns: "dictionary: The output of pytest parsed into a dictionary" """ - logging.debug(f"Running pytest to collect testcases for '{path}'") + PytestWrap.LOGGER.debug(f"Running pytest to collect testcases for '{path}'") pytest.main(['--collect-only', "-qq", path], plugins=[self.plugin]) output = {} for item in self.plugin.collected: From 1ffba3543b971a5ad0e086f862ac7e8ccb6422f3 Mon Sep 17 00:00:00 2001 From: Luis Gonzalez Date: Wed, 15 Sep 2021 12:20:55 +0200 Subject: [PATCH 11/15] refac: migrate logging from `logging` logger to custom `qa-docs` logger in `Sanity` module. #1879 Also, sanity new lines style and `qa-docs` paths within wazuh framework fixed. --- .../wazuh_testing/qa_docs/lib/pytest_wrap.py | 2 +- .../wazuh_testing/qa_docs/lib/sanity.py | 34 +++++++++++-------- .../wazuh_testing/scripts/qa_docs.py | 10 +++--- 3 files changed, 25 insertions(+), 21 deletions(-) diff --git a/deps/wazuh_testing/wazuh_testing/qa_docs/lib/pytest_wrap.py b/deps/wazuh_testing/wazuh_testing/qa_docs/lib/pytest_wrap.py index bbaeb357d7..ea7147a553 100644 --- a/deps/wazuh_testing/wazuh_testing/qa_docs/lib/pytest_wrap.py +++ b/deps/wazuh_testing/wazuh_testing/qa_docs/lib/pytest_wrap.py @@ -11,7 +11,7 @@ from wazuh_testing.qa_docs import QADOCS_LOGGER from wazuh_testing.tools.logging import Logging -from wazuh_testing.tools.exceptions import QAValueError + class PytestPlugin: """ diff --git a/deps/wazuh_testing/wazuh_testing/qa_docs/lib/sanity.py b/deps/wazuh_testing/wazuh_testing/qa_docs/lib/sanity.py index 8601eab5b1..dab53feee8 100644 --- a/deps/wazuh_testing/wazuh_testing/qa_docs/lib/sanity.py +++ b/deps/wazuh_testing/wazuh_testing/qa_docs/lib/sanity.py @@ -11,8 +11,11 @@ import re import json import ast -import logging + from wazuh_testing.qa_docs.lib.utils import check_existance +from wazuh_testing.qa_docs import QADOCS_LOGGER +from wazuh_testing.tools.logging import Logging +from wazuh_testing.tools.exceptions import QAValueError class Sanity(): @@ -20,6 +23,8 @@ class Sanity(): brief: Class in charge of performing a general sanity check on the already parsed documentation. It´s in charge of walk every documentation file, and every group file to dump the parsed documentation. """ + LOGGER = Logging.get_logger(QADOCS_LOGGER) + def __init__(self, config): self.conf = config self.files_regex = re.compile("^(?!.*group)test.*json$", re.IGNORECASE) @@ -39,8 +44,7 @@ def get_content(self, full_path): with open(full_path) as file: return json.load(file) except: - logging.error(f"Cannot load '{full_path}' file for sanity check") - raise Exception(f"Cannot load '{full_path}' file for sanity check") + raise QAValueError(f"Cannot load '{full_path}' file for sanity check", Sanity.LOGGER.error) def validate_fields(self, required_fields, available_fields): """ @@ -55,7 +59,7 @@ def validate_fields(self, required_fields, available_fields): for field in required_fields: if not check_existance(available_fields, field): self.add_report(f"Mandatory field '{field}' is missing in file {self.scan_file}") - logging.error(f"Mandatory field '{field}' is missing in file {self.scan_file}") + Sanity.LOGGER.error(f"Mandatory field '{field}' is missing in file {self.scan_file}") elif isinstance(required_fields[field], dict) or isinstance(required_fields[field], list): self.validate_fields(required_fields[field], available_fields) elif isinstance(required_fields, list): @@ -65,7 +69,7 @@ def validate_fields(self, required_fields, available_fields): else: if not check_existance(available_fields, field): self.add_report(f"Mandatory field '{field}' is missing in file {self.scan_file}") - logging.error(f"Mandatory field '{field}' is missing in file {self.scan_file}") + Sanity.LOGGER.error(f"Mandatory field '{field}' is missing in file {self.scan_file}") def validate_module_fields(self, fields): """ @@ -142,40 +146,40 @@ def print_report(self): """ brief: Makes a report with all the errors found, the coverage and the tags found. """ - print("") - print("During the sanity check:") + print("\nDuring the sanity check:") - print("") if self.error_reports: - print("The following errors were found:") + print("\nThe following errors were found:") for error in self.error_reports: print("- "+error) else: - print("No errors were found:") + print("\nNo errors were found:") if self.found_tags: - print("") - print("The following tags were found:") + print("\nThe following tags were found:") for tag in self.found_tags: print("- "+tag) - print("") modules_count = len(self.found_modules) tests_count = len(self.found_tests) tests_percentage = tests_count / self.project_tests * 100 - print(f"A total of {len(self.found_tests)} tests were found in {modules_count} modules") + print(f"\nA total of {len(self.found_tests)} tests were found in {modules_count} modules") print("A {:.2f}% from the tests of {} is covered.".format(tests_percentage, self.conf.project_path)) def run(self): """ brief: Runs a complete sanity check of each documentation file on the output folder. """ - logging.info("\nStarting documentation sanity check") + Sanity.LOGGER.info("Starting documentation sanity check") + for (root, *_, files) in os.walk(self.conf.documentation_path, topdown=True): files = list(filter(self.files_regex.match, files)) + for file in files: full_path = os.path.join(root, file) + print(full_path) content = self.get_content(full_path) + if content: self.scan_file = full_path self.validate_module_fields(content) diff --git a/deps/wazuh_testing/wazuh_testing/scripts/qa_docs.py b/deps/wazuh_testing/wazuh_testing/scripts/qa_docs.py index ceb97542c7..a1f814954f 100644 --- a/deps/wazuh_testing/wazuh_testing/scripts/qa_docs.py +++ b/deps/wazuh_testing/wazuh_testing/scripts/qa_docs.py @@ -11,10 +11,10 @@ from wazuh_testing.tools.exceptions import QAValueError VERSION = '0.1' -CONFIG_PATH = os.path.join(os.path.dirname(os.path.realpath(__file__)), '..', 'qa_docs', 'config.yaml') -OUTPUT_PATH = os.path.join(os.path.dirname(os.path.realpath(__file__)), '..', 'qa_docs', 'output') -LOG_PATH = os.path.join(os.path.dirname(os.path.realpath(__file__)), '..', 'qa_docs', 'log') -SEARCH_UI_PATH = os.path.join(os.path.dirname(os.path.realpath(__file__)), '..', 'qa_docs', 'search_ui') +CONFIG_PATH = os.path.join(os.path.dirname(os.path.dirname(os.path.realpath(__file__))), 'qa_docs', 'config.yaml') +OUTPUT_PATH = os.path.join(os.path.dirname(os.path.dirname(os.path.realpath(__file__))), 'qa_docs', 'output') +LOG_PATH = os.path.join(os.path.dirname(os.path.dirname(os.path.realpath(__file__))), 'qa_docs', 'log') +SEARCH_UI_PATH = os.path.join(os.path.dirname(os.path.dirname(os.path.realpath(__file__))), 'qa_docs', 'search_ui') qadocs_logger = Logging(QADOCS_LOGGER, 'INFO', True, os.path.join(LOG_PATH, f"{datetime.today().strftime('%Y-%m-%d-%H:%M:%S')}-qa-docs.log")) @@ -108,7 +108,7 @@ def main(): qadocs_logger.debug('qa-docs configuration loaded') elif args.sanity: - sanity = Sanity(Config(CONFIG_PATH)) + sanity = Sanity(Config(CONFIG_PATH, args.test_dir, OUTPUT_PATH)) qadocs_logger.debug('Running sanity check') sanity.run() From 1c91d050447811f5e162444bed95afcc399393c6 Mon Sep 17 00:00:00 2001 From: Luis Gonzalez Date: Wed, 15 Sep 2021 12:28:09 +0200 Subject: [PATCH 12/15] refac: migrate logging from `logging` logger to custom `qa-docs` logger in `utils` module. #1879 --- .../wazuh_testing/qa_docs/lib/utils.py | 26 +++++++++++++++---- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/deps/wazuh_testing/wazuh_testing/qa_docs/lib/utils.py b/deps/wazuh_testing/wazuh_testing/qa_docs/lib/utils.py index b280eb4f7f..521b4b1b5d 100644 --- a/deps/wazuh_testing/wazuh_testing/qa_docs/lib/utils.py +++ b/deps/wazuh_testing/wazuh_testing/qa_docs/lib/utils.py @@ -8,8 +8,11 @@ """ import os, shutil -import logging -import warnings + +from wazuh_testing.qa_docs import QADOCS_LOGGER +from wazuh_testing.tools.logging import Logging + +utils_logger = Logging.get_logger(QADOCS_LOGGER) def check_existance(source, key): """ @@ -47,6 +50,7 @@ def remove_inexistent(source, check_list, stop_list=None): for element in list(source): if stop_list and element in stop_list: break + if not check_existance(check_list, element): del source[element] elif isinstance(source[element], dict): @@ -113,6 +117,7 @@ def find_item(search_item, check): else: if search_item == item: return item + return None def check_missing_field(source, check): @@ -123,29 +128,38 @@ def check_missing_field(source, check): - "check (list): The expected keys." """ missing_filed = None + for source_field in source: if isinstance(source_field, dict): key = list(source_field.keys())[0] found_item = find_item(key, check) + if not found_item: print(f"Missing key {source_field}") return key + missing_filed = check_missing_field(source_field[key], found_item) + if missing_filed: return missing_filed + elif isinstance(source_field, list): missing_filed = None + for check_element in check: missing_filed = check_missing_field(source_field, check_element) if not missing_filed: break + if missing_filed: return source_field else: found_item = find_item(source_field, check) + if not found_item: print(f"Missing key {source_field}") return source_field + return missing_filed def clean_folder(folder): @@ -156,14 +170,16 @@ def clean_folder(folder): """ if not os.path.exists(folder): return - logging.debug(f"Going to clean '{folder}' folder") + + utils_logger.debug(f"Going to clean '{folder}' folder") + for filename in os.listdir(folder): file_path = os.path.join(folder, filename) + try: if os.path.isfile(file_path) or os.path.islink(file_path): os.unlink(file_path) elif os.path.isdir(file_path): shutil.rmtree(file_path) except Exception as e: - warnings.warn(f"Failed to delete {file_path}. Reason: {e}") - logging.error(f"Failed to delete {file_path}. Reason: {e}") + utils_logger.error(f"Failed to delete {file_path}. Reason: {e}") From cb21617244231e5bd8ab3a170e718f78a61b2b9c Mon Sep 17 00:00:00 2001 From: Luis Gonzalez Date: Wed, 15 Sep 2021 12:33:02 +0200 Subject: [PATCH 13/15] fix: `-t` option now working. #1879 It only loads the config file within a Config instance. --- deps/wazuh_testing/wazuh_testing/scripts/qa_docs.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/wazuh_testing/wazuh_testing/scripts/qa_docs.py b/deps/wazuh_testing/wazuh_testing/scripts/qa_docs.py index a1f814954f..10b36a25ee 100644 --- a/deps/wazuh_testing/wazuh_testing/scripts/qa_docs.py +++ b/deps/wazuh_testing/wazuh_testing/scripts/qa_docs.py @@ -104,7 +104,7 @@ def main(): elif args.test_config: qadocs_logger.debug('Loading qa-docs configuration') - Config(CONFIG_PATH) + Config(CONFIG_PATH, args.test_dir) qadocs_logger.debug('qa-docs configuration loaded') elif args.sanity: From 86e5045beb49f8e91dbb42b6e59f8d3164a57523 Mon Sep 17 00:00:00 2001 From: Luis Gonzalez Date: Thu, 16 Sep 2021 09:32:00 +0200 Subject: [PATCH 14/15] style: improve readability and clarity. --- .../wazuh_testing/qa_docs/doc_generator.py | 16 ++++----- .../wazuh_testing/qa_docs/lib/code_parser.py | 4 +-- .../wazuh_testing/qa_docs/lib/config.py | 34 +++++++++---------- 3 files changed, 27 insertions(+), 27 deletions(-) diff --git a/deps/wazuh_testing/wazuh_testing/qa_docs/doc_generator.py b/deps/wazuh_testing/wazuh_testing/qa_docs/doc_generator.py index 4f32da42d7..144d70dd12 100644 --- a/deps/wazuh_testing/wazuh_testing/qa_docs/doc_generator.py +++ b/deps/wazuh_testing/wazuh_testing/qa_docs/doc_generator.py @@ -46,7 +46,7 @@ def is_valid_folder(self, path): """ for regex in self.ignore_regex: if regex.match(path): - DocGenerator.LOGGER.warning(f"Folder validation: {regex} not matchin with {path}") + DocGenerator.LOGGER.warning(f"Folder validation: {regex} not matching with {path}") return False return True @@ -62,12 +62,12 @@ def is_valid_file(self, file): for regex in self.ignore_regex: if regex.match(file): - DocGenerator.LOGGER.warning(f"File validation: {regex} not matchin with {file}") + DocGenerator.LOGGER.warning(f"File validation: {regex} not matching with {file}") return False for regex in self.include_regex: if regex.match(file): - DocGenerator.LOGGER.warning(f"File validation: {regex} not matchin with {file}") + DocGenerator.LOGGER.warning(f"File validation: {regex} not matching with {file}") return True return False @@ -118,20 +118,20 @@ def dump_output(self, content, doc_path): - "doc_path (string): The path where the information should be dumped." """ if not os.path.exists(os.path.dirname(doc_path)): - DocGenerator.LOGGER.warning('Creating documentation folder') + DocGenerator.LOGGER.debug('Creating documentation folder') os.makedirs(os.path.dirname(doc_path)) try: DocGenerator.LOGGER.debug(f"Writing {doc_path}.json") - with open(doc_path + ".json", "w+") as outfile: - outfile.write(json.dumps(content, indent=4)) + with open(doc_path + ".json", "w+") as out_file: + out_file.write(json.dumps(content, indent=4)) except IOError: raise QAValueError(f"Cannot write in {doc_path}.json", DocGenerator.LOGGER.error) try: DocGenerator.LOGGER.debug(f"Writing {doc_path}.yaml") - with open(doc_path + ".yaml", "w+") as outfile: - outfile.write(yaml.dump(content)) + with open(doc_path + ".yaml", "w+") as out_file: + out_file.write(yaml.dump(content)) except IOError: raise QAValueError(f"Cannot write in {doc_path}.yaml", DocGenerator.LOGGER.error) diff --git a/deps/wazuh_testing/wazuh_testing/qa_docs/lib/code_parser.py b/deps/wazuh_testing/wazuh_testing/qa_docs/lib/code_parser.py index 3cb97fe819..981f6b99c2 100644 --- a/deps/wazuh_testing/wazuh_testing/qa_docs/lib/code_parser.py +++ b/deps/wazuh_testing/wazuh_testing/qa_docs/lib/code_parser.py @@ -73,10 +73,10 @@ def parse_comment(self, function): except Exception as inst: if hasattr(function, 'name'): - CodeParser.LOGGER.warning(f"Failed to parse comment of function {function.name} " + CodeParser.LOGGER.warning(f"Failed to parse test documentation in {function.name} " "from module {self.scan_file}. Error: {inst}") else: - CodeParser.LOGGER.warning(f"Failed to parse comment of module {self.scan_file}. Error: {inst}") + CodeParser.LOGGER.warning(f"Failed to parse module documentation in {self.scan_file}. Error: {inst}") doc = None return doc diff --git a/deps/wazuh_testing/wazuh_testing/qa_docs/lib/config.py b/deps/wazuh_testing/wazuh_testing/qa_docs/lib/config.py index d8cd7e0092..f711c83960 100644 --- a/deps/wazuh_testing/wazuh_testing/qa_docs/lib/config.py +++ b/deps/wazuh_testing/wazuh_testing/qa_docs/lib/config.py @@ -74,7 +74,7 @@ def __read_test_info(self): Test info: - test_wazuh_min_version: wazuh_min_version """ - Config.LOGGER.debug('Reading test info from config file') + Config.LOGGER.debug('Reading test info from the config file') if 'Test info' in self._config_data: self.test_info = self._config_data['Test info'] else: @@ -116,7 +116,7 @@ def __read_include_paths(self): # Will be replaced by --type --module and --test , so you can run what you need if not 'Include paths' in self._config_data: - raise QAValueError('Config include paths are empty', Config.LOGGER.error) + raise QAValueError('The include paths of the configuration file are empty', Config.LOGGER.error) include_paths = self._config_data['Include paths'] @@ -127,10 +127,10 @@ def __read_include_regex(self): """ brief: Reads from the config file the regexes used to identify test files. """ - Config.LOGGER.debug('Reading the regular expressions to include files from config file') + Config.LOGGER.debug('Reading the regular expressions from the config file to include test files') if not 'Include regex' in self._config_data: - raise QAValueError('Config include regex is empty', Config.LOGGER.error) + raise QAValueError('The include regex field is empty in the config file', Config.LOGGER.error) self.include_regex = self._config_data['Include regex'] @@ -138,10 +138,10 @@ def __read_group_files(self): """ brief: Reads from the config file the file name to be identified with a group. """ - Config.LOGGER.debug('Reading group files from config file') + Config.LOGGER.debug('Reading group files from the config file') if not 'Group files' in self._config_data: - raise QAValueError('Config include paths are empty', Config.LOGGER.error) + raise QAValueError('Group files field is empty in config file', Config.LOGGER.error) self.group_files = self._config_data['Group files'] @@ -149,10 +149,10 @@ def __read_function_regex(self): """ brief: Reads from the config file the regexes used to identify a test method. """ - Config.LOGGER.debug('Reading the regular expressions to include test methods from config file') + Config.LOGGER.debug('Reading the regular expressions to include test methods from the config file') if not 'Function regex' in self._config_data: - raise QAValueError('Config function regex is empty', Config.LOGGER.error) + raise QAValueError('The function regex field is empty in the config file', Config.LOGGER.error) self.function_regex = self._config_data['Function regex'] @@ -160,7 +160,7 @@ def __read_ignore_paths(self): """ brief: Reads from the config file all the paths to be excluded from the parsing. """ - Config.LOGGER.debug('Reading the paths to be ignored from config file') + Config.LOGGER.debug('Reading the paths to be ignored from the config file') if 'Ignore paths' in self._config_data: ignore_paths = self._config_data['Ignore paths'] @@ -172,15 +172,15 @@ def __read_module_fields(self): """ brief: Reads from the config file the optional and mandatory fields for the test module. """ - Config.LOGGER.debug('Reading mandatory and optional module fields from config file') + Config.LOGGER.debug('Reading mandatory and optional module fields from the config file') if not 'Module' in self._config_data['Output fields']: - raise QAValueError('Config output module fields is missing', Config.LOGGER.error) + raise QAValueError('Module fields are missing in the config file', Config.LOGGER.error) module_fields = self._config_data['Output fields']['Module'] if not 'Mandatory' in module_fields and not 'Optional' in module_fields: - raise QAValueError('Config output module fields are empty', Config.LOGGER.error) + raise QAValueError('Mandatory module fields are missing in the config file', Config.LOGGER.error) if 'Mandatory' in module_fields: self.module_fields.mandatory = module_fields['Mandatory'] @@ -192,15 +192,15 @@ def __read_test_fields(self): """ brief: Reads from the config file the optional and mandatory fields for the test functions. """ - Config.LOGGER.debug('Reading mandatory and optional test fields from config file') + Config.LOGGER.debug('Reading mandatory and optional test fields from the config file') if not 'Test' in self._config_data['Output fields']: - raise QAValueError('Config output test fields is missing', Config.LOGGER.error) + raise QAValueError('Test fields are missing in the config file', Config.LOGGER.error) test_fields = self._config_data['Output fields']['Test'] if not 'Mandatory' in test_fields and not 'Optional' in test_fields: - raise QAValueError('Config output test fields are empty', Config.LOGGER.error) + raise QAValueError('Mandatory module fields are missing in the config file', Config.LOGGER.error) if 'Mandatory' in test_fields: self.test_fields.mandatory = test_fields['Mandatory'] @@ -213,7 +213,7 @@ def __read_output_fields(self): brief: Reads all the mandatory and optional fields. """ if not 'Output fields' in self._config_data: - raise QAValueError('Config output fields is missing', Config.LOGGER.error) + raise QAValueError('Documentation schema not defined in the config file', Config.LOGGER.error) self.__read_module_fields() self.__read_test_fields() @@ -222,7 +222,7 @@ def __read_test_cases_field(self): """ brief: Reads from the configuration file the key to identify a Test Case list. """ - Config.LOGGER.debug('Reading Test Case key from config file') + Config.LOGGER.debug('Reading Test Case key from the config file') if 'Test cases field' in self._config_data: self.test_cases_field = self._config_data['Test cases field'] From 9e21347fdd74c17953f57a11cdf67be1d85b336f Mon Sep 17 00:00:00 2001 From: Luis Gonzalez Date: Thu, 16 Sep 2021 10:03:12 +0200 Subject: [PATCH 15/15] style: improve readability and clarity in `pytest_wrap.py` and `sanity.py` --- .../wazuh_testing/qa_docs/lib/pytest_wrap.py | 2 +- deps/wazuh_testing/wazuh_testing/qa_docs/lib/sanity.py | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/deps/wazuh_testing/wazuh_testing/qa_docs/lib/pytest_wrap.py b/deps/wazuh_testing/wazuh_testing/qa_docs/lib/pytest_wrap.py index ea7147a553..fb3876e992 100644 --- a/deps/wazuh_testing/wazuh_testing/qa_docs/lib/pytest_wrap.py +++ b/deps/wazuh_testing/wazuh_testing/qa_docs/lib/pytest_wrap.py @@ -43,7 +43,7 @@ def collect_test_cases(self, path): - "path (string): Path of the test file to extract the test cases. returns: "dictionary: The output of pytest parsed into a dictionary" """ - PytestWrap.LOGGER.debug(f"Running pytest to collect testcases for '{path}'") + PytestWrap.LOGGER.debug(f"Running pytest to collect test cases for '{path}'") pytest.main(['--collect-only', "-qq", path], plugins=[self.plugin]) output = {} for item in self.plugin.collected: diff --git a/deps/wazuh_testing/wazuh_testing/qa_docs/lib/sanity.py b/deps/wazuh_testing/wazuh_testing/qa_docs/lib/sanity.py index dab53feee8..3e9ea2d50e 100644 --- a/deps/wazuh_testing/wazuh_testing/qa_docs/lib/sanity.py +++ b/deps/wazuh_testing/wazuh_testing/qa_docs/lib/sanity.py @@ -58,8 +58,8 @@ def validate_fields(self, required_fields, available_fields): if isinstance(required_fields, dict): for field in required_fields: if not check_existance(available_fields, field): - self.add_report(f"Mandatory field '{field}' is missing in file {self.scan_file}") - Sanity.LOGGER.error(f"Mandatory field '{field}' is missing in file {self.scan_file}") + self.add_report(f"Mandatory field '{field}' is missing in the file {self.scan_file}") + Sanity.LOGGER.error(f"Mandatory field '{field}' is missing in the file {self.scan_file}") elif isinstance(required_fields[field], dict) or isinstance(required_fields[field], list): self.validate_fields(required_fields[field], available_fields) elif isinstance(required_fields, list): @@ -68,8 +68,8 @@ def validate_fields(self, required_fields, available_fields): self.validate_fields(field, available_fields) else: if not check_existance(available_fields, field): - self.add_report(f"Mandatory field '{field}' is missing in file {self.scan_file}") - Sanity.LOGGER.error(f"Mandatory field '{field}' is missing in file {self.scan_file}") + self.add_report(f"Mandatory field '{field}' is missing in the file {self.scan_file}") + Sanity.LOGGER.error(f"Mandatory field '{field}' is missing the in file {self.scan_file}") def validate_module_fields(self, fields): """