1#!/usr/bin/env python3 2# -*- coding: utf-8 -*- 3 4# Copyright (c) 2024-2025 Huawei Device Co., Ltd. 5# Licensed under the Apache License, Version 2.0 (the "License"); 6# you may not use this file except in compliance with the License. 7# You may obtain a copy of the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an "AS IS" BASIS, 13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14# See the License for the specific language governing permissions and 15# limitations under the License. 16# 17 18import glob 19import logging 20import os 21import pathlib 22import typing 23import jinja2 24import yaml 25import runner.logger as LOG 26import runner.plugins.ets.utils.constants 27import runner.utils 28 29 30class EtsFuncTestsCodeGenerator: 31 _TEST_SEPARATOR = "---" 32 _TEMPLATE_PATTERN = '/*.ets.j2' 33 34 35 def __init__(self, template_root_path: pathlib.Path): 36 self._logger = logging.getLogger("runner.generators.ets_func_tests") 37 self._jinja_env = jinja2.Environment( 38 loader=jinja2.FileSystemLoader(str(template_root_path)), 39 autoescape=jinja2.select_autoescape(), 40 variable_start_string=runner.plugins.ets.utils.constants.VARIABLE_START_STRING 41 ) 42 43 @staticmethod 44 def __get_true_file_basename(path:str) -> str: 45 base_fname = os.path.basename(path) 46 while '.' in base_fname: 47 base_fname, _ = os.path.splitext(base_fname) 48 return base_fname 49 50 @staticmethod 51 def __save_artefact_of_generator(test: str, template_fname: str, template_config_fname: str) -> str: 52 test = f"/* Template name : {template_fname}*/\n" + test 53 test = f"/* Config name : {template_config_fname}*/\n\n" + test 54 return test 55 56 def render_and_write_templates(self, 57 template_root_path: pathlib.Path, 58 current_dir: pathlib.Path, 59 outpath: pathlib.Path) -> typing.List[str]: 60 os.makedirs(outpath, exist_ok=True) 61 generated_test_list = [] 62 templates_fname_list = self.__find_all_templates(current_dir) 63 for template_fname in templates_fname_list: 64 generated_test_list.extend(self.__render_template(template_fname, template_root_path, outpath)) 65 return generated_test_list 66 67 def __find_all_templates(self, current_dir: pathlib.Path) -> typing.List[str]: 68 LOG.Log.summary(self._logger, f"Start searching in : {current_dir}") 69 LOG.Log.summary(self._logger, f"{str(current_dir) + self._TEMPLATE_PATTERN}") 70 templates_fname_list = glob.glob(str(current_dir) + self._TEMPLATE_PATTERN, recursive=False) 71 LOG.Log.summary(self._logger, f"Found {len(templates_fname_list)} templates") 72 return templates_fname_list 73 74 def __build_template_config_file_name(self, template_path_fname: str) -> str: 75 path_parser = pathlib.Path(template_path_fname) 76 template_base_fname = self.__get_true_file_basename(template_path_fname) 77 template_path = path_parser.parent 78 config_fname = "config-" + template_base_fname + ".yaml" 79 LOG.Log.summary(self._logger, f"Config path {config_fname}") 80 result = os.path.join(template_path, config_fname) 81 return result 82 83 def __render_template(self, 84 template_fname: str, 85 template_root_path: pathlib.Path, 86 outpath: pathlib.Path) -> typing.List[str]: 87 generated_tests_list = [] 88 template_config_name = self.__build_template_config_file_name(template_fname) 89 path_parser = pathlib.Path(template_fname) 90 template_relative_path = os.path.relpath(path_parser.parent, template_root_path) 91 template_relative_fname = os.path.join(template_relative_path, path_parser.name) 92 LOG.Log.summary(self._logger, f"Load template from {template_relative_fname}") 93 template = self._jinja_env.get_template(template_relative_fname) 94 params = self.__load_parameters(template_config_name) 95 content = template.render(**params) 96 content = content.strip() 97 content_list = self.__split_tests(content) 98 test_idx = 1 99 path_parser = pathlib.Path(template_fname) 100 fname = self.__get_true_file_basename(template_fname) 101 102 for test in content_list: 103 test = self.__save_artefact_of_generator(test, template_fname, template_config_name) 104 output_fname = "test-" + fname + "-" + str(test_idx).zfill(4) + ".ets" 105 outpath_final = outpath / output_fname 106 generated_tests_list.append(str(outpath)) 107 runner.utils.write_2_file(outpath_final, test) 108 test_idx += 1 109 return generated_tests_list 110 111 def __load_parameters(self, config_file_path : str) -> typing.Any: 112 with os.fdopen(os.open(config_file_path, os.O_RDONLY, 0o755), "r", encoding='utf8') as f_handle: 113 text = f_handle.read() 114 try: 115 params = yaml.safe_load(text) 116 LOG.Log.summary(self._logger, params) 117 except Exception as common_exp: 118 raise Exception(f"Could not load YAML: {str(common_exp)} filepath={config_file_path}") from common_exp 119 return params 120 121 def __split_tests(self, content : str) -> typing.List[str]: 122 content = content.rstrip(self._TEST_SEPARATOR) 123 content_list = content.split("---") 124 LOG.Log.summary(self._logger, f"size : {len(content_list)}") 125 return content_list 126