6c853b43af
- Client.Dotnet-030: add advise-supervisory to IsKnownGatewayCommand (was dead/unreachable, exit 2) - Client.Go-035/036/037: usage+README list advise-supervisory; add session-id guard test; fix write2 README wording - Client.Python-037/038: drop regressed 'scaffold' from pyproject; add advise-supervisory CLI tests - Client.Rust-039/040: document write_array_elements/advise-supervisory in design doc; pin outer MxValue data_type==0 - Client.Java-049/050/051: sync CLIENT_VERSION to 0.1.2; add advise-supervisory test; guard negative uint32 inputs (pending windev gradle verification) Client READMEs also updated for Server-057 add-family normalization wording. .NET/Go/Python/Rust verified green locally; Java pending windev.
164 lines
5.4 KiB
Python
164 lines
5.4 KiB
Python
"""Regression tests for Client.Python-037 and Client.Python-038.
|
|
|
|
Client.Python-037: ``pyproject.toml`` description must not contain "scaffold".
|
|
Client.Python-038: ``advise-supervisory`` CLI subcommand must have coverage
|
|
(registration smoke test + happy-path command-shape test).
|
|
|
|
Tests are TDD-first — written before the fix and expected to pass once the
|
|
source change lands.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
from pathlib import Path
|
|
from typing import Any
|
|
|
|
from click.testing import CliRunner
|
|
|
|
from zb_mom_ww_mxgateway import ClientOptions, GatewayClient
|
|
from zb_mom_ww_mxgateway.generated import mxaccess_gateway_pb2 as pb
|
|
from zb_mom_ww_mxgateway_cli.commands import main
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Client.Python-037 — pyproject.toml description must not contain "scaffold".
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
def test_pyproject_description_does_not_contain_scaffold() -> None:
|
|
"""The ``description`` field in ``pyproject.toml`` must not include the
|
|
word "scaffold" — a regression of Client.Python-001 that re-entered the
|
|
file at the package-rename commit.
|
|
"""
|
|
|
|
pyproject = (
|
|
Path(__file__).resolve().parent.parent / "pyproject.toml"
|
|
).read_text(encoding="utf-8")
|
|
|
|
# Find the description line and assert "scaffold" is absent.
|
|
for line in pyproject.splitlines():
|
|
stripped = line.strip()
|
|
if stripped.startswith("description"):
|
|
assert "scaffold" not in stripped.lower(), (
|
|
f"pyproject.toml description must not contain 'scaffold': {stripped!r}"
|
|
)
|
|
return
|
|
|
|
raise AssertionError("pyproject.toml has no 'description' line")
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Client.Python-038 — advise-supervisory must be registered + have a happy path.
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
def test_advise_supervisory_is_registered() -> None:
|
|
"""``advise-supervisory`` must be a registered subcommand of ``main``.
|
|
|
|
A ``--help`` invocation must exit 0 and the help text must include the
|
|
required options (--server-handle and --item-handle).
|
|
"""
|
|
|
|
runner = CliRunner()
|
|
result = runner.invoke(main, ["advise-supervisory", "--help"])
|
|
|
|
assert result.exit_code == 0, result.output
|
|
assert "--server-handle" in result.output
|
|
assert "--item-handle" in result.output
|
|
|
|
|
|
# --------------- fake-stub infrastructure (mirrors test_review_findings_022_to_026) ----
|
|
|
|
|
|
class _FakeUnary:
|
|
def __init__(self, replies: list[Any]) -> None:
|
|
self.replies = replies
|
|
self.requests: list[Any] = []
|
|
self.metadata: tuple[tuple[str, str], ...] | None = None
|
|
|
|
async def __call__(self, request: Any, *, metadata: tuple[tuple[str, str], ...]) -> Any:
|
|
self.requests.append(request)
|
|
self.metadata = metadata
|
|
return self.replies.pop(0)
|
|
|
|
|
|
class _FakeStub:
|
|
def __init__(self) -> None:
|
|
self.open_session = _FakeUnary(
|
|
[
|
|
pb.OpenSessionReply(
|
|
session_id="session-1",
|
|
protocol_status=pb.ProtocolStatus(code=pb.PROTOCOL_STATUS_CODE_OK),
|
|
),
|
|
],
|
|
)
|
|
self.invoke = _FakeUnary([])
|
|
self.OpenSession = self.open_session
|
|
self.Invoke = self.invoke
|
|
|
|
def set_invoke_replies(self, replies: list[Any]) -> None:
|
|
self.invoke.replies = replies
|
|
|
|
|
|
def _install_fake_connect(monkeypatch: Any, stub: _FakeStub) -> None:
|
|
"""Patch ``GatewayClient.connect`` so the CLI uses the supplied fake stub."""
|
|
|
|
real_connect = GatewayClient.connect
|
|
|
|
@classmethod # type: ignore[misc]
|
|
async def _spy_connect(cls: Any, options: ClientOptions, **kwargs: Any) -> GatewayClient:
|
|
return await real_connect(options, stub=stub)
|
|
|
|
monkeypatch.setattr(GatewayClient, "connect", _spy_connect)
|
|
|
|
|
|
def test_cli_advise_supervisory_happy_path(monkeypatch: Any) -> None:
|
|
"""``advise-supervisory`` must forward server_handle and item_handle in an
|
|
``MX_COMMAND_KIND_ADVISE_SUPERVISORY`` ``MxCommand``.
|
|
|
|
Pattern mirrors ``test_cli_acknowledge_alarm_happy_path`` in
|
|
``test_review_findings_022_to_026.py``.
|
|
"""
|
|
|
|
stub = _FakeStub()
|
|
stub.set_invoke_replies(
|
|
[
|
|
pb.MxCommandReply(
|
|
session_id="session-1",
|
|
kind=pb.MX_COMMAND_KIND_ADVISE_SUPERVISORY,
|
|
protocol_status=pb.ProtocolStatus(code=pb.PROTOCOL_STATUS_CODE_OK),
|
|
),
|
|
],
|
|
)
|
|
_install_fake_connect(monkeypatch, stub)
|
|
|
|
runner = CliRunner()
|
|
result = runner.invoke(
|
|
main,
|
|
[
|
|
"advise-supervisory",
|
|
"--endpoint",
|
|
"localhost:5000",
|
|
"--plaintext",
|
|
"--session-id",
|
|
"session-1",
|
|
"--server-handle",
|
|
"7",
|
|
"--item-handle",
|
|
"42",
|
|
"--json",
|
|
],
|
|
)
|
|
|
|
assert result.exit_code == 0, result.output
|
|
payload = json.loads(result.output)
|
|
assert payload["ok"] is True
|
|
|
|
# Verify the MxCommand shape forwarded to the gateway.
|
|
assert len(stub.invoke.requests) == 1
|
|
cmd = stub.invoke.requests[0].command
|
|
assert cmd.kind == pb.MX_COMMAND_KIND_ADVISE_SUPERVISORY
|
|
assert cmd.advise_supervisory.server_handle == 7
|
|
assert cmd.advise_supervisory.item_handle == 42
|