Files
cobol-java-v3/tests/test_worker.py
hangshuo652 bc1d56d1a4 feat: Phase 2 complete — 13 Phases of COBOL type classification and test benchmark
P0.6: gcov infrastructure
P1: extract_structure output expansion (11 new feature fields)
P2: Confusion group rule engine (8 pairs + contradiction + backtrack)
P3: 4-factor confidence calculation + quality gate update
P4: 33+2 COBOL program type test samples (22 files, 7 categories)
P5: parametrized/ test data generation engine
P6: japanese_data.py lookup tables
P7-10: Type-specific test suites (~159 parametrized tests)
P11: Full classification pipeline (classify_program) + orchestrator integration
P12: Documentation (module-interfaces, test-plan v3.0, coverage-matrix)

Architecture decisions:
- classification_pipeline/ merged to hina/pipeline/
- parametrized/ as independent module
- japanese_data.py as root-level file
- hina/__all__ only exports classify_program()

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-19 23:51:55 +08:00

160 lines
5.7 KiB
Python

"""WR-01~07: Worker 进程测试"""
import sys, os, json, tempfile
from pathlib import Path
from unittest.mock import patch, MagicMock
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
from web.worker import main as worker_main
def _write_task(tasks_dir, task_id, status="queued", runner="native"):
data = {
"id": task_id, "status": status, "runner": runner,
"copybook": f"/tmp/{task_id}/copybook.cpy",
"cobol_src": f"/tmp/{task_id}/program.cbl",
"java_src": f"/tmp/{task_id}/java",
"mapping": f"/tmp/{task_id}/mapping.yaml",
}
(tasks_dir / f"{task_id}.json").write_text(json.dumps(data), encoding="utf-8")
# ── WR-01: No tasks ──
def test_worker_no_tasks():
"""WR-01: 空 tasks/ → 无操作"""
with tempfile.TemporaryDirectory() as tmp:
with patch("web.worker.TASKS_DIR", Path(tmp)), \
patch("web.worker.time") as mock_time:
mock_time.sleep.side_effect = KeyboardInterrupt
try:
worker_main()
except KeyboardInterrupt:
pass
assert True
# ── WR-02: Normal task ──
def test_worker_normal_task():
"""WR-02: queued 任务 → 处理"""
with tempfile.TemporaryDirectory() as tmp:
tasks_dir = Path(tmp)
_write_task(tasks_dir, "t001")
mock_vr = MagicMock(
program="T", status="PASS", fields_matched=5, fields_mismatched=0,
duration_s=0.5, runner="native", field_results=[], debug={},
)
with patch("web.worker.TASKS_DIR", tasks_dir), \
patch("config.Config") as mock_cfg, \
patch("orchestrator.run_pipeline", return_value=mock_vr), \
patch("web.worker.time") as mock_time:
mock_time.sleep.side_effect = KeyboardInterrupt
mock_cfg.return_value = MagicMock()
try:
worker_main()
except KeyboardInterrupt:
pass
assert (tasks_dir / "t001.json").exists()
# ── WR-03: null JSON / empty file ──
def test_worker_null_json():
"""WR-03: null JSON → error 状态写入"""
with tempfile.TemporaryDirectory() as tmp:
tasks_dir = Path(tmp)
(tasks_dir / "n.json").write_text("null")
with patch("web.worker.TASKS_DIR", tasks_dir), \
patch("web.worker.time") as mock_time:
mock_time.sleep.side_effect = KeyboardInterrupt
try:
worker_main()
except KeyboardInterrupt:
pass
data = json.loads((tasks_dir / "n.json").read_text(encoding="utf-8"))
assert data["status"] == "error"
def test_worker_empty_json():
"""WR-03b: 空文件 → error 状态写入"""
with tempfile.TemporaryDirectory() as tmp:
tasks_dir = Path(tmp)
(tasks_dir / "e.json").write_text("")
with patch("web.worker.TASKS_DIR", tasks_dir), \
patch("web.worker.time") as mock_time:
mock_time.sleep.side_effect = KeyboardInterrupt
try:
worker_main()
except KeyboardInterrupt:
pass
data = json.loads((tasks_dir / "e.json").read_text(encoding="utf-8"))
assert data["status"] == "error"
# ── WR-04: Spark without spark-submit ──
def test_worker_spark_no_submit():
"""WR-04: spark 无 spark-submit → worker 内部处理"""
with tempfile.TemporaryDirectory() as tmp:
tasks_dir = Path(tmp)
_write_task(tasks_dir, "s001", runner="spark")
with patch("web.worker.TASKS_DIR", tasks_dir), \
patch("config.Config") as mock_cfg, \
patch("orchestrator.run_pipeline") as mock_run, \
patch("web.worker.time") as mock_time:
mock_time.sleep.side_effect = KeyboardInterrupt
mock_cfg.return_value = MagicMock()
mock_run.return_value = MagicMock(
program="S", status="PASS", fields_matched=3, fields_mismatched=0,
duration_s=0.2, runner="spark", field_results=[], debug={},
)
try:
worker_main()
except KeyboardInterrupt:
pass
assert True
# ── WR-05: Multiple tasks ──
def test_worker_multiple_tasks():
"""WR-05: 2个 queued → 依次处理"""
with tempfile.TemporaryDirectory() as tmp:
tasks_dir = Path(tmp)
_write_task(tasks_dir, "a1")
_write_task(tasks_dir, "a2")
mock_vr = MagicMock(
program="M", status="PASS", fields_matched=4, fields_mismatched=0,
duration_s=0.1, runner="native", field_results=[], debug={},
)
with patch("web.worker.TASKS_DIR", tasks_dir), \
patch("config.Config") as mock_cfg, \
patch("orchestrator.run_pipeline", return_value=mock_vr), \
patch("web.worker.time") as mock_time:
mock_time.sleep.side_effect = KeyboardInterrupt
mock_cfg.return_value = MagicMock()
try:
worker_main()
except KeyboardInterrupt:
pass
assert True
# ── WR-07: Task state machine ──
def test_task_state_machine():
"""WR-07: 只处理 queued 任务"""
with tempfile.TemporaryDirectory() as tmp:
tasks_dir = Path(tmp)
_write_task(tasks_dir, "rt1", status="running")
with patch("web.worker.TASKS_DIR", tasks_dir), \
patch("web.worker.time") as mock_time:
mock_time.sleep.side_effect = KeyboardInterrupt
try:
worker_main()
except KeyboardInterrupt:
pass
data = json.loads((tasks_dir / "rt1.json").read_text(encoding="utf-8"))
assert data["status"] == "running"