Module kalash.last_result_filter

Expand source code
import os
import re
import datetime

from xml.etree import ElementTree as ET


def is_test_result(xml_attribute):
    """
    Produces a lambda that checks a list of attributes
    in an XML `testcase` section against the one specified
    when filling the closure.

    Args:
        xml_attribute (str): attribute of the section searched for

    Returns:
        function that takes a list of attributes as a parameter
    """
    return lambda attr_list: xml_attribute in attr_list


is_test_fail = is_test_result('failure')
is_test_error = is_test_result('error')
is_test_fail_or_error = lambda x: is_test_result('failure')(x) or is_test_result('error')(x)
# when passed there is just stdout and stderr section but no error or failure:
is_test_pass = lambda attr_list: not is_test_fail_or_error(attr_list)


def filter_for_result(check_lr_tag_function):
    """
    Last result filtering function.

    Args:
        check_lr_tag_function (function): a lambda returning a boolean value
            depending on whether a specific XML attribute is present in a `testcase`
            section of the XML report

    Returns:
        A closure function bound to specific "OK"/"NOK" `last_result`
    """

    def process_xml_tree(path_to_xml):
        """
        Processes a single XML report and returns `testcase` section
        if the report isn't spawned from `unittest._ErrorHolder`.

        Args:
            path_to_xml (str): path to a valid XMLRunner report

        Returns:
            List of XML Elements (xml.etree.ElementTree.Element)
            or an empty list when `_ErrorHolder` is encountered
        """
        if str(path_to_xml).endswith('.xml'):
            xml_tree = ET.parse(path_to_xml)
            xml_tree_root = xml_tree.getroot()
            if re.search(r'_ErrorHolder', xml_tree_root.attrib['name']):
                # parsing unittest._ErrorHolder cases is not supported
                return list()
            else:
                return xml_tree_root.findall('testcase')

    def closure(single_test_path, reports_path):
        """
        Last result filtering closure.

        Args:
            single_test_path (str): path to a test being currently processed
                by the callback in `kalash`'s test loader
                (see: `metaparser.apply_filters()`)
            reports_path (str): path to the reports folder

        Returns:
            Array of booleans as used in `metaparser.apply_filters()`
        """
        results = dict()
        for root, dirs, files in os.walk(os.path.abspath(reports_path)):
            for name in files:
                single_report_path = os.path.join(root, name)
                # extract all `testcase` sections from the XML:
                test_cases = process_xml_tree(single_report_path)
                if test_cases:
                    for tc in test_cases:
                        # record all underlying tags in XML tree
                        result_tags = [child.tag for child in tc]
                        file_path = tc.attrib['file']              # record file path
                        # check the result tag in the report
                        # (whether it is the one you want when filtering)
                        # and if the file path is corresponding to the current test file:
                        if (os.path.abspath(file_path) == os.path.abspath(single_test_path)):
                            results[single_report_path] = \
                                datetime.datetime.strptime(
                                    tc.attrib['timestamp'], "%Y-%m-%dT%H:%M:%S")
        try:
            last_report_path = [k for k, _ in sorted(results.items(), key=lambda x: x[1])][-1]
            test_cases_that_pass_predicate = []
            test_cases = process_xml_tree(last_report_path)
            if test_cases:
                for tc in test_cases:
                    result_tags = [child.tag for child in tc]
                    test_cases_that_pass_predicate.append(check_lr_tag_function(result_tags))
        except (KeyError, IndexError):
            # when key error or IndexError encountered
            # it means that the folder contains no reports yet
            test_cases_that_pass_predicate = [False]

        return test_cases_that_pass_predicate

    return closure

Functions

def filter_for_result(check_lr_tag_function)

Last result filtering function.

Args

check_lr_tag_function : function
a lambda returning a boolean value depending on whether a specific XML attribute is present in a testcase section of the XML report

Returns

A closure function bound to specific "OK"/"NOK" last_result

