Esempio n. 1
0
    def __init__(self,
                 path: str,
                 tests_path: str,
                 inventory: str or None,
                 modules=None,
                 cmd_env=None,
                 system_environment=None,
                 resources=None,
                 output_format=None,
                 filter_list=None) -> None:
        # singletons init should be done before services, as singletons maybe used there
        FiltersHolder(filter_list)
        StepFactory(modules)

        self.tests_path = tests_path
        self.path = path
        self._compose = DockerCompose(resources)
        self.parser = Parser(path, inventory)
        self.holder = VariablesHolder(
            path,
            system_environment=system_environment,
            inventory_vars=self.parser.read_inventory(),
            cmd_env=cmd_env,
            resources=resources)
        if output_format:
            logger.log_storage = LogStorage(output_format)
Esempio n. 2
0
 def __init__(self,
              path: str,
              tests_path: str,
              inventory: str or None,
              modules=None,
              environment=None,
              resources=None) -> None:
     if modules is None:
         modules = []
     self.environment = environment if environment is not None else {}
     self.tests_path = tests_path
     self.path = path
     self.inventory = inventory
     self.all_includes = []
     self.modules = merge_two_dicts(
         prepare_modules(modules, step.registered_steps),
         step.registered_steps)
     self._compose = DockerCompose(resources)
Esempio n. 3
0
 def __init__(self, **kwargs) -> None:
     """
     :param kwargs: resources_dir param must exist for the initial load
     """
     super().__init__()
     # TODO find all submodules of catcher.modules.Module dynamically!
     self._modules = {
         'compose': DockerCompose(kwargs['resources_dir']),
         'requirements': Requirements(kwargs['resources_dir'])
     }
     debug('Loaded modules: {}'.format(list(self._modules.keys())))
Esempio n. 4
0
 def __init__(self,
              path: str,
              tests_path: str,
              inventory: str or None,
              modules=None,
              environment=None,
              system_environment=None,
              resources=None,
              output_format=None) -> None:
     if modules is None:
         modules = []
     self.environment = environment if environment is not None else {}
     self.system_vars = system_environment if system_environment is not None else {}
     self.tests_path = tests_path
     self.path = path
     self.inventory = inventory
     self.all_includes = []
     self.modules = merge_two_dicts(
         prepare_modules(modules, step.registered_steps),
         step.registered_steps)
     self._compose = DockerCompose(resources)
     self.resources = resources
     if output_format:
         logger.log_storage = LogStorage(output_format)
Esempio n. 5
0
class Runner:
    def __init__(self,
                 path: str,
                 tests_path: str,
                 inventory: str or None,
                 modules=None,
                 environment=None,
                 resources=None) -> None:
        if modules is None:
            modules = []
        self.environment = environment if environment is not None else {}
        self.tests_path = tests_path
        self.path = path
        self.inventory = inventory
        self.all_includes = []
        self.modules = merge_two_dicts(
            prepare_modules(modules, step.registered_steps),
            step.registered_steps)
        self._compose = DockerCompose(resources)

    def run_tests(self) -> bool:
        try:
            self._compose.up()
            variables = {}
            if self.inventory is not None:
                variables = read_source_file(self.inventory)
                variables['INVENTORY'] = get_filename(self.inventory)
                variables = try_get_object(fill_template_str(
                    variables, {}))  # fill env vars
            variables['CURRENT_DIR'] = self.path
            test_files = get_files(self.tests_path)
            results = []
            for file in test_files:
                self.all_includes = []
                try:
                    variables['TEST_NAME'] = file
                    test = self.prepare_test(file, variables)
                    test.run()
                    results.append(True)
                    info('Test ' + file + ' passed.')
                except Exception as e:
                    warning('Test ' + file + ' failed: ' + str(e))
                    results.append(False)
            return all(results)
        finally:
            self._compose.down()

    def prepare_test(self,
                     file: str,
                     variables: dict,
                     override_vars: None or dict = None) -> Test:
        body = read_source_file(file)
        registered_includes = self.process_includes(body.get('include', []),
                                                    variables)
        variables = merge_two_dicts(variables, body.get(
            'variables', {}))  # override variables with test's variables
        if override_vars:  # TODO warn when overriding inventory vars?
            variables = merge_two_dicts(variables, override_vars)
        return Test(self.path, registered_includes, variables,
                    body.get('config', {}), body.get('steps', []),
                    self.modules, self.environment)

    def process_includes(
            self,
            includes: list or str or dict,
            variables: dict,
            registered_includes: dict or None = None) -> (dict, dict):
        if registered_includes is None:
            registered_includes = {}
        if isinstance(includes, str) or isinstance(includes,
                                                   dict):  # single include
            self.process_include(includes, registered_includes, variables)
        elif isinstance(includes, list):  # an array of includes
            for i in includes:  # run all includes and save includes with alias
                variables = self.process_include(i, registered_includes,
                                                 variables)
        return registered_includes

    def process_include(self, include_file: str or dict, includes: dict,
                        variables: dict) -> dict:
        include_file = self.path_from_root(include_file)
        self.check_circular(include_file)
        include = Include(**include_file)
        self.all_includes.append(include)
        include.test = self.prepare_test(include.file, variables,
                                         include.variables)
        if include.alias is not None:
            includes[include.alias] = include.test
        if include.run_on_include:
            try:
                return include.test.run()
            except Exception as e:
                if not include.ignore_errors:
                    raise Exception('Include ' + include.file + ' failed: ' +
                                    str(e))
        return include.test.variables

    def check_circular(self, current_include: dict):
        path = current_include['file']
        if [include for include in self.all_includes if include.file == path]:
            raise Exception('Circular dependencies for ' + path)

    def path_from_root(self, include_file: str or dict) -> dict:
        if isinstance(include_file, str):
            return {'file': join(self.path, include_file)}
        else:
            include_file['file'] = join(self.path, include_file['file'])
            return include_file
