Exemple #1
0
    def run(self):
        #############################################################################################
        # Get environment
        #############################################################################################
        env = self.env

        # ToDo: Keep this in directive!!!
        collapse = self.options.get("collapse", None)
        if isinstance(collapse, str) and len(collapse) > 0:
            if collapse.upper() in ["TRUE", 1, "YES"]:
                collapse = True
            elif collapse.upper() in ["FALSE", 0, "NO"]:
                collapse = False
            else:
                raise Exception("collapse attribute must be true or false")
        else:
            collapse = getattr(env.app.config, "needs_collapse_details", None)

        hide = True if "hide" in self.options.keys() else False

        id = self.options.get("id", None)
        content = "\n".join(self.content)
        status = self.options.get("status", None)
        tags = self.options.get("tags", '')
        style = self.options.get("style", None)
        layout = self.options.get("layout", '')
        template = self.options.get("template", None)
        pre_template = self.options.get("pre_template", None)
        post_template = self.options.get("post_template", None)
        duration = self.options.get("duration", None)
        completion = self.options.get("completion", None)

        need_extra_options = {'duration': duration, 'completion': completion}
        for extra_link in env.config.needs_extra_links:
            need_extra_options[extra_link['option']] = self.options.get(
                extra_link['option'], '')

        for extra_option in env.config.needs_extra_options.keys():
            need_extra_options[extra_option] = self.options.get(
                extra_option, '')

        return add_need(env.app,
                        self.state,
                        self.docname,
                        self.lineno,
                        need_type=self.name,
                        title=self.trimmed_title,
                        id=id,
                        content=content,
                        status=status,
                        tags=tags,
                        hide=hide,
                        template=template,
                        pre_template=pre_template,
                        post_template=post_template,
                        collapse=collapse,
                        style=style,
                        layout=layout,
                        **need_extra_options)
