feat(python): add galaxy-browse CLI subcommand (§4.6)
This commit is contained in:
@@ -216,11 +216,21 @@ def test_batch_continues_after_error_line() -> None:
|
||||
class _FakeGalaxyClient:
|
||||
"""Minimal async-context-manager fake satisfying the galaxy command bodies."""
|
||||
|
||||
def __init__(self, *, ok: bool = True, objects=None, last_deploy=None, events=None) -> None:
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
ok: bool = True,
|
||||
objects=None,
|
||||
last_deploy=None,
|
||||
events=None,
|
||||
browse_roots=None,
|
||||
) -> None:
|
||||
self._ok = ok
|
||||
self._objects = objects or []
|
||||
self._last_deploy = last_deploy
|
||||
self._events = events or []
|
||||
self._browse_roots = browse_roots or []
|
||||
self.browse_options = None
|
||||
|
||||
async def __aenter__(self) -> "_FakeGalaxyClient":
|
||||
return self
|
||||
@@ -234,6 +244,10 @@ class _FakeGalaxyClient:
|
||||
async def discover_hierarchy(self):
|
||||
return self._objects
|
||||
|
||||
async def browse(self, options=None):
|
||||
self.browse_options = options
|
||||
return self._browse_roots
|
||||
|
||||
async def get_last_deploy_time(self):
|
||||
# Mirrors galaxy.py: protobuf ToDatetime() yields a timezone-NAIVE UTC datetime.
|
||||
return self._last_deploy
|
||||
@@ -326,6 +340,145 @@ def test_galaxy_watch_serializes_deploy_events(monkeypatch: pytest.MonkeyPatch)
|
||||
assert len(payload["events"]) == 1
|
||||
|
||||
|
||||
class _FakeBrowseNode:
|
||||
"""Minimal stand-in for LazyBrowseNode covering the CLI render path."""
|
||||
|
||||
def __init__(self, obj, *, has_children_hint=False, children=None) -> None:
|
||||
self._object = obj
|
||||
self._has_children_hint = has_children_hint
|
||||
self._children = list(children or [])
|
||||
self._is_expanded = bool(children)
|
||||
self.expand_calls = 0
|
||||
|
||||
@property
|
||||
def object(self):
|
||||
return self._object
|
||||
|
||||
@property
|
||||
def has_children_hint(self) -> bool:
|
||||
return self._has_children_hint
|
||||
|
||||
@property
|
||||
def children(self):
|
||||
return list(self._children)
|
||||
|
||||
@property
|
||||
def is_expanded(self) -> bool:
|
||||
return self._is_expanded
|
||||
|
||||
async def expand(self) -> None:
|
||||
self.expand_calls += 1
|
||||
self._is_expanded = True
|
||||
|
||||
|
||||
def test_galaxy_browse_serializes_nested_nodes(monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
from zb_mom_ww_mxgateway.generated import galaxy_repository_pb2 as galaxy_pb
|
||||
|
||||
child = _FakeBrowseNode(
|
||||
galaxy_pb.GalaxyObject(gobject_id=8, tag_name="Pump001", contained_name="Pump001"),
|
||||
has_children_hint=False,
|
||||
)
|
||||
root = _FakeBrowseNode(
|
||||
galaxy_pb.GalaxyObject(gobject_id=7, tag_name="Area001", contained_name="Area001"),
|
||||
has_children_hint=True,
|
||||
children=[child],
|
||||
)
|
||||
_patch_galaxy_connect(monkeypatch, _FakeGalaxyClient(browse_roots=[root]))
|
||||
|
||||
result = CliRunner().invoke(
|
||||
main,
|
||||
["galaxy-browse", "--plaintext", "--json"],
|
||||
)
|
||||
|
||||
assert result.exit_code == 0, result.output
|
||||
payload = json.loads(result.output)
|
||||
assert payload["command"] == "galaxy-browse"
|
||||
assert len(payload["nodes"]) == 1
|
||||
node = payload["nodes"][0]
|
||||
assert node["tagName"] == "Area001"
|
||||
assert node["hasChildrenHint"] is True
|
||||
assert len(node["children"]) == 1
|
||||
assert node["children"][0]["gobjectId"] == 8
|
||||
assert node["children"][0]["children"] == []
|
||||
|
||||
|
||||
def test_galaxy_browse_renders_indented_text_tree(monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
from zb_mom_ww_mxgateway.generated import galaxy_repository_pb2 as galaxy_pb
|
||||
|
||||
child = _FakeBrowseNode(
|
||||
galaxy_pb.GalaxyObject(gobject_id=8, tag_name="Pump001", browse_name="Pump001"),
|
||||
)
|
||||
root = _FakeBrowseNode(
|
||||
galaxy_pb.GalaxyObject(gobject_id=7, tag_name="Area001", browse_name="Area001"),
|
||||
has_children_hint=True,
|
||||
children=[child],
|
||||
)
|
||||
_patch_galaxy_connect(monkeypatch, _FakeGalaxyClient(browse_roots=[root]))
|
||||
|
||||
result = CliRunner().invoke(
|
||||
main,
|
||||
["galaxy-browse", "--plaintext"],
|
||||
)
|
||||
|
||||
assert result.exit_code == 0, result.output
|
||||
lines = result.output.splitlines()
|
||||
assert lines[0] == "1"
|
||||
assert lines[1] == "+ Area001 Area001 (gobject 7)"
|
||||
assert lines[2] == " - Pump001 Pump001 (gobject 8)"
|
||||
|
||||
|
||||
def test_galaxy_browse_forwards_filter_options(monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
fake = _FakeGalaxyClient(browse_roots=[])
|
||||
_patch_galaxy_connect(monkeypatch, fake)
|
||||
|
||||
result = CliRunner().invoke(
|
||||
main,
|
||||
[
|
||||
"galaxy-browse",
|
||||
"--plaintext",
|
||||
"--category-id",
|
||||
"10",
|
||||
"--category-id",
|
||||
"12",
|
||||
"--template-chain-contains",
|
||||
"$Pump",
|
||||
"--tag-name-glob",
|
||||
"Area*",
|
||||
"--include-attributes",
|
||||
"--alarm-bearing-only",
|
||||
"--historized-only",
|
||||
"--json",
|
||||
],
|
||||
)
|
||||
|
||||
assert result.exit_code == 0, result.output
|
||||
options = fake.browse_options
|
||||
assert tuple(options.category_ids) == (10, 12)
|
||||
assert tuple(options.template_chain_contains) == ("$Pump",)
|
||||
assert options.tag_name_glob == "Area*"
|
||||
assert options.include_attributes is True
|
||||
assert options.alarm_bearing_only is True
|
||||
assert options.historized_only is True
|
||||
|
||||
|
||||
def test_galaxy_browse_expands_to_depth(monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
from zb_mom_ww_mxgateway.generated import galaxy_repository_pb2 as galaxy_pb
|
||||
|
||||
root = _FakeBrowseNode(
|
||||
galaxy_pb.GalaxyObject(gobject_id=7, tag_name="Area001"),
|
||||
has_children_hint=True,
|
||||
)
|
||||
_patch_galaxy_connect(monkeypatch, _FakeGalaxyClient(browse_roots=[root]))
|
||||
|
||||
result = CliRunner().invoke(
|
||||
main,
|
||||
["galaxy-browse", "--plaintext", "--depth", "2", "--json"],
|
||||
)
|
||||
|
||||
assert result.exit_code == 0, result.output
|
||||
assert root.expand_calls == 1
|
||||
|
||||
|
||||
def test_galaxy_commands_are_registered() -> None:
|
||||
runner = CliRunner()
|
||||
for command in (
|
||||
@@ -333,6 +486,7 @@ def test_galaxy_commands_are_registered() -> None:
|
||||
"galaxy-last-deploy",
|
||||
"galaxy-discover",
|
||||
"galaxy-watch",
|
||||
"galaxy-browse",
|
||||
):
|
||||
result = runner.invoke(main, [command, "--help"])
|
||||
assert result.exit_code == 0, result.output
|
||||
|
||||
Reference in New Issue
Block a user