Esempio n. 6
0
class Runner:
    def __init__(self,
                 path: str,
                 tests_path: str,
                 inventory: str or None,
                 modules=None,
                 environment=None,
                 system_environment=None,
                 resources=None,
                 output_format=None) -> None:
        if modules is None:
            modules = []
        self.environment = environment if environment is not None else {}
        self.system_vars = system_environment if system_environment is not None else {}
        self.tests_path = tests_path
        self.path = path
        self.inventory = inventory
        self.all_includes = []
        self.modules = merge_two_dicts(
            prepare_modules(modules, step.registered_steps),
            step.registered_steps)
        self._compose = DockerCompose(resources)
        self.resources = resources
        if output_format:
            logger.log_storage = LogStorage(output_format)

    def run_tests(self) -> bool:
        try:
            self._compose.up()
            if self.system_vars:
                debug('Use system variables: ' +
                      str(list(self.system_vars.keys())))
                variables = self.system_vars
            else:
                variables = {}
            if self.inventory is not None:
                inv_vars = read_source_file(self.inventory)
                inv_vars['INVENTORY'] = get_filename(self.inventory)
                variables = try_get_object(
                    fill_template_str(inv_vars, variables))  # fill env vars
            variables['CURRENT_DIR'] = self.path
            variables[
                'RESOURCES_DIR'] = self.resources or self.path + '/resources'
            test_files = get_files(self.tests_path)
            results = []
            for file in test_files:
                self.all_includes = []
                try:
                    variables['TEST_NAME'] = file
                    test = self.prepare_test(file, variables)
                    logger.log_storage.test_start(file)
                    test.run()
                    results.append(True)
                    info('Test ' + file + ' passed.')
                    logger.log_storage.test_end(file, True)
                except Exception as e:
                    warning('Test ' + file + ' failed: ' + str(e))
                    results.append(False)
                    logger.log_storage.test_end(file, False, str(e))
            return all(results)
        finally:
            logger.log_storage.write_report(self.path)
            self._compose.down()

    def prepare_test(self,
                     file: str,
                     variables: dict,
                     override_vars: None or dict = None) -> Test:
        body = read_source_file(file)
        registered_includes = self.process_includes(body.get('include', []),
                                                    variables)
        variables = merge_two_dicts(variables, body.get(
            'variables', {}))  # override variables with test's variables
        if override_vars:
            override_keys = report_override(variables, override_vars)
            if override_keys:
                debug('Overriding these variables: ' + str(override_keys))
            variables = merge_two_dicts(variables, override_vars)
        return Test(
            self.path,
            registered_includes,
            deepcopy(variables),  # each test has independent variables
            body.get('config', {}),
            body.get('steps', []),
            self.modules,
            self.environment)

    def process_includes(
            self,
            includes: list or str or dict,
            variables: dict,
            registered_includes: dict or None = None) -> (dict, dict):
        if registered_includes is None:
            registered_includes = {}
        if isinstance(includes, str) or isinstance(includes,
                                                   dict):  # single include
            self.process_include(includes, registered_includes, variables)
        elif isinstance(includes, list):  # an array of includes
            for i in includes:  # run all includes and save includes with alias
                variables = self.process_include(i, registered_includes,
                                                 variables)
        return registered_includes

    def process_include(self, include_file: str or dict, includes: dict,
                        variables: dict) -> dict:
        include_file = self.path_from_root(include_file)
        self.check_circular(include_file)
        include = Include(**include_file)
        self.all_includes.append(include)
        include.test = self.prepare_test(include.file, variables,
                                         include.variables)
        if include.alias is not None:
            includes[include.alias] = include.test
        if include.run_on_include:
            try:
                logger.log_storage.test_start(include_file['file'],
                                              test_type='include')
                debug('Run include: ' + str(include.test))
                res = include.test.run()
                logger.log_storage.test_end(include.test.path,
                                            True,
                                            res,
                                            test_type='include')
                return res
            except Exception as e:
                logger.log_storage.test_end(include.test.path,
                                            False,
                                            str(e),
                                            test_type='include')
                if not include.ignore_errors:
                    raise Exception('Include ' + include.file + ' failed: ' +
                                    str(e))
        return include.test.variables

    def check_circular(self, current_include: dict):
        path = current_include['file']
        if [include for include in self.all_includes if include.file == path]:
            raise Exception('Circular dependencies for ' + path)

    def path_from_root(self, include_file: str or dict) -> dict:
        if isinstance(include_file, str):
            return {'file': join(self.path, include_file)}
        else:
            include_file['file'] = join(self.path, include_file['file'])
            return include_file
