2025-04-29 18:09:00 +08:00
|
|
|
|
from copy import deepcopy
|
|
|
|
|
|
from pathlib import Path
|
|
|
|
|
|
from ninja_extra import api_controller, ControllerBase, route
|
|
|
|
|
|
from ninja_extra.permissions import IsAuthenticated
|
|
|
|
|
|
from ninja_jwt.authentication import JWTAuth
|
|
|
|
|
|
from django.db import transaction
|
|
|
|
|
|
from django.db.models import QuerySet
|
|
|
|
|
|
from docxtpl import DocxTemplate
|
|
|
|
|
|
from apps.dict.models import Dict
|
|
|
|
|
|
from utils.chen_response import ChenResponse
|
|
|
|
|
|
from django.shortcuts import get_object_or_404
|
|
|
|
|
|
from typing import Union
|
|
|
|
|
|
from docxtpl import InlineImage
|
|
|
|
|
|
from apps.project.models import Dut, Project, Round
|
|
|
|
|
|
from utils.util import get_list_dict, get_str_dict, get_ident, get_case_ident
|
|
|
|
|
|
from utils.chapter_tools.csx_chapter import create_csx_chapter_dict
|
|
|
|
|
|
from utils.path_utils import project_path
|
|
|
|
|
|
from apps.createDocument.extensions.util import delete_dir_files
|
|
|
|
|
|
from apps.createDocument.extensions.parse_rich_text import RichParser
|
|
|
|
|
|
# 导入生成日志记录模块
|
|
|
|
|
|
from apps.createSeiTaiDocument.extensions.logger import GenerateLogger
|
|
|
|
|
|
|
|
|
|
|
|
chinese_round_name: list = ['一', '二', '三', '四', '五', '六', '七', '八', '九', '十']
|
|
|
|
|
|
|
|
|
|
|
|
# @api_controller("/generateHSM", tags=['生成回归记录系列文档'], auth=JWTAuth(), permissions=[IsAuthenticated])
|
|
|
|
|
|
@api_controller("/generateHJL", tags=['生成回归记录系列文档'])
|
|
|
|
|
|
class GenerateControllerHJL(ControllerBase):
|
|
|
|
|
|
logger = GenerateLogger('回归测试记录')
|
|
|
|
|
|
|
|
|
|
|
|
# important:删除之前的文件
|
|
|
|
|
|
@route.get('/create/deleteHJLDocument', url_name='delete-hjl-document')
|
|
|
|
|
|
def delete_hjl_document(self, id: int):
|
|
|
|
|
|
project_path_str = project_path(id)
|
|
|
|
|
|
save_path = Path.cwd() / 'media' / project_path_str / 'output_dir/hjl'
|
|
|
|
|
|
delete_dir_files(save_path)
|
|
|
|
|
|
|
|
|
|
|
|
@route.get("/create/basicInformation", url_name="create-basicInformation")
|
|
|
|
|
|
@transaction.atomic
|
|
|
|
|
|
def create_basicInformation(self, id: int):
|
|
|
|
|
|
"""生成回归测试记录的被测软件基本信息"""
|
|
|
|
|
|
project_path_str = project_path(id)
|
|
|
|
|
|
tpl_path = Path.cwd() / 'media' / project_path_str / 'form_template/hjl' / '被测软件基本信息.docx'
|
|
|
|
|
|
doc = DocxTemplate(tpl_path)
|
|
|
|
|
|
project_obj = get_object_or_404(Project, id=id)
|
|
|
|
|
|
# 第一轮次对象
|
|
|
|
|
|
round1_obj: Union[Round, None] = project_obj.pField.filter(key='0').first()
|
|
|
|
|
|
# 第一轮源代码被测件对象
|
|
|
|
|
|
round1_so_dut: Union[Dut, None] = round1_obj.rdField.filter(type='SO').first()
|
|
|
|
|
|
languages = get_list_dict('language', project_obj.language)
|
|
|
|
|
|
language_list = [item['ident_version'] for item in languages]
|
|
|
|
|
|
# 取非第一轮次
|
|
|
|
|
|
hround_list: QuerySet = project_obj.pField.exclude(key='0')
|
|
|
|
|
|
if len(hround_list) < 1:
|
|
|
|
|
|
# ***Inspect-start***
|
|
|
|
|
|
self.logger.model = '回归测试记录'
|
|
|
|
|
|
self.logger.write_warning_log('当前文档全部片段', f'该项目没有创建轮次')
|
|
|
|
|
|
# ***Inspect-end***
|
|
|
|
|
|
return ChenResponse(code=400, status=400, message='您未创建轮次,请创建完毕后再试')
|
|
|
|
|
|
|
|
|
|
|
|
context = {
|
|
|
|
|
|
'project_name': project_obj.name,
|
|
|
|
|
|
'language': "、".join(language_list),
|
|
|
|
|
|
'soft_type': project_obj.get_soft_type_display(),
|
|
|
|
|
|
'security_level': get_str_dict(project_obj.security_level, 'security_level'),
|
|
|
|
|
|
'runtime': get_str_dict(project_obj.runtime, 'runtime'),
|
|
|
|
|
|
'devplant': get_str_dict(project_obj.devplant, 'devplant'),
|
|
|
|
|
|
'recv_date': project_obj.beginTime.strftime("%Y-%m-%d"),
|
|
|
|
|
|
'dev_unit': project_obj.dev_unit,
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
version_info = [{'version': round1_so_dut.version,
|
|
|
|
|
|
'line_count': int(round1_so_dut.total_lines),
|
|
|
|
|
|
'effective_line': int(round1_so_dut.effective_lines)}]
|
|
|
|
|
|
# 循环回归的轮次
|
|
|
|
|
|
for hround in hround_list:
|
|
|
|
|
|
# 每个轮次独立渲染context
|
|
|
|
|
|
context_round = deepcopy(context)
|
|
|
|
|
|
# 取中文名称
|
|
|
|
|
|
cname = chinese_round_name[int(hround.key)] # 输出二、三...
|
|
|
|
|
|
# 取该轮次源代码版本放入版本列表
|
|
|
|
|
|
so_dut: Dut = hround.rdField.filter(type='SO').first()
|
|
|
|
|
|
if not so_dut:
|
|
|
|
|
|
return ChenResponse(code=400, status=400, message=f'您第{cname}轮次中缺少源代码被测件,请添加')
|
|
|
|
|
|
version_info.append(
|
|
|
|
|
|
{'version': so_dut.version, 'line_count': int(so_dut.total_lines),
|
|
|
|
|
|
'effective_line': int(so_dut.effective_lines)})
|
|
|
|
|
|
context_round['version_info'] = version_info
|
|
|
|
|
|
# 开始渲染每个轮次的二级文档
|
|
|
|
|
|
save_path = Path.cwd() / 'media' / project_path_str / 'output_dir/hjl' / f"第{cname}轮被测软件基本信息.docx"
|
2025-12-19 18:08:19 +08:00
|
|
|
|
doc.render(context=context_round, autoescape=True)
|
2025-04-29 18:09:00 +08:00
|
|
|
|
try:
|
|
|
|
|
|
doc.save(save_path)
|
|
|
|
|
|
except PermissionError:
|
|
|
|
|
|
return ChenResponse(code=400, status=400, message='您打开了生成的文档,请关闭后重试')
|
|
|
|
|
|
return ChenResponse(code=200, status=200, message='多轮回归说明文档基本信息生成完毕')
|
|
|
|
|
|
|
|
|
|
|
|
@route.get("/create/caseinfo", url_name="create-caseinfo")
|
|
|
|
|
|
@transaction.atomic
|
|
|
|
|
|
def create_caseinfo(self, id: int):
|
|
|
|
|
|
"""生成回归测试记录的-{测试用例记录}"""
|
|
|
|
|
|
project_path_str = project_path(id)
|
|
|
|
|
|
tpl_path = Path.cwd() / 'media' / project_path_str / 'form_template/hjl' / '测试用例记录.docx'
|
|
|
|
|
|
doc = DocxTemplate(tpl_path)
|
|
|
|
|
|
project_obj = get_object_or_404(Project, id=id)
|
|
|
|
|
|
hround_list: QuerySet = project_obj.pField.exclude(key='0')
|
|
|
|
|
|
if len(hround_list) < 1:
|
|
|
|
|
|
return None
|
|
|
|
|
|
demand_prefix = '3.1'
|
|
|
|
|
|
# 循环每轮轮次对象
|
|
|
|
|
|
for hround in hround_list:
|
|
|
|
|
|
cname = chinese_round_name[int(hround.key)] # var:输出二、三字样
|
|
|
|
|
|
test_type_len = Dict.objects.get(code='testType').dictItem.count() # 测试类型的个数
|
|
|
|
|
|
type_number_list = [i for i in range(1, test_type_len + 1)] # 测试类型编号对应的列表
|
|
|
|
|
|
list_list = [[] for j in range(1, test_type_len + 1)] # 每个测试类型组合为一个列表[[],[],[],[]]
|
|
|
|
|
|
testType_list, last_chapter_items = create_csx_chapter_dict(hround)
|
|
|
|
|
|
testDemands = hround.rtField.all() # 本轮所有测试项
|
|
|
|
|
|
for demand in testDemands:
|
|
|
|
|
|
type_index = type_number_list.index(int(demand.testType))
|
|
|
|
|
|
demand_ident = get_ident(demand)
|
|
|
|
|
|
# ~~~组装测试项~~~
|
|
|
|
|
|
demand_last_chapter = last_chapter_items[demand.testType].index(demand.key) + 1
|
|
|
|
|
|
demand_chapter = ".".join([demand_prefix, str(testType_list.index(demand.testType) + 1),
|
|
|
|
|
|
str(demand_last_chapter)])
|
|
|
|
|
|
demand_dict = {
|
|
|
|
|
|
'name': demand.name,
|
|
|
|
|
|
'ident': demand_ident,
|
|
|
|
|
|
'chapter': demand_chapter,
|
|
|
|
|
|
'item': []
|
|
|
|
|
|
}
|
|
|
|
|
|
# ~~~这里组装测试项里面的测试用例~~~
|
|
|
|
|
|
for case in demand.tcField.all():
|
|
|
|
|
|
step_list = []
|
|
|
|
|
|
index = 1
|
|
|
|
|
|
for one in case.step.all():
|
|
|
|
|
|
# 这里需要对operation富文本处理
|
|
|
|
|
|
rich_parser = RichParser(one.operation)
|
|
|
|
|
|
desc_list = rich_parser.get_final_list(doc, img_size=68)
|
|
|
|
|
|
rich_parser2 = RichParser(one.result)
|
|
|
|
|
|
res_list = rich_parser2.get_final_list(doc, img_size=75)
|
|
|
|
|
|
# 组装用例里面的步骤dict
|
|
|
|
|
|
passed = '通过'
|
|
|
|
|
|
if one.passed == '2':
|
|
|
|
|
|
passed = '未通过'
|
|
|
|
|
|
if one.passed == '3':
|
|
|
|
|
|
passed = '未执行'
|
|
|
|
|
|
step_dict = {
|
|
|
|
|
|
'index': index,
|
|
|
|
|
|
'operation': desc_list,
|
|
|
|
|
|
'expect': one.expect,
|
|
|
|
|
|
'result': res_list,
|
|
|
|
|
|
'passed': passed,
|
|
|
|
|
|
}
|
|
|
|
|
|
step_list.append(step_dict)
|
|
|
|
|
|
index += 1
|
|
|
|
|
|
# 查询所有的problem
|
|
|
|
|
|
problem_list = []
|
|
|
|
|
|
problem_prefix = "PT"
|
|
|
|
|
|
proj_ident = project_obj.ident
|
|
|
|
|
|
for problem in case.caseField.all():
|
|
|
|
|
|
problem_list.append("_".join([problem_prefix, proj_ident, problem.ident]))
|
|
|
|
|
|
# fpga的时序图
|
|
|
|
|
|
rich_parser3 = RichParser(case.timing_diagram)
|
|
|
|
|
|
timing_diagram = rich_parser3.get_final_list(doc, img_size=115, height=50)
|
|
|
|
|
|
has_timing_diagram = False
|
|
|
|
|
|
if len(timing_diagram) > 0:
|
|
|
|
|
|
if isinstance(timing_diagram[0], InlineImage):
|
|
|
|
|
|
has_timing_diagram = True
|
|
|
|
|
|
# 组装用例的dict
|
|
|
|
|
|
case_dict = {
|
|
|
|
|
|
'name': case.name,
|
|
|
|
|
|
'ident': get_case_ident(demand_ident, case),
|
|
|
|
|
|
'summary': case.summarize,
|
|
|
|
|
|
'initialization': case.initialization,
|
|
|
|
|
|
'premise': case.premise,
|
|
|
|
|
|
'design_person': case.designPerson,
|
|
|
|
|
|
'test_person': case.testPerson,
|
|
|
|
|
|
'monitor_person': case.monitorPerson,
|
|
|
|
|
|
'step': step_list,
|
|
|
|
|
|
'time': str(case.exe_time) if case.exe_time is not None else str(case.update_datetime),
|
|
|
|
|
|
'problems': "、".join(problem_list),
|
|
|
|
|
|
'round_num_chn': cname,
|
|
|
|
|
|
# 2025年4月24日新增
|
|
|
|
|
|
'has_timing_diagram': has_timing_diagram,
|
|
|
|
|
|
'timing_diagram': timing_diagram,
|
|
|
|
|
|
}
|
|
|
|
|
|
demand_dict['item'].append(case_dict)
|
|
|
|
|
|
|
|
|
|
|
|
list_list[type_index].append(demand_dict)
|
|
|
|
|
|
# 定义渲染上下文
|
|
|
|
|
|
context = {}
|
|
|
|
|
|
output_list = []
|
|
|
|
|
|
for (index, li) in enumerate(list_list):
|
|
|
|
|
|
qs = Dict.objects.get(code="testType").dictItem.get(key=str(index + 1))
|
|
|
|
|
|
context_str = qs.title
|
|
|
|
|
|
sort = qs.sort
|
|
|
|
|
|
table = {
|
|
|
|
|
|
"type": context_str,
|
|
|
|
|
|
"item": li,
|
|
|
|
|
|
"sort": sort
|
|
|
|
|
|
}
|
|
|
|
|
|
output_list.append(table)
|
|
|
|
|
|
# 排序
|
|
|
|
|
|
output_list = sorted(output_list, key=(lambda x: x["sort"]))
|
|
|
|
|
|
context["data"] = output_list
|
|
|
|
|
|
# 最后渲染
|
|
|
|
|
|
save_path = Path.cwd() / 'media' / project_path_str / 'output_dir/hjl' / f"第{cname}轮测试用例记录.docx"
|
2025-12-19 18:08:19 +08:00
|
|
|
|
doc.render(context, autoescape=True)
|
2025-04-29 18:09:00 +08:00
|
|
|
|
try:
|
|
|
|
|
|
doc.save(save_path)
|
|
|
|
|
|
except PermissionError:
|
|
|
|
|
|
return ChenResponse(code=400, status=400, message='您打开了生成的文档,请关闭后重试')
|
|
|
|
|
|
return ChenResponse(code=200, status=200, message='多轮回归测试用例记录生成完毕')
|