| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122 |
- """P5-M2 regression: MotorCADTaskExecutor mock-vs-real branch.
- Run: python scripts/test_executor_p5m2.py
- Verifies that enable_mock=True routes to the base-class mock solver (no
- Motor-CAD, no model_path required) and that enable_mock=False keeps the
- real-adapter contract (model_path required). exit 0 == PASS.
- NOTE: All strings in this file are ASCII only.
- """
- import json
- import os
- import sys
- import tempfile
- import unittest
- _SCRIPTS_DIR = os.path.dirname(os.path.abspath(__file__))
- if _SCRIPTS_DIR not in sys.path:
- sys.path.insert(0, _SCRIPTS_DIR)
- import task_executor as te # noqa: E402
- # local-file mode: no real web calls during the test
- te.requests = None
- def _make_local_task(tmp, tid, params):
- path = os.path.join(tmp, tid + "_task.json")
- with open(path, "w", encoding="utf-8") as fh:
- json.dump({"task_id": tid, "task_name": "p5m2",
- "parameters": params}, fh)
- return {"task_id": tid, "_local_file": path, "parameters": params}
- class MotorCADExecutorMockBranchTest(unittest.TestCase):
- """Exercise the enable_mock branch added in P5-M2."""
- def setUp(self):
- self.tmp = tempfile.mkdtemp(prefix="p5m2_exec_")
- def tearDown(self):
- import shutil
- shutil.rmtree(self.tmp, ignore_errors=True)
- def _run(self, executor, tid, params):
- executor.dispatch_task = lambda t: True
- captured = {}
- executor.on_complete = lambda t, res, met: captured.setdefault(t, res)
- executor.execute_task(_make_local_task(self.tmp, tid, params))
- return captured.get(tid)
- # ---------- happy path ----------
- def test_mock_point_source_and_no_model_required(self):
- ex = te.MotorCADTaskExecutor(task_dir=self.tmp, enable_mock=True,
- model_path=None)
- res = self._run(ex, "m1", [{"airgap_mm": 1.0, "point_id": 1}])
- self.assertEqual(len(res), 1)
- self.assertEqual(res[0]["status"], "OK")
- self.assertEqual(res[0]["source"], "mock")
- self.assertIn("tavg_nm", res[0])
- def test_mock_multi_point(self):
- ex = te.MotorCADTaskExecutor(task_dir=self.tmp, enable_mock=True,
- model_path=None)
- res = self._run(ex, "m2", [
- {"airgap_mm": 0.8, "point_id": 1},
- {"airgap_mm": 1.0, "point_id": 2},
- {"airgap_mm": 1.2, "point_id": 3},
- ])
- self.assertEqual(len(res), 3)
- for r in res:
- self.assertEqual(r["status"], "OK")
- self.assertEqual(r["source"], "mock")
- # ---------- boundary ----------
- def test_mock_with_illegal_model_path_still_mocks(self):
- # mock must win even when model_path points at a nonexistent file,
- # proving no Motor-CAD instance / adapter is launched.
- ex = te.MotorCADTaskExecutor(task_dir=self.tmp, enable_mock=True,
- model_path="Z:/nonexistent/model.mot")
- res = self._run(ex, "m3", [{"airgap_mm": 1.0, "point_id": 1}])
- self.assertEqual(res[0]["source"], "mock")
- def test_default_mock_off(self):
- # P4-M3 default: real solver adapter, so enable_mock defaults False
- ex = te.MotorCADTaskExecutor(task_dir=self.tmp, model_path=None)
- self.assertIs(ex.enable_mock, False)
- # ---------- abnormal ----------
- def test_real_mode_requires_model_path(self):
- ex = te.MotorCADTaskExecutor(task_dir=self.tmp, enable_mock=False,
- model_path=None)
- with self.assertRaises(RuntimeError):
- ex._run_simulation_point({"airgap_mm": 1.0}, 0)
- # ---------- metadata key exclusion ----------
- def test_point_id_excluded_from_motorcad_params(self):
- # Regression (P5-M2 real E2E): point_id is a passthrough
- # metadata key and must never be sent to Motor-CAD set_variable.
- src_path = os.path.join(_SCRIPTS_DIR, "robust_motorcad.py")
- with open(src_path, "r", encoding="utf-8") as fh:
- src = fh.read()
- self.assertIn(
- 'if var in ("point_index", "point_label", "point_id"):',
- src)
- # ---------- business alias ----------
- def test_business_alias_airgap_resolves(self):
- from robust_motorcad import resolve_variable_name
- self.assertEqual(resolve_variable_name("airgap_mm"), "Airgap")
- # unknown canonical names pass through untouched
- self.assertEqual(resolve_variable_name("SomeUnknown"), "SomeUnknown")
- # ---------- empty value ----------
- def test_mock_empty_model_path_string(self):
- ex = te.MotorCADTaskExecutor(task_dir=self.tmp, enable_mock=True,
- model_path="")
- res = self._run(ex, "m4", [{"airgap_mm": 1.0, "point_id": 1}])
- self.assertEqual(res[0]["source"], "mock")
- if __name__ == "__main__":
- unittest.main(verbosity=2)
|