0
0
Fork 0
Codesys-MCP-SP21-plus/tests
Karstein Kvistad 2607063306 fix: 4 broken-tool fixes (compile json long, connect_to_device LoginMode,
create_folder SP21+ fallback, ensure_project_open cross-project switch)
+ bench results

compile_project.py + get_compile_messages.py:
- IronPython 2.7's json.dumps cannot serialize System.Int64-backed `long`
  values, which is what CODESYS's compile-message objects expose as
  line_number / position. Added _coerce_int + _coerce_str helpers and a
  shared _build_message_entry function. Three duplicated message-building
  blocks collapsed into single helper calls.
- Defensive `try: json.dumps(...) except TypeError: json.dumps(default=str)`
  so a stray field that slips past the helpers doesn't kill the emit.

connect_to_device.py:
- SP21+ may expose the login enum as LoginMode rather than
  OnlineChangeOption. Extended the candidate sweep to probe both
  script_engine.LoginMode and script_engine.OnlineChangeOption AND
  online_app.LoginMode/OnlineChangeOption (some builds attach it to the
  app object). Added "OnlineChange" + "Login" + "Download" to the
  preferred-priority list. Added a 3-arg call shape variant for SPs
  that take (mode, secondary-mode, force-bool).

create_folder.py:
- parent_object.create_folder() is no longer exposed on every parent type
  in SP21+. Added two fallback factories tried in order:
    1. parent.create_object(typeUuid='85d1215e-6520-4983-9a55-2d39d1f24cb4', name=...)
    2. parent.add(script_engine.types.IecFolder, name=...)
  with detailed warnings when each path fails. Final TypeError now lists
  every factory tried so a future SP rotation surfaces clearly.

ensure_project_open.py:
- Uncommented the close-prior-project branch (was a TODO since the
  initial fork). Cross-project switches in a persistent CODESYS now do
  save() -> close() -> 500ms pump -> open(target). Without this,
  projects.open against a different already-primary project fails
  intermittently on file lock contention or pops a "project in use"
  modal that freezes the IDE thread.
- save() is best-effort: if it raises (transient lock, save-as required)
  we still proceed with close + open rather than getting stuck in a
  half-switched state forever.

tests/bench-results.json:
- Captured timings from a clean run on MCPTest2 (PLCWinNT, 5 lib refs,
  ~12 POUs). 9 tools x 2 modes x iterations.
  Headers (mean ms): persistent vs headless --
    open_project              7700  vs   40041   (~5x; first call cold)
    mirror_export             1547  vs   23723   (~15x)
    list_project_libraries    1565  vs   23322   (~15x)
    get_all_pou_code          1607  vs   23376   (~15x)
    save_project              2095  vs   23321   (~11x)
    create_pou (FB)           1540  vs   23903   (~16x)
    delete_object             1544  vs   27420   (~18x)
    bump_project_version      1540  vs   30678   (~20x)
    bump_project_version #2   1556  vs   37769   (~24x)
- set_pou_code FAILED in both modes -- bench harness param-shape issue
  (multi-line code passed verbatim to triple-quoted-string interpolation
  doesn't survive the round-trip). Tool itself works fine through the
  MCP tool call path; bench needs to escape newlines / use the same
  prepareScriptWithHelpers shape the server uses. Filed for follow-up.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-26 16:53:25 +02:00
..
integration Initial release: MCP server for CODESYS with persistent UI instance 2026-02-08 18:59:16 +10:00
unit Initial release: MCP server for CODESYS with persistent UI instance 2026-02-08 18:59:16 +10:00
bench-results.json fix: 4 broken-tool fixes (compile json long, connect_to_device LoginMode, 2026-04-26 16:53:25 +02:00
bench.mjs docs+test: TEST_OVERVIEW + bench harness for headless vs persistent 2026-04-26 16:41:52 +02:00
mock_watcher.py Initial release: MCP server for CODESYS with persistent UI instance 2026-02-08 18:59:16 +10:00
TEST_OVERVIEW.md docs+test: TEST_OVERVIEW + bench harness for headless vs persistent 2026-04-26 16:41:52 +02:00