diff --git a/conftest.py b/conftest.py index be7d5309a8..ed152c3f06 100644 --- a/conftest.py +++ b/conftest.py @@ -15,6 +15,7 @@ import logging import os +import re import sys import xml.etree.ElementTree as ET from datetime import datetime @@ -219,27 +220,6 @@ def session_tempdir() -> str: return _tmpdir -@pytest.fixture() -def log_minimum_free_heap_size(dut: IdfDut, config: str) -> Callable[..., None]: - def real_func() -> None: - res = dut.expect(r'Minimum free heap size: (\d+) bytes') - logging.info( - '\n------ heap size info ------\n' - '[app_name] {}\n' - '[config_name] {}\n' - '[target] {}\n' - '[minimum_free_heap_size] {} Bytes\n' - '------ heap size end ------'.format( - os.path.basename(dut.app.app_path), - config, - dut.target, - res.group(1).decode('utf8'), - ) - ) - - return real_func - - @pytest.fixture def case_tester(dut: IdfDut, **kwargs): # type: ignore yield CaseTester(dut, **kwargs) @@ -313,6 +293,102 @@ def junit_properties(test_case_name: str, record_xml_attribute: Callable[[str, o record_xml_attribute('name', test_case_name) +###################### +# Log Util Functions # +###################### +@pytest.fixture +def log_performance(record_property: Callable[[str, object], None]) -> Callable[[str, str], None]: + """ + log performance item with pre-defined format to the console + and record it under the ``properties`` tag in the junit report if available. + """ + + def real_func(item: str, value: str) -> None: + """ + :param item: performance item name + :param value: performance value + """ + logging.info('[Performance][%s]: %s', item, value) + record_property(item, value) + + return real_func + + +@pytest.fixture +def check_performance(idf_path: str) -> Callable[[str, float, str], None]: + """ + check if the given performance item meets the passing standard or not + """ + + def real_func(item: str, value: float, target: str) -> None: + """ + :param item: performance item name + :param value: performance item value + :param target: target chip + :raise: AssertionError: if check fails + """ + def _find_perf_item(operator: str, path: str) -> float: + with open(path, 'r') as f: + data = f.read() + match = re.search(r'#define\s+IDF_PERFORMANCE_{}_{}\s+([\d.]+)'.format(operator, item.upper()), data) + return float(match.group(1)) # type: ignore + + def _check_perf(operator: str, standard_value: float) -> None: + if operator == 'MAX': + ret = value <= standard_value + else: + ret = value >= standard_value + if not ret: + raise AssertionError( + "[Performance] {} value is {}, doesn't meet pass standard {}".format(item, value, standard_value) + ) + + path_prefix = os.path.join(idf_path, 'components', 'idf_test', 'include') + performance_files = ( + os.path.join(path_prefix, target, 'idf_performance_target.h'), + os.path.join(path_prefix, 'idf_performance.h'), + ) + + found_item = False + for op in ['MIN', 'MAX']: + for performance_file in performance_files: + try: + standard = _find_perf_item(op, performance_file) + except (IOError, AttributeError): + # performance file doesn't exist or match is not found in it + continue + + _check_perf(op, standard) + found_item = True + break + + if not found_item: + raise AssertionError('Failed to get performance standard for {}'.format(item)) + + return real_func + + +@pytest.fixture +def log_minimum_free_heap_size(dut: IdfDut, config: str) -> Callable[..., None]: + def real_func() -> None: + res = dut.expect(r'Minimum free heap size: (\d+) bytes') + logging.info( + '\n------ heap size info ------\n' + '[app_name] {}\n' + '[config_name] {}\n' + '[target] {}\n' + '[minimum_free_heap_size] {} Bytes\n' + '------ heap size end ------'.format( + os.path.basename(dut.app.app_path), + config, + dut.target, + res.group(1).decode('utf8'), + ) + ) + + return real_func + + ################## # Hook functions # ##################