"""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"