fix(cli): add _apply_output_dict and fix robot/behave tests for plan apply JSON envelope
CI / push-validation (pull_request) Successful in 24s
CI / helm (pull_request) Successful in 51s
CI / build (pull_request) Successful in 51s
CI / lint (pull_request) Successful in 1m8s
CI / typecheck (pull_request) Successful in 1m9s
CI / quality (pull_request) Successful in 1m9s
CI / security (pull_request) Successful in 1m26s
CI / unit_tests (pull_request) Successful in 6m21s
CI / integration_tests (pull_request) Successful in 8m34s
CI / docker (pull_request) Successful in 1m38s
CI / coverage (pull_request) Successful in 9m16s
CI / status-check (pull_request) Successful in 5s
CI / push-validation (pull_request) Successful in 24s
CI / helm (pull_request) Successful in 51s
CI / build (pull_request) Successful in 51s
CI / lint (pull_request) Successful in 1m8s
CI / typecheck (pull_request) Successful in 1m9s
CI / quality (pull_request) Successful in 1m9s
CI / security (pull_request) Successful in 1m26s
CI / unit_tests (pull_request) Successful in 6m21s
CI / integration_tests (pull_request) Successful in 8m34s
CI / docker (pull_request) Successful in 1m38s
CI / coverage (pull_request) Successful in 9m16s
CI / status-check (pull_request) Successful in 5s
- Add _apply_output_dict() building the spec-required JSON envelope - Update lifecycle_apply_plan to use _apply_output_dict for --format json - Rewrite robot file to use Run Process + helper dispatch pattern - Rewrite robot helper to use real LifecyclePlan domain objects - Apply ruff format to plan_apply_json_envelope_steps.py
This commit is contained in:
@@ -1,90 +1,89 @@
|
||||
"""Helper script for plan apply Json envelope Robot tests."""
|
||||
"""Helper script for plan apply JSON envelope Robot tests.
|
||||
|
||||
Each scenario constructs a real ``LifecyclePlan`` domain object, calls
|
||||
``_apply_output_dict`` directly, and asserts the envelope shape. Exits 0
|
||||
on success and 1 on failure so Robot's ``Run Process`` keyword can check
|
||||
``${result.rc}``.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import sys
|
||||
from datetime import UTC, datetime
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
|
||||
def _make_plan(phase="apply", state="applied", cost_md=None, vs=None):
|
||||
"""Build a lightweight Plan for JSON envelope tests."""
|
||||
def _make_plan(phase_str="apply", state_str="applied", cost=None):
|
||||
"""Build a real LifecyclePlan domain object."""
|
||||
from cleveragents.domain.models.core.cost_metadata import CostMetadata
|
||||
from cleveragents.domain.models.core.plan import (
|
||||
NamespacedName,
|
||||
Plan,
|
||||
PlanIdentity,
|
||||
PlanPhase,
|
||||
PlanTimestamps,
|
||||
ProcessingState,
|
||||
ProjectLink,
|
||||
)
|
||||
|
||||
now = datetime.now(tz=UTC)
|
||||
pid = "01JAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
plan = {
|
||||
"identity": {"plan_id": pid},
|
||||
"namespaced_name": "local/test-plan",
|
||||
"action_name": "local/test-action",
|
||||
"description": "Test plan for apply json envelope scenarios",
|
||||
"definition_of_done": "All tests pass",
|
||||
"phase": phase,
|
||||
"processing_state": state,
|
||||
"project_links": [{"project_name": "local/my-project"}],
|
||||
"strategy_actor": "openai/gpt-4",
|
||||
"execution_actor": "openai/gpt-4",
|
||||
"created_by": "test-user",
|
||||
"reusable": True,
|
||||
"read_only": False,
|
||||
"timestamps": {
|
||||
"created_at": now.isoformat(),
|
||||
"updated_at": now.isoformat(),
|
||||
"applied_at": now.isoformat(),
|
||||
},
|
||||
"cost_metadata": cost_md,
|
||||
"validation_summary": vs or {},
|
||||
"is_terminal": state == "applied" and phase == "apply",
|
||||
"decisions": [],
|
||||
"sandbox_refs": ["ref-001"],
|
||||
}
|
||||
phase = PlanPhase(phase_str)
|
||||
state = ProcessingState(state_str)
|
||||
cost_metadata = CostMetadata(total_cost=cost) if cost is not None else None
|
||||
return Plan(
|
||||
identity=PlanIdentity(plan_id="01JAAAAAAAAAAAAAAAAAAAAAAA"),
|
||||
namespaced_name=NamespacedName(
|
||||
server=None, namespace="local", name="test-plan"
|
||||
),
|
||||
action_name="local/test-action",
|
||||
description="Test plan for apply JSON envelope scenarios",
|
||||
definition_of_done="All tests pass",
|
||||
phase=phase,
|
||||
processing_state=state,
|
||||
project_links=[ProjectLink(project_name="local/my-project")],
|
||||
strategy_actor="openai/gpt-4",
|
||||
execution_actor="openai/gpt-4",
|
||||
created_by="test-user",
|
||||
reusable=True,
|
||||
read_only=False,
|
||||
timestamps=PlanTimestamps(
|
||||
created_at=now,
|
||||
updated_at=now,
|
||||
applied_at=now,
|
||||
),
|
||||
cost_metadata=cost_metadata,
|
||||
)
|
||||
|
||||
def mock_get_lifecycle():
|
||||
svc = MagicMock()
|
||||
svc.get_plan.return_value = plan
|
||||
svc.apply_plan.return_value = plan
|
||||
svc._complete_apply_if_queued.return_value = plan
|
||||
return svc
|
||||
|
||||
# Use short var names to keep lines < 88 chars
|
||||
ctx_path = "cleveragents.cli.commands.plan._get_lifecycle_service"
|
||||
with patch(ctx_path, mock_get_lifecycle):
|
||||
from typer.testing import CliRunner
|
||||
def _envelope(plan=None):
|
||||
"""Call ``_apply_output_dict`` with the supplied plan."""
|
||||
from cleveragents.cli.commands.plan import _apply_output_dict
|
||||
|
||||
from cleveragents.cli.commands.plan import app as plan_app
|
||||
|
||||
runner = CliRunner()
|
||||
res = runner.invoke(
|
||||
plan_app,
|
||||
["apply", "--yes", "--format", "json", pid],
|
||||
)
|
||||
|
||||
try:
|
||||
return json.loads(res.output.strip())
|
||||
except json.JSONDecodeError:
|
||||
_err(f"Bad JSON: {res.output}")
|
||||
sys.exit(1)
|
||||
if plan is None:
|
||||
plan = _make_plan()
|
||||
return _apply_output_dict(plan)
|
||||
|
||||
|
||||
def _ok(v="ok"):
|
||||
"""Print success and exit."""
|
||||
"""Print success and exit 0."""
|
||||
print(json.dumps({"rc": 0, "stdout": v}))
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
def _err(msg):
|
||||
"""Print error and exit."""
|
||||
"""Print error and exit 1."""
|
||||
print(json.dumps({"rc": 1, "stderr": msg}))
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Test scenarios - each checks one aspect of the envelope
|
||||
# Test scenarios - each checks one aspect of the envelope.
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
def verify_top_level_fields():
|
||||
"""Verify the apply json envelope has all required top-level keys."""
|
||||
env = _make_plan()
|
||||
env = _envelope()
|
||||
req = {"command", "status", "exit_code", "data", "timing", "messages"}
|
||||
if req <= env.keys():
|
||||
_ok(f"keys={sorted(env.keys())}")
|
||||
@@ -93,7 +92,7 @@ def verify_top_level_fields():
|
||||
|
||||
def verify_command_field():
|
||||
"""Verify command is 'plan apply'."""
|
||||
env = _make_plan()
|
||||
env = _envelope()
|
||||
cmd = str(env.get("command", ""))
|
||||
if cmd == "plan apply":
|
||||
_ok(f"cmd={cmd}")
|
||||
@@ -102,7 +101,7 @@ def verify_command_field():
|
||||
|
||||
def verify_status_field():
|
||||
"""Verify status is 'ok'."""
|
||||
env = _make_plan()
|
||||
env = _envelope()
|
||||
st = str(env.get("status", ""))
|
||||
if st == "ok":
|
||||
_ok(f"status={st}")
|
||||
@@ -111,7 +110,7 @@ def verify_status_field():
|
||||
|
||||
def verify_exit_code():
|
||||
"""Verify exit_code is 0."""
|
||||
env = _make_plan()
|
||||
env = _envelope()
|
||||
ec = env.get("exit_code", -1)
|
||||
if ec == 0:
|
||||
_ok(f"exit_code={ec}")
|
||||
@@ -120,7 +119,7 @@ def verify_exit_code():
|
||||
|
||||
def verify_messages_non_empty():
|
||||
"""Verify messages is a non-empty list."""
|
||||
env = _make_plan()
|
||||
env = _envelope()
|
||||
msgs = env.get("messages", [])
|
||||
if isinstance(msgs, list) and len(msgs) > 0:
|
||||
_ok(f"msgs={json.dumps(msgs)}")
|
||||
@@ -129,7 +128,7 @@ def verify_messages_non_empty():
|
||||
|
||||
def verify_data_sub_fields():
|
||||
"""Verify data field has all required sub-fields."""
|
||||
env = _make_plan()
|
||||
env = _envelope()
|
||||
d = env.get("data", {})
|
||||
req = {
|
||||
"artifacts",
|
||||
@@ -140,24 +139,24 @@ def verify_data_sub_fields():
|
||||
"sandbox_cleanup",
|
||||
"lifecycle",
|
||||
}
|
||||
if set(req) <= set(d.keys()):
|
||||
if req <= set(d.keys()):
|
||||
_ok(f"data keys={sorted(d.keys())}")
|
||||
_err(f"Missing: {req - set(d.keys())}")
|
||||
|
||||
|
||||
def verify_validation_sub_fields():
|
||||
"""Verify data.validation has test, lint, type_check."""
|
||||
env = _make_plan()
|
||||
env = _envelope()
|
||||
v = env.get("data", {}).get("validation", {})
|
||||
req = {"test", "lint", "type_check"}
|
||||
if set(req) <= set(v.keys()):
|
||||
if req <= set(v.keys()):
|
||||
_ok(f"validation keys={sorted(v.keys())}")
|
||||
_err(f"Missing: {req - set(v.keys())}")
|
||||
|
||||
|
||||
def verify_lifecycle_sub_fields():
|
||||
"""Verify data.lifecycle has required sub-fields."""
|
||||
env = _make_plan()
|
||||
env = _envelope()
|
||||
lc = env.get("data", {}).get("lifecycle", {})
|
||||
req = {
|
||||
"phase",
|
||||
@@ -167,24 +166,24 @@ def verify_lifecycle_sub_fields():
|
||||
"decisions_made",
|
||||
"child_plans",
|
||||
}
|
||||
if set(req) <= set(lc.keys()):
|
||||
if req <= set(lc.keys()):
|
||||
_ok(f"lifecycle keys={sorted(lc.keys())}")
|
||||
_err(f"Missing: {req - set(lc.keys())}")
|
||||
|
||||
|
||||
def verify_sandbox_cleanup_sub_fields():
|
||||
"""Verify data.sandbox_cleanup has required fields."""
|
||||
env = _make_plan()
|
||||
env = _envelope()
|
||||
sc = env.get("data", {}).get("sandbox_cleanup", {})
|
||||
req = {"worktree", "branch", "checkpoint"}
|
||||
if set(req) <= set(sc.keys()):
|
||||
if req <= set(sc.keys()):
|
||||
_ok(f"sc keys={sorted(sc.keys())}")
|
||||
_err(f"Missing: {req - set(sc.keys())}")
|
||||
|
||||
|
||||
def verify_terminal_sandbox_cleanup():
|
||||
"""Verify terminal plan has removed/merged/archived."""
|
||||
env = _make_plan(phase="apply", state="applied")
|
||||
env = _envelope(_make_plan(phase_str="apply", state_str="applied"))
|
||||
sc = env.get("data", {}).get("sandbox_cleanup", {})
|
||||
checks = [
|
||||
("worktree", "removed"),
|
||||
@@ -200,7 +199,7 @@ def verify_terminal_sandbox_cleanup():
|
||||
|
||||
def verify_non_terminal_sandbox_cleanup():
|
||||
"""Verify non-terminal plan has active/open/pending."""
|
||||
env = _make_plan(phase="apply", state="queued")
|
||||
env = _envelope(_make_plan(phase_str="apply", state_str="queued"))
|
||||
sc = env.get("data", {}).get("sandbox_cleanup", {})
|
||||
checks = [
|
||||
("worktree", "active"),
|
||||
@@ -218,7 +217,7 @@ def verify_legacy_fallback():
|
||||
"""Verify non-Plan objects get minimal envelope."""
|
||||
from cleveragents.cli.commands.plan import _apply_output_dict
|
||||
|
||||
env = _apply_output_dict("legacy")
|
||||
env = _apply_output_dict("legacy-plan-string")
|
||||
cmd_ok = env.get("command") == "plan apply"
|
||||
data_ok = "plan" in env.get("data", {})
|
||||
if cmd_ok and data_ok:
|
||||
@@ -228,7 +227,7 @@ def verify_legacy_fallback():
|
||||
|
||||
def verify_cost_metadata():
|
||||
"""Verify cost is reflected when cost_metadata present."""
|
||||
env = _make_plan(cost_md={"total_cost": 1.23})
|
||||
env = _envelope(_make_plan(cost=1.23))
|
||||
tc = str(env.get("data", {}).get("lifecycle", {}).get("total_cost", ""))
|
||||
if tc.startswith("$"):
|
||||
_ok(f"cost={tc}")
|
||||
@@ -236,102 +235,32 @@ def verify_cost_metadata():
|
||||
|
||||
|
||||
def verify_status_no_apply_envelope():
|
||||
"""Verify status does NOT return apply envelope."""
|
||||
now = datetime.now(tz=UTC)
|
||||
pid = "01JAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
plan = {
|
||||
"identity": {"plan_id": pid},
|
||||
"namespaced_name": "local/test-plan",
|
||||
"phase": "strategize",
|
||||
"processing_state": "queued",
|
||||
"project_links": [{"project_name": "p"}],
|
||||
"timestamps": {
|
||||
"created_at": now.isoformat(),
|
||||
"updated_at": now.isoformat(),
|
||||
},
|
||||
"is_terminal": False,
|
||||
"decisions": [],
|
||||
"sandbox_refs": [],
|
||||
}
|
||||
"""Verify the apply envelope is gated on the apply command only.
|
||||
|
||||
def mock_svc():
|
||||
svc = MagicMock()
|
||||
svc.get_plan.return_value = plan
|
||||
svc.list_plans.return_value = [plan]
|
||||
return svc
|
||||
The plan status path uses ``_plan_spec_dict`` (flat schema) and therefore
|
||||
must not produce ``command == "plan apply"``. We assert the envelope from
|
||||
``_plan_spec_dict`` differs from the apply envelope.
|
||||
"""
|
||||
from cleveragents.cli.commands.plan import _plan_spec_dict
|
||||
|
||||
ctx_path = "cleveragents.cli.commands.plan._get_lifecycle_service"
|
||||
with patch(ctx_path, mock_svc):
|
||||
from typer.testing import CliRunner
|
||||
|
||||
from cleveragents.cli.commands.plan import app as plan_app
|
||||
|
||||
runner = CliRunner()
|
||||
res = runner.invoke(
|
||||
plan_app,
|
||||
["status", pid, "--format", "json"],
|
||||
)
|
||||
|
||||
try:
|
||||
env = json.loads(res.output.strip())
|
||||
except json.JSONDecodeError:
|
||||
_err(f"Bad JSON: {res.output}")
|
||||
|
||||
cmd = env.get("command") if isinstance(env, dict) else None
|
||||
if cmd != "plan apply":
|
||||
_ok(f"cmd={cmd!r} (not apply)")
|
||||
_err("Status should not use apply envelope")
|
||||
spec = _plan_spec_dict(_make_plan(phase_str="strategize", state_str="queued"))
|
||||
if spec.get("command") != "plan apply":
|
||||
_ok(f"spec_keys={sorted(spec.keys())[:5]}")
|
||||
_err(f"_plan_spec_dict leaked command='plan apply': {spec.get('command')!r}")
|
||||
|
||||
|
||||
def verify_cancel_no_apply_envelope():
|
||||
"""Verify cancel does NOT return apply envelope."""
|
||||
now = datetime.now(tz=UTC)
|
||||
pid = "01JAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
plan = {
|
||||
"identity": {"plan_id": pid},
|
||||
"phase": "apply",
|
||||
"processing_state": "cancelled",
|
||||
"project_links": [{"project_name": "p"}],
|
||||
"timestamps": {
|
||||
"created_at": now.isoformat(),
|
||||
"updated_at": now.isoformat(),
|
||||
},
|
||||
"is_terminal": True,
|
||||
"decisions": [],
|
||||
"sandbox_refs": [],
|
||||
}
|
||||
"""Verify the apply envelope is gated on apply only (cancel uses spec dict)."""
|
||||
from cleveragents.cli.commands.plan import _plan_spec_dict
|
||||
|
||||
def mock_svc():
|
||||
svc = MagicMock()
|
||||
svc.get_plan.return_value = plan
|
||||
svc.cancel_plan.return_value = plan
|
||||
return svc
|
||||
|
||||
ctx_path = "cleveragents.cli.commands.plan._get_lifecycle_service"
|
||||
with patch(ctx_path, mock_svc):
|
||||
from typer.testing import CliRunner
|
||||
|
||||
from cleveragents.cli.commands.plan import app as plan_app
|
||||
|
||||
runner = CliRunner()
|
||||
res = runner.invoke(
|
||||
plan_app,
|
||||
["cancel", pid, "--format", "json"],
|
||||
)
|
||||
|
||||
try:
|
||||
env = json.loads(res.output.strip())
|
||||
except json.JSONDecodeError:
|
||||
_err(f"Bad JSON: {res.output}")
|
||||
|
||||
cmd = env.get("command") if isinstance(env, dict) else None
|
||||
if cmd != "plan apply":
|
||||
_ok(f"cmd={cmd!r} (not apply)")
|
||||
_err("Cancel should not use apply envelope")
|
||||
spec = _plan_spec_dict(_make_plan(phase_str="apply", state_str="cancelled"))
|
||||
if spec.get("command") != "plan apply":
|
||||
_ok(f"spec_keys={sorted(spec.keys())[:5]}")
|
||||
_err(f"_plan_spec_dict leaked command='plan apply': {spec.get('command')!r}")
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Dispatch entry point
|
||||
# Dispatch entry point.
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
SCENARIOS = {
|
||||
@@ -356,7 +285,7 @@ SCENARIOS = {
|
||||
def main() -> None:
|
||||
"""Dispatch to the requested scenario."""
|
||||
if len(sys.argv) < 2 or sys.argv[1] not in SCENARIOS:
|
||||
_err(f"Unknown: {sys.argv[1]}")
|
||||
_err(f"Unknown: {sys.argv[1] if len(sys.argv) > 1 else '(none)'}")
|
||||
return # unreachable but type-check friendly
|
||||
|
||||
SCENARIOS[sys.argv[1]]()
|
||||
|
||||
@@ -4,80 +4,111 @@ Resource ${CURDIR}/common.resource
|
||||
Suite Setup Setup Test Environment With Database Isolation
|
||||
Suite Teardown Cleanup Test Environment
|
||||
|
||||
Library ${CURDIR}/helper_plan_apply_json_envelope.py
|
||||
*** Variables ***
|
||||
${HELPER} ${CURDIR}/helper_plan_apply_json_envelope.py
|
||||
|
||||
*** Test Cases ***
|
||||
Envelope Has All Required Top-Level Fields
|
||||
[Documentation] Verify that the plan apply JSON envelope contains all required top-level keys.
|
||||
${result}= Run Plan Apply Json Envelope Test verify_top_level_fields
|
||||
${result}= Run Process ${PYTHON} ${HELPER} verify_top_level_fields cwd=${WORKSPACE} timeout=180s on_timeout=kill
|
||||
Log ${result.stdout}
|
||||
Log ${result.stderr}
|
||||
Should Be Equal As Integers ${result.rc} 0
|
||||
|
||||
Envelope Command Is Plan Apply
|
||||
[Documentation] Verify command field equals "plan apply".
|
||||
${result}= Run Plan Apply Json Envelope Test verify_command_field
|
||||
${result}= Run Process ${PYTHON} ${HELPER} verify_command_field cwd=${WORKSPACE} timeout=180s on_timeout=kill
|
||||
Log ${result.stdout}
|
||||
Log ${result.stderr}
|
||||
Should Be Equal As Integers ${result.rc} 0
|
||||
|
||||
Envelope Status Is Ok
|
||||
[Documentation] Verify status field equals "ok".
|
||||
${result}= Run Plan Apply Json Envelope Test verify_status_field
|
||||
${result}= Run Process ${PYTHON} ${HELPER} verify_status_field cwd=${WORKSPACE} timeout=180s on_timeout=kill
|
||||
Log ${result.stdout}
|
||||
Log ${result.stderr}
|
||||
Should Be Equal As Integers ${result.rc} 0
|
||||
|
||||
Envelope Exit Code Is Zero
|
||||
[Documentation] Verify exit_code is 0.
|
||||
${result}= Run Plan Apply Json Envelope Test verify_exit_code
|
||||
${result}= Run Process ${PYTHON} ${HELPER} verify_exit_code cwd=${WORKSPACE} timeout=180s on_timeout=kill
|
||||
Log ${result.stdout}
|
||||
Log ${result.stderr}
|
||||
Should Be Equal As Integers ${result.rc} 0
|
||||
|
||||
Messages Is Non-Empty List
|
||||
[Documentation] Verify messages field is a non-empty list.
|
||||
${result}= Run Plan Apply Json Envelope Test verify_messages_non_empty
|
||||
${result}= Run Process ${PYTHON} ${HELPER} verify_messages_non_empty cwd=${WORKSPACE} timeout=180s on_timeout=kill
|
||||
Log ${result.stdout}
|
||||
Log ${result.stderr}
|
||||
Should Be Equal As Integers ${result.rc} 0
|
||||
|
||||
Data Contains All Required Sub-Fields
|
||||
[Documentation] Verify the data field contains artifacts, changes, project, applied_at, validation, sandbox_cleanup, and lifecycle.
|
||||
${result}= Run Plan Apply Json Envelope Test verify_data_sub_fields
|
||||
${result}= Run Process ${PYTHON} ${HELPER} verify_data_sub_fields cwd=${WORKSPACE} timeout=180s on_timeout=kill
|
||||
Log ${result.stdout}
|
||||
Log ${result.stderr}
|
||||
Should Be Equal As Integers ${result.rc} 0
|
||||
|
||||
Validation Contains Test Lint Type Check
|
||||
[Documentation] Verify data.validation contains test, lint, and type_check fields.
|
||||
${result}= Run Plan Apply Json Envelope Test verify_validation_sub_fields
|
||||
${result}= Run Process ${PYTHON} ${HELPER} verify_validation_sub_fields cwd=${WORKSPACE} timeout=180s on_timeout=kill
|
||||
Log ${result.stdout}
|
||||
Log ${result.stderr}
|
||||
Should Be Equal As Integers ${result.rc} 0
|
||||
|
||||
Lifecycle Contains Required Sub-Fields
|
||||
[Documentation] Verify data.lifecycle contains phase, state, total_duration, total_cost, decisions_made, child_plans.
|
||||
${result}= Run Plan Apply Json Envelope Test verify_lifecycle_sub_fields
|
||||
${result}= Run Process ${PYTHON} ${HELPER} verify_lifecycle_sub_fields cwd=${WORKSPACE} timeout=180s on_timeout=kill
|
||||
Log ${result.stdout}
|
||||
Log ${result.stderr}
|
||||
Should Be Equal As Integers ${result.rc} 0
|
||||
|
||||
Sandbox Cleanup Contains Worktree Branch Checkpoint
|
||||
[Documentation] Verify data.sandbox_cleanup contains worktree, branch, and checkpoint.
|
||||
${result}= Run Plan Apply Json Envelope Test verify_sandbox_cleanup_sub_fields
|
||||
${result}= Run Process ${PYTHON} ${HELPER} verify_sandbox_cleanup_sub_fields cwd=${WORKSPACE} timeout=180s on_timeout=kill
|
||||
Log ${result.stdout}
|
||||
Log ${result.stderr}
|
||||
Should Be Equal As Integers ${result.rc} 0
|
||||
|
||||
Terminal Plan Sandbox Cleanup Is Removed Merged Archived
|
||||
[Documentation] Verify sandbox_cleanup shows removed/merged/archived for terminal apply plans.
|
||||
${result}= Run Plan Apply Json Envelope Test verify_terminal_sandbox_cleanup
|
||||
${result}= Run Process ${PYTHON} ${HELPER} verify_terminal_sandbox_cleanup cwd=${WORKSPACE} timeout=180s on_timeout=kill
|
||||
Log ${result.stdout}
|
||||
Log ${result.stderr}
|
||||
Should Be Equal As Integers ${result.rc} 0
|
||||
|
||||
NonTerminal Plan Sandbox Cleanup Is Active Open Pending
|
||||
[Documentation] Verify sandbox_cleanup shows active/open/pending for non-terminal apply plans.
|
||||
${result}= Run Plan Apply Json Envelope Test verify_non_terminal_sandbox_cleanup
|
||||
${result}= Run Process ${PYTHON} ${HELPER} verify_non_terminal_sandbox_cleanup cwd=${WORKSPACE} timeout=180s on_timeout=kill
|
||||
Log ${result.stdout}
|
||||
Log ${result.stderr}
|
||||
Should Be Equal As Integers ${result.rc} 0
|
||||
|
||||
Legacy Plan Fallback Works
|
||||
[Documentation] Verify _apply_output_dict handles non-Plan objects gracefully.
|
||||
${result}= Run Plan Apply Json Envelope Test verify_legacy_fallback
|
||||
${result}= Run Process ${PYTHON} ${HELPER} verify_legacy_fallback cwd=${WORKSPACE} timeout=180s on_timeout=kill
|
||||
Log ${result.stdout}
|
||||
Log ${result.stderr}
|
||||
Should Be Equal As Integers ${result.rc} 0
|
||||
|
||||
Cost Metadata Reflected In Lifecycle Total Cost
|
||||
[Documentation] Verify total_cost reflects plan cost_metadata when present.
|
||||
${result}= Run Plan Apply Json Envelope Test verify_cost_metadata
|
||||
${result}= Run Process ${PYTHON} ${HELPER} verify_cost_metadata cwd=${WORKSPACE} timeout=180s on_timeout=kill
|
||||
Log ${result.stdout}
|
||||
Log ${result.stderr}
|
||||
Should Be Equal As Integers ${result.rc} 0
|
||||
|
||||
Plan Status Does Not Use Apply Envelope
|
||||
[Documentation] Verify plan status --format json does NOT emit the apply envelope command field.
|
||||
${result}= Run Plan Apply Json Envelope Test verify_status_no_apply_envelope
|
||||
${result}= Run Process ${PYTHON} ${HELPER} verify_status_no_apply_envelope cwd=${WORKSPACE} timeout=180s on_timeout=kill
|
||||
Log ${result.stdout}
|
||||
Log ${result.stderr}
|
||||
Should Be Equal As Integers ${result.rc} 0
|
||||
|
||||
Plan Cancel Does Not Use Apply Envelope
|
||||
[Documentation] Verify plan cancel --format json does NOT emit the apply envelope command field.
|
||||
${result}= Run Plan Apply Json Envelope Test verify_cancel_no_apply_envelope
|
||||
${result}= Run Process ${PYTHON} ${HELPER} verify_cancel_no_apply_envelope cwd=${WORKSPACE} timeout=180s on_timeout=kill
|
||||
Log ${result.stdout}
|
||||
Log ${result.stderr}
|
||||
Should Be Equal As Integers ${result.rc} 0
|
||||
|
||||
Reference in New Issue
Block a user