Esempio n. 7
0
class Runner:
    def __init__(self,
                 path: str,
                 tests_path: str,
                 inventory: str or None,
                 modules=None,
                 cmd_env=None,
                 system_environment=None,
                 resources=None,
                 output_format=None,
                 filter_list=None) -> None:
        # singletons init should be done before services, as singletons maybe used there
        FiltersHolder(filter_list)
        StepFactory(modules)

        self.tests_path = tests_path
        self.path = path
        self._compose = DockerCompose(resources)
        self.parser = Parser(path, inventory)
        self.holder = VariablesHolder(
            path,
            system_environment=system_environment,
            inventory_vars=self.parser.read_inventory(),
            cmd_env=cmd_env,
            resources=resources)
        if output_format:
            logger.log_storage = LogStorage(output_format)

    def run_tests(self, output: str = 'full') -> bool:
        """
        Run the testcase
        :param output: 'full' - all output possible. 'limited' - only test end report & summary. 'final' - only summary.
        """
        try:
            self._compose.up()
            results = []
            for parse_result in self.parser.read_tests(self.tests_path):
                if parse_result.should_run:  # parse successful
                    variables = self.holder.variables  # each test has it's own copy of global variables
                    variables[
                        'TEST_NAME'] = parse_result.test.file  # variables are shared between test and includes
                    with OptionalOutput(output == 'final'):
                        for include in parse_result.run_on_include:  # run all includes before the main test.
                            self._run_test(include,
                                           variables,
                                           output=output,
                                           test_type='include')
                        result = self._run_test(parse_result.test,
                                                variables,
                                                output=output)
                        results.append(result)
                        self._run_finally(parse_result.test, result)
                else:  # parse failed (dependency/parsing problem)
                    warning('Test ' +
                            cut_path(self.tests_path, parse_result.test) +
                            logger.red(' failed: ') +
                            str(parse_result.parse_error))
                    logger.log_storage.test_parse_fail(
                        parse_result.test, parse_result.parse_error)
                    results.append(False)
            return all(results)
        finally:
            logger.log_storage.write_report(join(self.path, 'reports'))
            logger.log_storage.print_summary(self.tests_path)
            self._compose.down()

    def _run_test(self,
                  test: Test,
                  global_variables: dict,
                  output: str = 'full',
                  test_type='test') -> bool:
        try:
            self.holder.prepare_variables(test, global_variables)
            logger.log_storage.test_start(test.file, test_type=test_type)
            test.check_ignored()
            with OptionalOutput(output == 'limited'):
                test.run()
            info(test_type.capitalize() + ' ' +
                 cut_path(self.tests_path, test.file) +
                 logger.green(' passed.'))
            logger.log_storage.test_end(test.file, True, test_type=test_type)
            return True
        except SkipException:
            info(test_type.capitalize() + ' ' +
                 cut_path(self.tests_path, test.file) +
                 logger.yellow(' skipped.'))
            logger.log_storage.test_end(test.file,
                                        True,
                                        end_comment='Skipped',
                                        test_type=test_type)
            return True
        except Exception as e:
            warning(test_type.capitalize() + ' ' +
                    cut_path(self.tests_path, test.file) +
                    logger.red(' failed: ') + str(e))
            debug(traceback.format_exc())
            logger.log_storage.test_end(test.file,
                                        False,
                                        str(e),
                                        test_type=test_type)
            return False

    def _run_finally(self, test, result: bool):
        if test and test.final:
            logger.log_storage.test_start(test.file,
                                          test_type='{}_cleanup'.format(
                                              test.file))
            try:
                test.run_finally(result)
                info('Test ' + cut_path(self.tests_path, test.file) +
                     ' [cleanup] ' + logger.green(' passed.'))
                logger.log_storage.test_end(test.file,
                                            True,
                                            test_type='{} [cleanup]'.format(
                                                test.file))
            except Exception as e:
                warning('Test ' + cut_path(self.tests_path, test.file) +
                        ' [cleanup] ' + logger.red(' failed: ') + str(e))
                debug(traceback.format_exc())
                logger.log_storage.test_end(test.file,
                                            False,
                                            test_type='{} [cleanup]'.format(
                                                test.file))