Exemple #2
0
    def run(self):
        self.prepare_basic_options()
        self.load_test_file()

        suite_name = self.options.get('suite', None)
        if suite_name is None:
            raise TestReportInvalidOption('Suite not given!')

        suite = None
        for suite_obj in self.results:
            if suite_obj['name'] == suite_name:
                suite = suite_obj
                break

        if suite is None:
            raise TestReportInvalidOption(
                'Suite {} not found in test file {}'.format(
                    suite_name, self.test_file))

        cases = suite['tests']

        passed = suite['passed']
        skipped = suite['skips']
        errors = suite['errors']
        failed = suite['failures']

        main_section = []
        docname = self.state.document.settings.env.docname
        main_section += add_need(self.app,
                                 self.state,
                                 docname,
                                 self.lineno,
                                 need_type=self.need_type,
                                 title=self.test_name,
                                 id=self.test_id,
                                 content=self.test_content,
                                 links=self.test_links,
                                 tags=self.test_tags,
                                 status=self.test_status,
                                 collapse=self.collapse,
                                 file=self.test_file_given,
                                 suite=suite['name'],
                                 cases=cases,
                                 passed=passed,
                                 skipped=skipped,
                                 failed=failed,
                                 errors=errors)

        if 'auto_cases' in self.options.keys():
            for case in suite['testcases']:
                case_id = self.test_id
                case_id += '_' + hashlib.sha1(
                    case['classname'].encode("UTF-8") +
                    case['name'].encode("UTF-8")).hexdigest().upper()[:5]

                options = self.options
                options['case'] = case['name']
                options['classname'] = case['classname']
                options['id'] = case_id

                if 'links' not in self.options:
                    options['links'] = self.test_id
                elif self.test_id not in options['links']:
                    options['links'] = options['links'] + ';' + self.test_id

                arguments = [case['name']]
                case_directive = sphinxcontrib.test_reports.directives.test_case.TestCaseDirective(
                    self.app.config.tr_case[0],
                    arguments,
                    options,
                    '',
                    self.lineno,  # no content
                    self.content_offset,
                    self.block_text,
                    self.state,
                    self.state_machine)

                main_section += case_directive.run()

        return main_section
    def run(self):
        docname = self.state.document.settings.env.docname
        app = self.env.app
        needs_services = self.env.app.needs_services

        service_name = self.arguments[0]
        service = needs_services.get(service_name)
        section = []

        if "debug" not in self.options:
            service_data = service.request(self.options)
            for datum in service_data:
                options = {}

                try:
                    content = datum["content"].split("\n")
                except KeyError:
                    content = []

                content.extend(self.content)

                if "type" not in datum.keys():
                    # Use the first defined type, if nothing got defined by service (should not be the case)
                    need_type = self.env.app.config.needs_types[0]["directive"]
                else:
                    need_type = datum["type"]
                    del datum["type"]

                if "title" not in datum.keys():
                    need_title = ""
                else:
                    need_title = datum["title"]
                    del datum["title"]

                # We need to check if all given options from services are really available as configured
                # extra_option or extra_link
                missing_options = {}
                for element in datum.keys():
                    defined_options = list(self.__class__.option_spec.keys())
                    defined_options.append(
                        "content"
                    )  # Add content, so that it gets not detected as missing
                    if element not in defined_options and element not in getattr(
                            app.config, "needs_extra_links", []):
                        missing_options[element] = datum[element]

                # Finally delete not found options
                for missing_option in missing_options:
                    del datum[missing_option]

                if app.config.needs_service_all_data:
                    for name, value in missing_options.items():
                        content.append(f"\n:{name}: {value}")

                # content.insert(0, '.. code-block:: text\n')
                options["content"] = "\n".join(content)
                # Replace values in datum with calculated/checked ones.
                datum.update(options)

                # ToDo: Tags and Status are not set (but exist in data)
                section += add_need(self.env.app, self.state, docname,
                                    self.lineno, need_type, need_title,
                                    **datum)
        else:
            try:
                service_debug_data = service.debug(self.options)
            except NotImplementedError:
                service_debug_data = {
                    "error":
                    f'Service {service_name} does not support "debug" output.'
                }
            viewer_node = get_data_viewer_node(title="Debug data",
                                               data=service_debug_data)
            section.append(viewer_node)
        return section
    def run(self):
        docname = self.state.document.settings.env.docname
        app = self.env.app
        needs_services = self.env.app.needs_services

        service_name = self.arguments[0]
        service = needs_services.get(service_name)
        service_data = service.request(self.options)

        section = []

        for datum in service_data:
            options = {}

            try:
                content = datum['content'].split('\n')
            except KeyError:
                content = []

            content.extend(self.content)

            if 'type' not in datum.keys():
                # Use the first defined type, if nothing got defined by service (should not be the case)
                need_type = self.env.app.config.needs_types[0]['directive']
            else:
                need_type = datum['type']
                del datum['type']

            if 'title' not in datum.keys():
                need_title = ""
            else:
                need_title = datum['title']
                del datum['title']

            # We need to check if all given options from services are really available as configured
            # extra_option or extra_link
            missing_options = {}
            for element in datum.keys():
                defined_options = list(self.__class__.option_spec.keys())
                defined_options.append(
                    'content'
                )  # Add content, so that it gets not detected as missing
                if element not in defined_options and element not in getattr(
                        app.config, "needs_extra_links", []):
                    missing_options[element] = datum[element]

            # Finally delete not found options
            for missing_option in missing_options:
                del datum[missing_option]

            if app.config.needs_service_all_data:
                for name, value in missing_options.items():
                    content.append('\n:{}: {}'.format(name, value))

            # content.insert(0, '.. code-block:: text\n')
            options['content'] = '\n'.join(content)
            # Replace values in datum with calculated/checked ones.
            datum.update(options)

            # ToDo: Tags and Status are not set (but exist in data)
            section += add_need(self.env.app, self.state, docname, self.lineno,
                                need_type, need_title, **datum)

        return section
            case_name = case_full_name
            case_parameter = ''

        if case_parameter is None:
            case_parameter = ''

        main_section = []
        docname = self.state.document.settings.env.docname
        main_section += add_need(self.app,
                                 self.state,
                                 docname,
                                 self.lineno,
                                 need_type=self.need_type,
                                 title=self.test_name,
                                 id=self.test_id,
                                 content=content,
                                 links=self.test_links,
                                 tags=self.test_tags,
                                 status=self.test_status,
                                 collapse=self.collapse,
                                 file=self.test_file_given,
                                 suite=suite['name'],
                                 case=case_full_name,
                                 case_name=case_name,
                                 case_parameter=case_parameter,
                                 classname=class_name,
                                 result=result,
                                 time=time,
                                 style=style)
        return main_section
    def run(self):
        #############################################################################################
        # Get environment
        #############################################################################################
        env = self.env

        # ToDo: Keep this in directive!!!
        collapse = self.options.get("collapse", None)
        if isinstance(collapse, str):
            if collapse.upper() in ["TRUE", 1, "YES"]:
                collapse = True
            elif collapse.upper() in ["FALSE", 0, "NO"]:
                collapse = False
            else:
                raise Exception("collapse attribute must be true or false")

        hide = "hide" in self.options

        id = self.options.get("id", None)
        content = "\n".join(self.content)
        status = self.options.get("status", None)
        if status:
            status = status.replace(
                "__", ""
            )  # Support for multiline options, which must use __ for empty lines
        tags = self.options.get("tags", "")
        style = self.options.get("style", None)
        layout = self.options.get("layout", "")
        template = self.options.get("template", None)
        pre_template = self.options.get("pre_template", None)
        post_template = self.options.get("post_template", None)
        duration = self.options.get("duration", None)
        completion = self.options.get("completion", None)

        need_extra_options = {"duration": duration, "completion": completion}
        for extra_link in env.config.needs_extra_links:
            need_extra_options[extra_link["option"]] = self.options.get(
                extra_link["option"], "")

        NEEDS_CONFIG.get("extra_options")
        for extra_option in NEEDS_CONFIG.get("extra_options").keys():
            need_extra_options[extra_option] = self.options.get(
                extra_option, "")

        need_nodes = add_need(
            env.app,
            self.state,
            self.docname,
            self.lineno,
            need_type=self.name,
            title=self.trimmed_title,
            id=id,
            content=content,
            status=status,
            tags=tags,
            hide=hide,
            template=template,
            pre_template=pre_template,
            post_template=post_template,
            collapse=collapse,
            style=style,
            layout=layout,
            **need_extra_options,
        )
        return need_nodes
    def run(self):
        needs_list = {}
        version = self.options.get("version", None)
        filter_string = self.options.get("filter", None)
        id_prefix = self.options.get("id_prefix", "")

        tags = self.options.get("tags", [])
        if len(tags) > 0:
            tags = [tag.strip() for tag in re.split(";|,", tags)]

        env = self.state.document.settings.env

        need_import_path = self.arguments[0]

        if not os.path.isabs(need_import_path):
            # Relative path should starts from current rst file directory
            curr_dir = os.path.dirname(self.docname)
            new_need_import_path = os.path.join(env.app.confdir, curr_dir,
                                                need_import_path)

            correct_need_import_path = new_need_import_path
            if not os.path.exists(new_need_import_path):
                # Check the old way that calculates relative path starting from conf.py directory
                old_need_import_path = os.path.join(env.app.confdir,
                                                    need_import_path)
                if os.path.exists(old_need_import_path):
                    correct_need_import_path = old_need_import_path
                    logger.warning(
                        "Deprecation warning: Relative path must be relative to the current document in future, "
                        "not to the conf.py location. Use a starting '/', like '/needs.json', to make the path "
                        "relative to conf.py.")
        else:
            # Absolute path starts with /, based on the conf.py directory. The / need to be striped
            correct_need_import_path = os.path.join(env.app.confdir,
                                                    need_import_path[1:])

        if not os.path.exists(correct_need_import_path):
            raise ReferenceError(
                f"Could not load needs import file {correct_need_import_path}")

        with open(correct_need_import_path) as needs_file:
            needs_file_content = needs_file.read()
        try:
            needs_import_list = json.loads(needs_file_content)
        except json.JSONDecodeError as e:
            # ToDo: Add exception handling
            raise e

        if version is None:
            try:
                version = needs_import_list["current_version"]
                if not isinstance(version, str):
                    raise KeyError
            except KeyError:
                raise CorruptedNeedsFile(
                    f"Key 'current_version' missing or corrupted in {correct_need_import_path}"
                )
        if version not in needs_import_list["versions"].keys():
            raise VersionNotFound(
                f"Version {version} not found in needs import file {correct_need_import_path}"
            )

        needs_list = needs_import_list["versions"][version]["needs"]

        # Filter imported needs
        needs_list_filtered = {}
        for key, need in needs_list.items():
            if filter_string is None:
                needs_list_filtered[key] = need
            else:
                filter_context = {key: value for key, value in need.items()}

                # Support both ways of addressing the description, as "description" is used in json file, but
                # "content" is the sphinx internal name for this kind of information
                filter_context["content"] = need["description"]
                try:
                    if filter_single_need(env.app, filter_context,
                                          filter_string):
                        needs_list_filtered[key] = need
                except Exception as e:
                    logger.warning(
                        "needimport: Filter {} not valid. Error: {}. {}{}".
                        format(filter_string, e, self.docname, self.lineno))

        needs_list = needs_list_filtered

        # If we need to set an id prefix, we also need to manipulate all used ids in the imported data.
        if id_prefix:
            needs_ids = needs_list.keys()

            for need in needs_list.values():
                for id in needs_ids:
                    # Manipulate links in all link types
                    for extra_link in env.config.needs_extra_links:
                        if extra_link["option"] in need and id in need[
                                extra_link["option"]]:
                            for n, link in enumerate(
                                    need[extra_link["option"]]):
                                if id == link:
                                    need[extra_link["option"]][n] = "".join(
                                        [id_prefix, id])
                    # Manipulate descriptions
                    # ToDo: Use regex for better matches.
                    need["description"] = need["description"].replace(
                        id, "".join([id_prefix, id]))

        # tags update
        for need in needs_list.values():
            need["tags"] = need["tags"] + tags

        need_nodes = []
        for need in needs_list.values():
            # Set some values based on given option or value from imported need.
            need["template"] = self.options.get(
                "template", getattr(need, "template", None))
            need["pre_template"] = self.options.get(
                "pre_template", getattr(need, "pre_template", None))
            need["post_template"] = self.options.get(
                "post_template", getattr(need, "post_template", None))
            need["layout"] = self.options.get("layout",
                                              getattr(need, "layout", None))
            need["style"] = self.options.get("style",
                                             getattr(need, "style", None))
            need["style"] = self.options.get("style",
                                             getattr(need, "style", None))
            if "hide" in self.options:
                need["hide"] = True
            else:
                need["hide"] = getattr(need, "hide", None)
            need["collapse"] = self.options.get(
                "collapse", getattr(need, "collapse", None))

            # The key needs to be different for add_need() api call.
            need["need_type"] = need["type"]

            # Replace id, to get unique ids
            need["id"] = id_prefix + need["id"]

            need["content"] = need["description"]
            # Remove unknown options, as they may be defined in source system, but not in this sphinx project
            extra_link_keys = [
                x["option"] for x in env.config.needs_extra_links
            ]
            extra_option_keys = list(NEEDS_CONFIG.get("extra_options").keys())
            default_options = [
                "title",
                "status",
                "content",
                "id",
                "tags",
                "hide",
                "template",
                "pre_template",
                "post_template",
                "collapse",
                "style",
                "layout",
                "need_type",
            ]
            delete_options = []
            for option in need.keys():
                if option not in default_options + extra_link_keys + extra_option_keys:
                    delete_options.append(option)

            for option in delete_options:
                del need[option]

            need["docname"] = self.docname
            need["lineno"] = self.lineno

            nodes = add_need(env.app, self.state, **need)
            need_nodes.extend(nodes)

        return need_nodes
    def run(self):
        self.prepare_basic_options()
        results = self.load_test_file()

        # Error handling, if file not found
        if results is None:
            main_section = []
            content = nodes.error()
            para = nodes.paragraph()
            text_string = "Test file not found: {}".format(self.test_file)
            text = nodes.Text(text_string, text_string)
            para += text
            content.append(para)
            main_section.append(content)
            return main_section

        suites = len(self.results)
        cases = sum([int(x['tests']) for x in self.results])

        passed = sum([x['passed'] for x in self.results])
        skipped = sum([x['skips'] for x in self.results])
        errors = sum([x['errors'] for x in self.results])
        failed = sum([x['failures'] for x in self.results])

        main_section = []
        docname = self.state.document.settings.env.docname
        main_section += add_need(self.app,
                                 self.state,
                                 docname,
                                 self.lineno,
                                 need_type=self.need_type,
                                 title=self.test_name,
                                 id=self.test_id,
                                 content=self.test_content,
                                 links=self.test_links,
                                 tags=self.test_tags,
                                 status=self.test_status,
                                 collapse=self.collapse,
                                 file=self.test_file_given,
                                 suites=suites,
                                 cases=cases,
                                 passed=passed,
                                 skipped=skipped,
                                 failed=failed,
                                 errors=errors)

        if 'auto_cases' in self.options.keys(
        ) and 'auto_suites' not in self.options.keys():
            raise TestReportIncompleteConfiguration(
                'option auto_cases must be used together with '
                'auto_suites for test-file directives.')

        if 'auto_suites' in self.options.keys():
            for suite in self.results:
                suite_id = self.test_id
                suite_id += '_' + hashlib.sha1(
                    suite['name'].encode("UTF-8")).hexdigest().upper()[:3]

                options = self.options
                options['suite'] = suite['name']
                options['id'] = suite_id

                if 'links' not in self.options:
                    options['links'] = self.test_id
                elif self.test_id not in options['links']:
                    options['links'] = options['links'] + ';' + self.test_id

                arguments = [suite['name']]
                suite_directive = sphinxcontrib.test_reports.directives.test_suite.TestSuiteDirective(
                    self.app.config.tr_suite[0],
                    arguments,
                    options,
                    '',
                    self.lineno,  # no content
                    self.content_offset,
                    self.block_text,
                    self.state,
                    self.state_machine)

                main_section += suite_directive.run()

        return main_section