Expand source code
def filter_for_result(check_lr_tag_function):
    """
    Last result filtering function.

    Args:
        check_lr_tag_function (function): a lambda returning a boolean value
            depending on whether a specific XML attribute is present in a `testcase`
            section of the XML report

    Returns:
        A closure function bound to specific "OK"/"NOK" `last_result`
    """

    def process_xml_tree(path_to_xml):
        """
        Processes a single XML report and returns `testcase` section
        if the report isn't spawned from `unittest._ErrorHolder`.

        Args:
            path_to_xml (str): path to a valid XMLRunner report

        Returns:
            List of XML Elements (xml.etree.ElementTree.Element)
            or an empty list when `_ErrorHolder` is encountered
        """
        if str(path_to_xml).endswith('.xml'):
            xml_tree = ET.parse(path_to_xml)
            xml_tree_root = xml_tree.getroot()
            if re.search(r'_ErrorHolder', xml_tree_root.attrib['name']):
                # parsing unittest._ErrorHolder cases is not supported
                return list()
            else:
                return xml_tree_root.findall('testcase')

    def closure(single_test_path, reports_path):
        """
        Last result filtering closure.

        Args:
            single_test_path (str): path to a test being currently processed
                by the callback in `kalash`'s test loader
                (see: `metaparser.apply_filters()`)
            reports_path (str): path to the reports folder

        Returns:
            Array of booleans as used in `metaparser.apply_filters()`
        """
        results = dict()
        for root, dirs, files in os.walk(os.path.abspath(reports_path)):
            for name in files:
                single_report_path = os.path.join(root, name)
                # extract all `testcase` sections from the XML:
                test_cases = process_xml_tree(single_report_path)
                if test_cases:
                    for tc in test_cases:
                        # record all underlying tags in XML tree
                        result_tags = [child.tag for child in tc]
                        file_path = tc.attrib['file']              # record file path
                        # check the result tag in the report
                        # (whether it is the one you want when filtering)
                        # and if the file path is corresponding to the current test file:
                        if (os.path.abspath(file_path) == os.path.abspath(single_test_path)):
                            results[single_report_path] = \
                                datetime.datetime.strptime(
                                    tc.attrib['timestamp'], "%Y-%m-%dT%H:%M:%S")
        try:
            last_report_path = [k for k, _ in sorted(results.items(), key=lambda x: x[1])][-1]
            test_cases_that_pass_predicate = []
            test_cases = process_xml_tree(last_report_path)
            if test_cases:
                for tc in test_cases:
                    result_tags = [child.tag for child in tc]
                    test_cases_that_pass_predicate.append(check_lr_tag_function(result_tags))
        except (KeyError, IndexError):
            # when key error or IndexError encountered
            # it means that the folder contains no reports yet
            test_cases_that_pass_predicate = [False]

        return test_cases_that_pass_predicate

    return closure
def is_test_error(attr_list)
Expand source code
return lambda attr_list: xml_attribute in attr_list
def is_test_fail(attr_list)
Expand source code
return lambda attr_list: xml_attribute in attr_list
def is_test_fail_or_error(x)
Expand source code
is_test_fail_or_error = lambda x: is_test_result('failure')(x) or is_test_result('error')(x)
def is_test_pass(attr_list)
Expand source code
is_test_pass = lambda attr_list: not is_test_fail_or_error(attr_list)
def is_test_result(xml_attribute)

Produces a lambda that checks a list of attributes in an XML testcase section against the one specified when filling the closure.

Args

xml_attribute : str
attribute of the section searched for

Returns

function that takes a list of attributes as a parameter

Expand source code
def is_test_result(xml_attribute):
    """
    Produces a lambda that checks a list of attributes
    in an XML `testcase` section against the one specified
    when filling the closure.

    Args:
        xml_attribute (str): attribute of the section searched for

    Returns:
        function that takes a list of attributes as a parameter
    """
    return lambda attr_list: xml_attribute in attr_list