e2e: port batch subcommand to all five client CLIs
scripts/run-client-e2e-tests.ps1 expects each language CLI to expose a `batch` subcommand that reads command lines from stdin, runs each through the normal subcommand dispatch, writes the JSON result, then a sentinel line `__MXGW_BATCH_EOR__`. The implementation lived on a divergent branch (commit6126099) that was never merged into main — this commit ports the same protocol to HEAD's renamed CLIs so the existing matrix script runs end-to-end. The protocol: - one line of stdin = one full CLI invocation - successful output → stdout, then __MXGW_BATCH_EOR__ - failure → {"error":"...","type":"error"} JSON on stdout, then __MXGW_BATCH_EOR__ (errors do NOT exit the loop) - empty line or EOF terminates the loop Per-CLI additions: .NET: RunBatchAsync + per-line StringWriter capture, JSON error envelope when forceJsonErrors is true. Two new tests in MxGatewayClientCliTests covering the success and error paths. Go: runBatch with bufio.Scanner, runs each line through the existing runWithIO switch with a buffered stdout writer. One new test pinning the EOR sentinel. Rust: new `Batch` variant on the clap Command enum, run_batch re-parses each line via Cli::try_parse_from. Two new tests in the inline mod tests block. Python: new `batch` click command in commands.py that uses CliRunner to dispatch each line; synthesises {"error",..."type"} JSON from click error messages when the captured output isn't already JSON-shaped. Three new tests in test_cli.py. Java: BatchCommand inner @Command with BufferedReader stdin loop, fresh commandLine() per dispatch with captured stdout/stderr PrintWriters; non-zero exit codes and uncaught exceptions both surface as JSON-error blocks. Two new tests. Also fixes scripts/run-client-e2e-tests.ps1 line 705: the Python invocation was still passing the old module name `mxgateway_cli` to `python -m`; the client SDK rename in397d3c5moved it to `zb_mom_ww_mxgateway_cli`. Without the fix the Python leg fails with "No module named mxgateway_cli" before reaching open-session. Verification: full matrix at the redeployed gateway (localhost:5120, running ZB.MOM.WW.MxGateway.Server.exe / ZB.MOM.WW.MxGateway.Worker.exe) with -SkipBulk -SkipReadWriteBulk -SkipParity -SkipAuth (those phases exercise bulk read/write CLI subcommands that also live on the divergent branch — porting those is a follow-up). All five clients report `closed=true, addedItems=120, eventCount=5` and overall `success=true`. Per-language unit tests pass: - dotnet: 59/59 - go: all packages clean - rust: cargo test --workspace clean - python: 42/42 - java: gradle build SUCCESSFUL Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -7,6 +7,8 @@ from click.testing import CliRunner
|
||||
from zb_mom_ww_mxgateway import __version__
|
||||
from zb_mom_ww_mxgateway_cli.commands import main
|
||||
|
||||
_BATCH_EOR = "__MXGW_BATCH_EOR__"
|
||||
|
||||
|
||||
def test_version_json_is_deterministic() -> None:
|
||||
runner = CliRunner()
|
||||
@@ -66,3 +68,59 @@ def test_cli_error_output_redacts_api_key() -> None:
|
||||
|
||||
assert result.exit_code != 0
|
||||
assert "mxgw_test_secret" not in result.output
|
||||
|
||||
|
||||
def test_batch_runs_version_command_and_writes_eor() -> None:
|
||||
runner = CliRunner()
|
||||
|
||||
result = runner.invoke(main, ["batch"], input="version --json\n")
|
||||
|
||||
assert result.exit_code == 0
|
||||
blocks = [block for block in result.output.split(_BATCH_EOR + "\n") if block]
|
||||
assert len(blocks) == 1
|
||||
payload = json.loads(blocks[0].strip())
|
||||
assert payload == {
|
||||
"client": "mxgw-py",
|
||||
"package": "mxaccess-gateway-client",
|
||||
"version": __version__,
|
||||
}
|
||||
|
||||
|
||||
def test_batch_terminates_on_empty_line() -> None:
|
||||
runner = CliRunner()
|
||||
|
||||
result = runner.invoke(
|
||||
main,
|
||||
["batch"],
|
||||
input="version --json\n\nversion --json\n",
|
||||
)
|
||||
|
||||
assert result.exit_code == 0
|
||||
# Only the first command runs; the empty line breaks the loop before the second.
|
||||
assert result.output.count(_BATCH_EOR) == 1
|
||||
|
||||
|
||||
def test_batch_continues_after_error_line() -> None:
|
||||
runner = CliRunner()
|
||||
|
||||
# First line is invalid (unknown subcommand), second is a valid version call.
|
||||
result = runner.invoke(
|
||||
main,
|
||||
["batch"],
|
||||
input="not-a-real-command\nversion --json\n",
|
||||
)
|
||||
|
||||
assert result.exit_code == 0
|
||||
assert result.output.count(_BATCH_EOR) == 2
|
||||
|
||||
blocks = [block for block in result.output.split(_BATCH_EOR + "\n") if block]
|
||||
assert len(blocks) == 2
|
||||
|
||||
# First block: error JSON ({"error": "...", "type": "..."}).
|
||||
error_payload = json.loads(blocks[0].strip().splitlines()[-1])
|
||||
assert "error" in error_payload
|
||||
assert "type" in error_payload
|
||||
|
||||
# Second block: successful version JSON.
|
||||
version_payload = json.loads(blocks[1].strip())
|
||||
assert version_payload["version"] == __version__
|
||||
|
||||
Reference in New Issue
Block a user