fix(runner): isolate black-box groups in per-group work dirs; add test
This commit is contained in:
+16
-8
@@ -12,6 +12,7 @@ from dataclasses import dataclass, field
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from . import file_io
|
from . import file_io
|
||||||
|
from .blackbox import BlackBoxGroup
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@@ -1002,7 +1003,7 @@ def run_external_groups(program_name: str, outdir: str, temp_dir: str,
|
|||||||
fields_dict: list[dict], fd_fields: dict,
|
fields_dict: list[dict], fd_fields: dict,
|
||||||
select_info: dict, open_dir: dict,
|
select_info: dict, open_dir: dict,
|
||||||
roles: dict, field_to_fd: dict,
|
roles: dict, field_to_fd: dict,
|
||||||
groups: list, source_dir: str,
|
groups: list[BlackBoxGroup], source_dir: str,
|
||||||
data_fields: list[dict] | None = None,
|
data_fields: list[dict] | None = None,
|
||||||
multi_write_fds: set | None = None,
|
multi_write_fds: set | None = None,
|
||||||
java_src_dir: str | None = None
|
java_src_dir: str | None = None
|
||||||
@@ -1049,8 +1050,14 @@ def run_external_groups(program_name: str, outdir: str, temp_dir: str,
|
|||||||
base = Path(outdir) / 'black_box' / label
|
base = Path(outdir) / 'black_box' / label
|
||||||
src_in_dir = base / 'cobol' / 'input'
|
src_in_dir = base / 'cobol' / 'input'
|
||||||
dst_out_dir = base / 'cobol' / 'output'
|
dst_out_dir = base / 'cobol' / 'output'
|
||||||
|
group_work = work_dir / f'bb_{label}'
|
||||||
|
if group_work.exists():
|
||||||
|
shutil.rmtree(str(group_work), ignore_errors=True)
|
||||||
|
group_work.mkdir(parents=True, exist_ok=True)
|
||||||
if src_in_dir.exists():
|
if src_in_dir.exists():
|
||||||
shutil.rmtree(str(src_in_dir), ignore_errors=True)
|
shutil.rmtree(str(src_in_dir), ignore_errors=True)
|
||||||
|
if dst_out_dir.exists():
|
||||||
|
shutil.rmtree(str(dst_out_dir), ignore_errors=True)
|
||||||
|
|
||||||
output_input_files(
|
output_input_files(
|
||||||
records, src_in_dir, f'{program_name}_{label}', roles,
|
records, src_in_dir, f'{program_name}_{label}', roles,
|
||||||
@@ -1064,19 +1071,19 @@ def run_external_groups(program_name: str, outdir: str, temp_dir: str,
|
|||||||
if src_in_dir.is_dir():
|
if src_in_dir.is_dir():
|
||||||
for src in sorted(src_in_dir.iterdir()):
|
for src in sorted(src_in_dir.iterdir()):
|
||||||
if src.is_file() and src.suffix.lower() != '.json':
|
if src.is_file() and src.suffix.lower() != '.json':
|
||||||
shutil.copy2(str(src), str(work_dir / src.name))
|
shutil.copy2(str(src), str(group_work / src.name))
|
||||||
|
|
||||||
_clean_gcda(str(work_dir))
|
_clean_gcda(str(group_work))
|
||||||
group = GroupInfo(
|
group = GroupInfo(
|
||||||
name=f'{program_name}_black_box_{label}',
|
name=f'{program_name}_black_box_{label}',
|
||||||
records=records,
|
records=records,
|
||||||
expected_outputs=[{}] * len(records),
|
expected_outputs=[],
|
||||||
fd_field_dicts=fd_field_dicts,
|
fd_field_dicts=fd_field_dicts,
|
||||||
open_dir=open_dir,
|
open_dir=open_dir,
|
||||||
select_info=select_info,
|
select_info=select_info,
|
||||||
multi_write_fds=multi_write_fds or set(),
|
multi_write_fds=multi_write_fds or set(),
|
||||||
)
|
)
|
||||||
r = run_group(group, exe_path, str(work_dir), log_dir=log_dir)
|
r = run_group(group, exe_path, str(group_work), log_dir=log_dir)
|
||||||
results.append(r)
|
results.append(r)
|
||||||
logger.info(f" 组 '{group.name}': returncode={r.returncode}, "
|
logger.info(f" 组 '{group.name}': returncode={r.returncode}, "
|
||||||
f"{'✓' if r.passed else '✗'}")
|
f"{'✓' if r.passed else '✗'}")
|
||||||
@@ -1087,15 +1094,15 @@ def run_external_groups(program_name: str, outdir: str, temp_dir: str,
|
|||||||
continue
|
continue
|
||||||
sel = select_info.get(fd_name, {})
|
sel = select_info.get(fd_name, {})
|
||||||
assign = sel.get('assign', fd_name) if isinstance(sel, dict) else fd_name
|
assign = sel.get('assign', fd_name) if isinstance(sel, dict) else fd_name
|
||||||
src = os.path.join(str(work_dir), assign)
|
src = os.path.join(str(group_work), assign)
|
||||||
if os.path.exists(src):
|
if os.path.exists(src):
|
||||||
shutil.copy2(src, str(dst_out_dir / assign))
|
shutil.copy2(src, str(dst_out_dir / assign))
|
||||||
|
|
||||||
if java_cfg:
|
if java_cfg:
|
||||||
jrep = _run_java_scene(
|
jrep = _run_java_scene(
|
||||||
program_name, label,
|
program_name, f'bb_{label}',
|
||||||
base / 'java' / 'output',
|
base / 'java' / 'output',
|
||||||
str(work_dir),
|
str(group_work),
|
||||||
src_in_dir, dst_out_dir,
|
src_in_dir, dst_out_dir,
|
||||||
fd_field_dicts, open_dir, select_info,
|
fd_field_dicts, open_dir, select_info,
|
||||||
java_cfg, log_dir=log_dir, label=label,
|
java_cfg, log_dir=log_dir, label=label,
|
||||||
@@ -1103,6 +1110,7 @@ def run_external_groups(program_name: str, outdir: str, temp_dir: str,
|
|||||||
jrep['section'] = 'black_box'
|
jrep['section'] = 'black_box'
|
||||||
java_reports.append(jrep)
|
java_reports.append(jrep)
|
||||||
|
|
||||||
|
_clean_gcda(str(work_dir))
|
||||||
return results, java_reports
|
return results, java_reports
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,58 @@
|
|||||||
|
"""run_external_groups 编排测试(mock 编译/执行,不依赖 cobol/java 工具链)"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..")))
|
||||||
|
|
||||||
|
from cobol_testgen import runner
|
||||||
|
from cobol_testgen.blackbox import BlackBoxGroup
|
||||||
|
|
||||||
|
|
||||||
|
def test_run_external_groups_orchestration(tmp_path, monkeypatch):
|
||||||
|
fields_dict = [
|
||||||
|
{"name": "R01APPL-ID", "level": 3, "pic": "X(8)",
|
||||||
|
"pic_info": {"type": "alphanumeric", "digits": 0, "decimal": 0,
|
||||||
|
"length": 8, "signed": False}},
|
||||||
|
]
|
||||||
|
fd_fields = {"R01INNFIL": ["R01APPL-ID"], "W01OUTFIL": ["R01APPL-ID"]}
|
||||||
|
select_info = {"R01INNFIL": {"assign": "ZAN04R01"},
|
||||||
|
"W01OUTFIL": {"assign": "ZAN04W01",
|
||||||
|
"organization": "SEQUENTIAL"}}
|
||||||
|
open_dir = {"R01INNFIL": "INPUT", "W01OUTFIL": "OUTPUT"}
|
||||||
|
roles = {"R01APPL-ID": "input"}
|
||||||
|
field_to_fd = {"R01APPL-ID": "R01INNFIL"}
|
||||||
|
|
||||||
|
monkeypatch.setattr(runner, "compile_sub_modules", lambda *a, **k: [])
|
||||||
|
monkeypatch.setattr(runner, "compile_program",
|
||||||
|
lambda *a, **k: str(tmp_path / "P.exe"))
|
||||||
|
monkeypatch.setattr(runner, "_discover_java", lambda *a, **k: None)
|
||||||
|
|
||||||
|
calls = []
|
||||||
|
|
||||||
|
def fake_run_group(group, exe_path, temp_dir, log_dir=None):
|
||||||
|
calls.append((group.name, temp_dir))
|
||||||
|
Path(temp_dir, "ZAN04W01").write_bytes(b"A0000001")
|
||||||
|
return runner.GroupResult(name=group.name, returncode=0, passed=True)
|
||||||
|
|
||||||
|
monkeypatch.setattr(runner, "run_group", fake_run_group)
|
||||||
|
|
||||||
|
groups = [
|
||||||
|
BlackBoxGroup(label="g1",
|
||||||
|
records=[{"R01APPL-ID": "A0000001"}],
|
||||||
|
term_types=["normal"]),
|
||||||
|
BlackBoxGroup(label="g2", records=[], term_types=[]),
|
||||||
|
]
|
||||||
|
outdir = tmp_path / "out"
|
||||||
|
results, jreports = runner.run_external_groups(
|
||||||
|
"P", str(outdir), str(tmp_path / "work"),
|
||||||
|
fields_dict, fd_fields, select_info, open_dir,
|
||||||
|
roles, field_to_fd, groups, source_dir=str(tmp_path / "src"),
|
||||||
|
)
|
||||||
|
|
||||||
|
assert [r.name for r in results] == ["P_black_box_g1"]
|
||||||
|
assert jreports == []
|
||||||
|
out_file = outdir / "black_box" / "g1" / "cobol" / "output" / "ZAN04W01"
|
||||||
|
assert out_file.read_bytes() == b"A0000001"
|
||||||
|
assert "bb_g1" in calls[0][1]
|
||||||
Reference in New Issue
Block a user