linux_only / macos_only / windows_only were replaced by platforms(...)
and conftest now rejects them, but test docstrings and comments still
explained gating in terms of the old names, which points readers at a
marker they cannot use. Reword them to platforms("<os>") and the
-m platforms lane. ci.yaml's comment already says platforms("windows").
70 lines
2.9 KiB
Python
70 lines
2.9 KiB
Python
# -*- coding: utf-8 -*-
|
|
"""Regression tests for the launchd plist scan's malformed-file tolerance.
|
|
|
|
``_loaded_launchd_backend_jobs`` documents that unreadable or
|
|
malformed plists are skipped, but ``plistlib.load`` propagates
|
|
``xml.parsers.expat.ExpatError`` (which is NOT a ``ValueError`` subclass) for
|
|
XML that is not well-formed, so one hand-edited LaunchAgent plist aborted the
|
|
whole ``hermes update`` post-pull cleanup instead of being skipped.
|
|
"""
|
|
import os
|
|
from unittest import mock
|
|
|
|
import pytest
|
|
|
|
from hermes_cli import main_dashboard
|
|
|
|
# ``_loaded_launchd_backend_jobs`` reads ``sys.platform`` directly (no host seam), so
|
|
# the scan runs only on a real macOS host — never by faking the platform.
|
|
pytestmark = pytest.mark.platforms("macos")
|
|
|
|
|
|
# A plist that is not well-formed XML yet launchd itself tolerates: a raw `&&`
|
|
# in ProgramArguments is exactly what an operator writes when trying to chain
|
|
# two commands in one job.
|
|
MALFORMED_PLIST = (
|
|
'<?xml version="1.0" encoding="UTF-8"?>\n<plist version="1.0">\n<dict>\n'
|
|
" <key>Label</key>\n <string>com.example.bad</string>\n"
|
|
" <key>ProgramArguments</key>\n <array>\n"
|
|
" <string>/usr/local/bin/hermes</string>\n <string>&&</string>\n"
|
|
" </array>\n</dict>\n</plist>\n"
|
|
)
|
|
|
|
GOOD_PLIST = (
|
|
'<?xml version="1.0" encoding="UTF-8"?>\n<plist version="1.0">\n<dict>\n'
|
|
" <key>Label</key>\n <string>ai.hermes.dashboard.test</string>\n"
|
|
" <key>ProgramArguments</key>\n <array>\n"
|
|
" <string>/usr/local/bin/hermes</string>\n <string>dashboard</string>\n"
|
|
" <string>--port</string>\n <string>9119</string>\n"
|
|
" </array>\n</dict>\n</plist>\n"
|
|
)
|
|
|
|
|
|
def test_malformed_plist_is_skipped_not_fatal(tmp_path):
|
|
p = tmp_path / "com.example.bad.plist"
|
|
p.write_text(MALFORMED_PLIST, encoding="utf-8")
|
|
with mock.patch(
|
|
"hermes_cli.gateway._launchd_print_service_pid", return_value=(False, None)
|
|
) as probe:
|
|
assert main_dashboard._loaded_launchd_backend_jobs([("agent", tmp_path)]) == []
|
|
probe.assert_not_called() # the malformed job never reaches the launchctl probe
|
|
|
|
|
|
def test_malformed_sibling_does_not_hide_the_good_job(tmp_path):
|
|
(tmp_path / "com.example.bad.plist").write_text(MALFORMED_PLIST, encoding="utf-8")
|
|
(tmp_path / "ai.hermes.dashboard.test.plist").write_text(GOOD_PLIST, encoding="utf-8")
|
|
with mock.patch(
|
|
"hermes_cli.gateway._launchd_print_service_pid", return_value=(True, 4321)
|
|
) as probe:
|
|
jobs = main_dashboard._loaded_launchd_backend_jobs([("agent", tmp_path)])
|
|
assert jobs == [
|
|
(
|
|
f"gui/{os.getuid()}", # windows-footgun: ok — platforms("macos") file
|
|
"ai.hermes.dashboard.test",
|
|
["/usr/local/bin/hermes", "dashboard", "--port", "9119"],
|
|
4321,
|
|
)
|
|
]
|
|
# Only the well-formed label was probed against launchd.
|
|
assert [c.args[1] for c in probe.call_args_list] == ["ai.hermes.dashboard.test"]
|