import os
import re
import json
import shutil
import argparse
import subprocess
import concurrent.futures
from llm import generate_script, check_package_command, generate_markdown
from logger import logger
MAX_TIMES = 2
TEST_CASE_DIR = "generate_test_cases"
TMP_DIR = "tmp"
NOTE_DIR = "note.md"
COMMON_DIR = "common"
SUITE_DIR = "suite2cases"
TESTCASE_DIR = "testcases"
LOGS_DIR = "logs"
current_file_path = os.path.abspath(__file__)
current_dir_path = os.path.dirname(current_file_path)
current_directory = os.getcwd()
def parse_markdown_table(markdown_text):
table_rows = re.findall(r'^\|(.*)\|$', markdown_text, re.MULTILINE)
headers = re.split(r'\s*\|\s*', table_rows[0].strip())
table_data = []
for row in table_rows[2:]:
if row:
cells = row.split(' | ')
if len(cells) == len(headers):
row_data = {headers[i]: cells[i] for i in range(len(headers))}
table_data.append(row_data)
return table_data
def get_test_case(md_file):
with open(md_file, 'r') as f:
test_case_file = f.read()
dicts = parse_markdown_table(test_case_file)
return dicts
def get_command_info(rpm_package_name, command):
if command == rpm_package_name:
command = ""
command_info = ""
rpm_package_command = [rpm_package_name]
if command:
rpm_package_command.append(command)
if '.sh' in rpm_package_name:
rpm_package_command.insert(0, 'sh')
try:
tmp_command = list(rpm_package_command)
tmp_command.append('help')
result = subprocess.run(tmp_command, capture_output=True, text=True, timeout=5)
if not result.stdout:
tmp_command = list(rpm_package_command)
tmp_command.append('--help')
result = subprocess.run(tmp_command, capture_output=True, text=True, timeout=5)
if not result.stdout:
logger.info(f"获取软件包{rpm_package_name} {command}的help信息失败")
else:
command_info = result.stdout
else:
command_info = result.stdout
except Exception as e:
logger.info(f"获取软件包{rpm_package_name} {command}的help信息失败:{e}")
return command, command_info
def get_note(note_dir):
note = ""
if not note_dir or not os.path.exists(note_dir):
return note
with open(note_dir, 'r') as f:
note = f.read()
return note
def check_exec_log(script_exec_log):
lines = script_exec_log.splitlines()
filtered_lines = [line for line in lines if not line.startswith('+')]
filtered_script_exec_log = '\n'.join(filtered_lines)
return filtered_script_exec_log
def execute_script(package_name, rpm_package_name, command, script):
script_exec_result = False
script_exec_log = ""
with open(os.path.join(current_directory, SUITE_DIR, f'{package_name}_{rpm_package_name}_{command}.json'), 'w') as f:
suite_json_template = {"path": f"$OET_PATH/{TESTCASE_DIR}/{package_name}",
"cases": [{"name": f"{rpm_package_name}_{command}"}]}
f.write(json.dumps(suite_json_template, indent=4))
with open(os.path.join(current_directory, TESTCASE_DIR, package_name, f'{rpm_package_name}_{command}.sh'), 'w') as f:
f.write(script)
try:
result = subprocess.run(
['bash', 'mugen.sh', '-f', f'{package_name}_{rpm_package_name}_{command}', '-x'],
capture_output=True, text=True, timeout=60)
logger.info("执行测试脚本完成")
script_exec_result = True if result.returncode == 0 else False
log_dir = os.path.join(
current_directory, LOGS_DIR, f'{package_name}_{rpm_package_name}_{command}',
f"{rpm_package_name}_{command}")
if os.path.exists(log_dir):
logs = os.listdir(log_dir)
if logs:
latest_log = max(logs, key=lambda x: os.path.getctime(os.path.join(log_dir, x)))
with open(os.path.join(log_dir, latest_log), 'r') as f:
script_exec_log = f.read()
except Exception as e:
logger.info(f"执行测试脚本失败:{e}")
filtered_script_exec_log = check_exec_log(script_exec_log)
if filtered_script_exec_log:
with open(os.path.join(log_dir, 'filter.log'), 'w') as f:
f.write(filtered_script_exec_log)
return script_exec_result, filtered_script_exec_log
def get_test_script_by_rpm_package_name(package_name, rpm_package_name):
package_info = ""
logger.info(f"获取二进制命令{rpm_package_name}的信息...")
rpm_package_command = [rpm_package_name]
if '.sh' in rpm_package_name:
rpm_package_command = ['sh', rpm_package_name]
try:
tmp_command = list(rpm_package_command)
tmp_command.append('help')
result = subprocess.run(tmp_command, capture_output=True, text=True, timeout=5)
if result.stdout:
package_info = result.stdout
else:
package_info = result.stderr
except Exception as e:
logger.info(f"尝试获取二进制命令{rpm_package_name}的help信息失败:{e}")
if 'usage' not in package_info or 'Usage' not in package_info:
try:
tmp_command = list(rpm_package_command)
tmp_command.append('--help')
result = subprocess.run(tmp_command, capture_output=True, text=True, timeout=5)
if result.stdout:
package_info = result.stdout
else:
package_info = result.stderr
except Exception as e:
logger.info(f"尝试获取二进制命令{rpm_package_name}的--help信息失败:{e}")
if 'usage' in package_info or 'Usage' in package_info:
logger.info(f"获取二进制命令{rpm_package_name}的信息成功")
logger.info(package_info)
else:
logger.info(f"获取二进制命令{rpm_package_name}的信息失败")
return []
commands = check_package_command(rpm_package_name, package_info)
if rpm_package_name in commands:
commands.remove(rpm_package_name)
if not commands:
logger.info(f"获取软件包{package_name}的子命令为空")
commands = ['']
logger.info(f"获取软件包{rpm_package_name}的子命令:{commands}")
software_dir = os.path.join(current_dir_path, TEST_CASE_DIR, package_name)
os.makedirs(software_dir, exist_ok=True)
note_file = get_note(os.path.join(current_dir_path, TMP_DIR, NOTE_DIR))
common_file = os.path.join(current_dir_path, TMP_DIR, COMMON_DIR)
os.makedirs(os.path.join(current_directory, TESTCASE_DIR, package_name, 'common'), exist_ok=True)
shutil.copytree(common_file, os.path.join(current_directory,
TESTCASE_DIR, package_name, 'common'), dirs_exist_ok=True)
result_commands = []
for index, command in enumerate(commands):
command_name, command_info = get_command_info(rpm_package_name, command)
if not command:
command = f"{rpm_package_name}_{index+1}"
history_script = ""
history_script_exec_result = False
history_script_exec_log = ""
times = 0
while not history_script_exec_result and times < MAX_TIMES:
times += 1
script = generate_script(package_name, rpm_package_name, package_info, command_name, command_info,
note_file, history_script, history_script_exec_log)
if not script:
script = history_script
else:
history_script = script
if not script:
logger.info(f"第{times}次生成测试脚本{rpm_package_name}/{rpm_package_name}_{command}.sh失败")
continue
logger.info("正在执行测试脚本...")
history_script_exec_result, history_script_exec_log = execute_script(
package_name, rpm_package_name, command, script)
logger.info(f"第{times}次校验测试脚本{rpm_package_name}/{rpm_package_name}_{command}.sh,结果:{history_script_exec_result}")
with open(os.path.join(software_dir, f'{command}.sh'), "w") as f:
f.write(script)
result_commands.append(command)
logger.info(f"生成测试脚本{software_dir}/{command}.sh")
return result_commands
def uninstall_package(package_name):
logger.info(f"开始卸载软件包{package_name}")
result = subprocess.run(['dnf', 'remove', '-y', package_name], capture_output=True, text=True)
if result.returncode != 0:
logger.info(f"卸载软件包失败:{result.stderr}")
return
logger.info(f"卸载软件包{package_name}成功")
def get_test_script(package_name):
logger.info(f"开始生成测试脚本{package_name}")
logger.info("正在安装软件包...")
result = subprocess.run(['dnf', 'install', '-y', package_name], capture_output=True, text=True)
if result.returncode != 0:
logger.info(f"安装软件包失败:{result.stderr}")
uninstall_package(package_name)
return
result = subprocess.run(['rpm', '-qa'], stdout=subprocess.PIPE, text=True)
ccb_packages = [package for package in result.stdout.split('\n') if 'ccb' in package]
if ccb_packages:
logger.info(f"已安装ccb包:{ccb_packages}")
else:
logger.info("未安装ccb包,请参考README文档安装ccb")
return
logger.info("正在使用ccb提取二进制包...")
result = subprocess.run(
['ccb', 'select', 'rpms', f'repo_name={package_name}', '--size=1', '-f rpms'],
capture_output=True, text=True)
if result.returncode != 0:
logger.info(f"使用ccb提取二进制包失败:{result.stderr}")
uninstall_package(package_name)
return
ccb_json = json.loads(result.stdout)
if not ccb_json:
logger.info(f"未找到软件包{package_name}的二进制包")
uninstall_package(package_name)
return
extracted_names = []
for item in ccb_json[0]['_source']['rpms']:
if 'debugsource' not in item['name'] and 'debuginfo' not in item['name'] and 'help' not in item['name'] and item['name'] not in extracted_names:
extracted_names.append(item['name'])
logger.info(f"提取到的二进制包名:{extracted_names}")
rpm_package_names = []
pattern = re.compile(r'/usr/bin/(\S+)')
for extracted_name in extracted_names:
rpm_result = subprocess.run(['rpm', '-ql', extracted_name], stdout=subprocess.PIPE, text=True)
if rpm_result.returncode == 0:
rpm_lines = rpm_result.stdout.splitlines()
for line in rpm_lines:
match = pattern.search(line)
if match:
rpm_package_names.append(match.group(1))
if not rpm_package_names:
logger.info(f"未找到软件包{package_name}的二进制命令名")
uninstall_package(package_name)
return
logger.info(f"提取到的二进制命令名:{rpm_package_names}")
total_commands = []
for rpm_package_name in rpm_package_names:
commands = get_test_script_by_rpm_package_name(package_name, rpm_package_name)
if commands:
total_commands.extend(commands)
logger.info("开始生成套件...")
software_dir = os.path.join(current_dir_path, TEST_CASE_DIR, package_name)
if not os.path.exists(software_dir):
logger.info(f"{package_name}未生成脚本")
uninstall_package(package_name)
return
with open(os.path.join(software_dir, f'{package_name}.json'), "w") as f:
suite_json_template = {"path": f"$OET_PATH/{TESTCASE_DIR}/{package_name}", "cases": []}
for index, command in enumerate(total_commands):
if not command:
command = f"{package_name}_{index+1}"
suite_json_template["cases"].append({"name": f"{command}"})
json.dump(suite_json_template, f, indent=4)
logger.info(f"生成{package_name}.json套件")
uninstall_package(package_name)
def get_test_script_md(package_name):
software_dir = os.path.join(current_dir_path, TEST_CASE_DIR, package_name)
for file in os.listdir(software_dir):
if file.endswith(".sh"):
with open(os.path.join(software_dir, file), "r") as f:
script = f.read()
md_file = generate_markdown(package_name, file, script)
with open(os.path.join(software_dir, f"{file}.md"), "w") as f:
f.write(md_file)
logger.info(f"生成测试文档{software_dir}/{file}.md")
def get_test_script_by_file_path(file_path, timeout=600):
with open(file_path, 'r') as f:
packages = f.read().splitlines()
with concurrent.futures.ThreadPoolExecutor() as executor:
for package in packages:
future = executor.submit(get_test_script, package)
try:
future.result(timeout=timeout)
except Exception as e:
logger.info(f"Generating script for package '{package}' failed. reason:{str(e)} Skipping...")
logger.info("\n")
def get_test_script_md_by_file_path(file_path, timeout=600):
with open(file_path, 'r') as f:
packages = f.read().splitlines()
with concurrent.futures.ThreadPoolExecutor() as executor:
for package in packages:
future = executor.submit(get_test_script_md, package)
try:
future.result(timeout=timeout)
except Exception as e:
logger.info(f"Generating md for package '{package}' failed. reason:{str(e)} Skipping...")
logger.info("\n")
def main():
parser = argparse.ArgumentParser(description='根据软件包的help和测试文档生成测试脚本')
group = parser.add_mutually_exclusive_group(required=True)
parser.add_argument('-m', '--mode', help='模式,默认为shell,shell和md', default='shell')
group.add_argument('-n', '--package-name', help='软件包名称')
group.add_argument('-f', '--file-path', help='包含多个软件包名称的文件路径')
args = parser.parse_args()
if args.mode == 'shell':
if args.package_name:
get_test_script(args.package_name)
elif args.file_path:
get_test_script_by_file_path(args.file_path)
elif args.mode == 'md':
if args.package_name:
get_test_script_md(args.package_name)
elif args.file_path:
get_test_script_md_by_file_path(args.file_path)
if __name__ == "__main__":
main()