feat: 修复 Java Runner command_line 参数传递 + DB-Java 比对功能

- 修复 orchestrator_db.py: Java Runner 未传递 command_line 参数导致 ABEND
- 新增 DB-Java 文件式运行 + DB 表比对功能
- 优化输出目录结构: output/<PROGRAM_ID>/cobol/
- 新增测试文件: test_java_comparison.py, test_java_e2e.py
- 更新 AI 使用日志
This commit is contained in:
hangshuo652
2026-09-09 21:35:21 +08:00
parent f712b7b527
commit bdc1584b3c
14 changed files with 2652 additions and 113 deletions
+40 -12
View File
@@ -1101,7 +1101,10 @@ def _coordinate_tertiary_fd(records, fd_prefixes, data_fields, term_types=None):
_apply(rec, master, pairs, 0)
_apply(rec, d, pairs, 0)
# rec1..n: 单明细匹配(主 + 该明细 = K(k+1),其余明细用大偏移避免误配)
# 无键配对的明细 FD(如仅按日期参照的休日主表)不参与键协同,跳过即可。
for k, d in enumerate(details):
if d not in dpairs:
continue
if k + 1 >= len(p):
continue
rec = records[p[k + 1]]
@@ -1496,6 +1499,7 @@ def main():
copybook_dirs=[str(d) for d in _cpy_dirs],
skip_jvm=True,
)
orch.run_java = True
vr = orch.run_all(generate_coverage=False)
# Copy output files to outdir (skip if src == dst to avoid self-copy)
@@ -1756,7 +1760,7 @@ def main():
else:
db_input = None
outpath = prog_outdir / 'main' / 'json' / (filepath.stem + '.json')
outpath = prog_outdir / 'cobol' / 'main' / 'json' / (filepath.stem + '.json')
output_json(records, outpath, roles,
fd_fields=fd_fields, field_to_fd=field_to_fd,
open_dir=open_dir,
@@ -1766,14 +1770,14 @@ def main():
select_info = parse_file_control(preprocessed)
output_input_files(records, prog_outdir / 'main' / 'input', filepath.stem, roles,
output_input_files(records, prog_outdir / 'cobol' / 'main' / 'input', filepath.stem, roles,
fd_fields, field_to_fd, open_dir,
term_types=term_types,
data_fields=fields_dict, select_info=select_info)
# P12: 子程序输入供给(CALL 目标子程序的 INPUT FD 输入文件)
_provision_sub_input_files(
source, str(filepath.parent), prog_outdir / 'main' / 'input'
source, str(filepath.parent), prog_outdir / 'cobol' / 'main' / 'input'
)
# ── Skip 数据集(主 FD 空文件触发 PERFORM UNTIL 条件即时满足)──
@@ -1793,13 +1797,13 @@ def main():
if eof_fd_dir in ('INPUT', 'I-O') and r in ('input', 'inout'):
del rec[fname]
# 写 Skip JSON
skip_outpath = prog_outdir / 'skip' / 'json' / (filepath.stem + '.json')
skip_outpath = prog_outdir / 'cobol' / 'run_skip' / 'json' / (filepath.stem + '.json')
output_json(skip_records, skip_outpath, roles,
fd_fields=fd_fields, field_to_fd=field_to_fd,
open_dir=open_dir, term_types=skip_term_types,
data_fields=fields_dict)
# 写 Skip 输入文件(主 FD 因字段已剥离而不输出)
skip_input_dir = prog_outdir / 'skip' / 'input'
skip_input_dir = prog_outdir / 'cobol' / 'run_skip' / 'input'
output_input_files(skip_records, skip_input_dir,
filepath.stem + '_skip', roles,
fd_fields, field_to_fd, open_dir,
@@ -1810,13 +1814,30 @@ def main():
eof_input_path.parent.mkdir(parents=True, exist_ok=True)
with open(eof_input_path, 'w', encoding='utf-8') as f:
json.dump([], f)
# 空二进制文件(COBOL INPUT 模式需要物理文件存在)
# 空二进制文件(COBOL INPUT 模式需要物理文件存在)
# 通用化:skip 数据集 = 全部输入 FD 均无记录,故为每个输入 FD 都落空文件,
# 而非仅主 FD(多输入程序若只建主 FD 空文件,其余 FD 运行时缺失,
# 只能依赖工作目录残留,Java/COBOL 干净场景下会 OPEN 失败)。
eof_assign = select_info.get(eof_fd, {}).get('assign', '')
if eof_assign:
bin_path = skip_input_dir / eof_assign
skip_input_assigns = []
seen_assign = set()
for _fd_name in fd_fields:
_dir = (open_dir or {}).get(_fd_name, '')
if _dir not in ('INPUT', 'I-O'):
continue
_assign = select_info.get(_fd_name, {}).get('assign', '')
if not _assign or _assign in seen_assign:
continue
seen_assign.add(_assign)
skip_input_assigns.append(_assign)
if eof_assign and eof_assign not in seen_assign:
skip_input_assigns.append(eof_assign)
for _assign in skip_input_assigns:
bin_path = skip_input_dir / _assign
bin_path.parent.mkdir(parents=True, exist_ok=True)
bin_path.write_bytes(b'')
logger.info(f" Skip 数据集: {skip_outpath}(空 {eof_fd}")
if not bin_path.exists():
bin_path.write_bytes(b'')
logger.info(f" Skip 数据集: {skip_outpath}(全部输入 FD 空文件: {', '.join(skip_input_assigns)}")
gcov_data = None
if gcov_mode and proc_div and _HAVE_GCOV and _HAVE_RUNNER:
@@ -1909,13 +1930,20 @@ def main():
if dp3_sample:
logger.info(f"DEBUG DP#3 other constraints: {sorted(dp3_sample)[:5]}")
cov_result = run_coverage(branch_tree, branch_paths_with_assigns, fields_dict,
orig_source, cov_prefix, index_relpath='index.html',
orig_source, cov_prefix,
index_relpath='../../coverage/index.html',
gcov_data=gcov_data)
programs.append(cov_result)
programs[-1]['detail_relpath'] = f'{filepath.stem}/coverage/{filepath.stem}_coverage.html'
if programs:
generate_coverage_index(programs, outdir / 'coverage')
# 总览 index.html 位于 <outdir>/coverage/detail_relpath(相对 <outdir>
# 需加一级 '../' 前缀才能从 index 定位到各程序明细页。
for _p in programs:
_rel = _p.get('detail_relpath') or ''
if _rel and not _rel.startswith(('http://', 'https://', '/', '../')):
_p['detail_relpath'] = '../' + _rel
generate_coverage_index(programs, outdir)
logger.info(f"\n覆盖率总览:{outdir / 'coverage' / 'index.html'}")