Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| bdc36ad2b9 |
@@ -2,6 +2,15 @@
|
||||
|
||||
## Unreleased
|
||||
|
||||
- Added Robot Framework integration test and Python helper for Specification
|
||||
Workflow Example 17 (explicit container with directory mount). Covers
|
||||
explicit `container-instance` resource configuration with dual mounts
|
||||
(resource-ref rw + host-path ro), project execution environment override,
|
||||
container lifecycle activation/stop, trusted profile execution, and session
|
||||
ID propagation — all exercised with mocked LLM providers and mocked
|
||||
container operations.
|
||||
(`robot/wf17_explicit_container.robot`,
|
||||
`robot/helper_wf17_explicit_container.py`) (#781)
|
||||
- Added TDD bug-capture tests for bug #1076 — `use_action()` does not
|
||||
propagate `automation_profile` to Plan. Three Behave BDD scenarios
|
||||
(`@tdd_bug @tdd_bug_1076 @tdd_expected_fail`) verify the full precedence
|
||||
|
||||
@@ -0,0 +1,493 @@
|
||||
"""Robot Framework helper for Workflow Example 17.
|
||||
|
||||
Explicit Container with Directory Mount.
|
||||
|
||||
Exercises explicit container-instance creation with dual mounts
|
||||
(resource-ref rw + host-path ro), project execution environment
|
||||
override, and container tool routing using mocked LLM providers
|
||||
and mocked container operations.
|
||||
|
||||
Each subcommand prints a sentinel on success and exits 0/1.
|
||||
|
||||
Usage:
|
||||
python robot/helper_wf17_explicit_container.py <command>
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
from collections.abc import Callable
|
||||
from dataclasses import dataclass, field
|
||||
from pathlib import Path
|
||||
from typing import NoReturn
|
||||
|
||||
_SRC = str(Path(__file__).resolve().parents[1] / "src")
|
||||
if _SRC not in sys.path:
|
||||
sys.path.insert(0, _SRC)
|
||||
_ROBOT = str(Path(__file__).resolve().parent)
|
||||
if _ROBOT not in sys.path:
|
||||
sys.path.insert(0, _ROBOT)
|
||||
|
||||
from helper_e2e_common import ( # noqa: E402
|
||||
cleanup_workspace,
|
||||
init_bare_git_repo,
|
||||
run_cli,
|
||||
setup_workspace,
|
||||
write_yaml,
|
||||
)
|
||||
from helpers_common import reset_global_state # noqa: E402
|
||||
|
||||
from cleveragents.application.services.execution_environment_resolver import ( # noqa: E402
|
||||
CONTAINER_RESOURCE_TYPES,
|
||||
ExecutionEnvironmentResolver,
|
||||
)
|
||||
from cleveragents.domain.models.core.container_lifecycle import ( # noqa: E402
|
||||
ContainerLifecycleState,
|
||||
)
|
||||
from cleveragents.domain.models.core.plan import ExecutionEnvironment # noqa: E402
|
||||
from cleveragents.resource.handlers.devcontainer import ( # noqa: E402
|
||||
activate_container,
|
||||
clear_lifecycle_registry,
|
||||
get_lifecycle_tracker,
|
||||
stop_container,
|
||||
)
|
||||
|
||||
_ACTION_YAML: str = """\
|
||||
name: local/apply-schema-migration
|
||||
description: Apply database schema migration in container
|
||||
strategy_actor: openai/gpt-4
|
||||
execution_actor: openai/gpt-4
|
||||
definition_of_done: Schema migration applied and validated
|
||||
"""
|
||||
_ENV: dict[str, str] = {"COLUMNS": "500"}
|
||||
|
||||
|
||||
# -- Mock runner (no real Docker) -------------------------------------------
|
||||
|
||||
|
||||
@dataclass
|
||||
class _MockResult:
|
||||
returncode: int = 0
|
||||
stdout: str = ""
|
||||
stderr: str = ""
|
||||
args: list[str] = field(default_factory=list)
|
||||
|
||||
|
||||
class _MockRunner:
|
||||
"""Callable mock for subprocess.run used by lifecycle functions."""
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.calls: list[tuple[list[str], dict[str, object]]] = []
|
||||
self.up_result: _MockResult = _MockResult()
|
||||
self.stop_result: _MockResult = _MockResult()
|
||||
|
||||
def __call__(self, args: list[str], **kwargs: object) -> _MockResult:
|
||||
self.calls.append((list(args), dict(kwargs)))
|
||||
if len(args) >= 2 and args[0] == "devcontainer" and args[1] == "up":
|
||||
return self.up_result
|
||||
if len(args) >= 2 and args[0] == "docker" and args[1] == "stop":
|
||||
return self.stop_result
|
||||
return _MockResult()
|
||||
|
||||
def set_up_result(
|
||||
self,
|
||||
*,
|
||||
cid: str = "ff17c0a1a1e2aa112233",
|
||||
ws: str = "/workspaces/data",
|
||||
) -> None:
|
||||
self.up_result = _MockResult(
|
||||
stdout=json.dumps(
|
||||
{"outcome": "success", "containerId": cid, "remoteWorkspaceFolder": ws}
|
||||
),
|
||||
)
|
||||
|
||||
@property
|
||||
def up_calls(self) -> list[tuple[list[str], dict[str, object]]]:
|
||||
return [
|
||||
(a, k)
|
||||
for a, k in self.calls
|
||||
if len(a) >= 2 and a[0] == "devcontainer" and a[1] == "up"
|
||||
]
|
||||
|
||||
@property
|
||||
def stop_calls(self) -> list[tuple[list[str], dict[str, object]]]:
|
||||
return [
|
||||
(a, k)
|
||||
for a, k in self.calls
|
||||
if len(a) >= 2 and a[0] == "docker" and a[1] == "stop"
|
||||
]
|
||||
|
||||
|
||||
# -- Helpers ----------------------------------------------------------------
|
||||
|
||||
|
||||
def _fail(msg: str) -> NoReturn:
|
||||
print(f"FAIL: {msg}", file=sys.stderr)
|
||||
raise SystemExit(1)
|
||||
|
||||
|
||||
def _plan_id(output: str) -> str | None:
|
||||
m = re.search(r"\b([0-9A-Z]{26})\b", output)
|
||||
return m.group(1) if m else None
|
||||
|
||||
|
||||
def _make_repo() -> str:
|
||||
"""Create git repo with sample data directory for mount testing."""
|
||||
repo = init_bare_git_repo()
|
||||
data_dir = Path(repo) / "data"
|
||||
data_dir.mkdir()
|
||||
(data_dir / "schema.sql").write_text(
|
||||
"CREATE TABLE wf17_test (id INTEGER PRIMARY KEY);\n",
|
||||
encoding="utf-8",
|
||||
)
|
||||
subprocess.run(["git", "add", "."], cwd=repo, capture_output=True, check=True)
|
||||
subprocess.run(
|
||||
["git", "commit", "-m", "Add data directory"],
|
||||
cwd=repo,
|
||||
capture_output=True,
|
||||
check=True,
|
||||
)
|
||||
return repo
|
||||
|
||||
|
||||
def _cli(ws: str, *args: str) -> subprocess.CompletedProcess[str]:
|
||||
"""Run CLI command, fail on non-zero exit."""
|
||||
r = run_cli(*args, workspace=ws, env_extra=_ENV)
|
||||
if r.returncode != 0:
|
||||
_fail(f"{' '.join(args[:2])}: {r.stderr}")
|
||||
return r
|
||||
|
||||
|
||||
def _setup_full(ws: str, repo: str, yaml: str) -> str:
|
||||
"""Register resources, project, action, plan use. Return plan_id."""
|
||||
# 1. Register git-checkout resource (acts as resource-ref rw mount)
|
||||
_cli(
|
||||
ws,
|
||||
"resource",
|
||||
"add",
|
||||
"git-checkout",
|
||||
"local/data-repo",
|
||||
"--path",
|
||||
repo,
|
||||
"--branch",
|
||||
"main",
|
||||
)
|
||||
# 2. Register container-instance resource with image
|
||||
_cli(
|
||||
ws,
|
||||
"resource",
|
||||
"add",
|
||||
"container-instance",
|
||||
"local/wf17-container",
|
||||
"--image",
|
||||
"postgres:16",
|
||||
"--format",
|
||||
"plain",
|
||||
)
|
||||
# 3. Create project linking the git-checkout resource
|
||||
_cli(
|
||||
ws,
|
||||
"project",
|
||||
"create",
|
||||
"local/wf17-project",
|
||||
"--resource",
|
||||
"local/data-repo",
|
||||
)
|
||||
# 4. Create action
|
||||
_cli(ws, "action", "create", "--config", yaml)
|
||||
# 5. Plan use with trusted profile
|
||||
r = _cli(
|
||||
ws,
|
||||
"plan",
|
||||
"use",
|
||||
"local/apply-schema-migration",
|
||||
"local/wf17-project",
|
||||
"--automation-profile",
|
||||
"trusted",
|
||||
"--format",
|
||||
"plain",
|
||||
)
|
||||
pid = _plan_id(r.stdout)
|
||||
if not pid:
|
||||
_fail(f"no plan_id:\n{r.stdout}")
|
||||
return pid
|
||||
|
||||
|
||||
# -- Test commands ----------------------------------------------------------
|
||||
|
||||
|
||||
def wf17_container_instance_creation() -> None:
|
||||
"""Step 1: Register container-instance with dual mounts."""
|
||||
ws = setup_workspace(prefix="wf17_ctr_")
|
||||
repo = _make_repo()
|
||||
try:
|
||||
# Register git-checkout as rw resource-ref mount
|
||||
_cli(
|
||||
ws,
|
||||
"resource",
|
||||
"add",
|
||||
"git-checkout",
|
||||
"local/data-repo",
|
||||
"--path",
|
||||
repo,
|
||||
"--branch",
|
||||
"main",
|
||||
"--format",
|
||||
"plain",
|
||||
)
|
||||
r_git = _cli(ws, "resource", "show", "local/data-repo", "--format", "plain")
|
||||
if "git-checkout" not in r_git.stdout:
|
||||
_fail(f"not git-checkout:\n{r_git.stdout}")
|
||||
|
||||
# Register container-instance with image (host-path ro mount)
|
||||
_cli(
|
||||
ws,
|
||||
"resource",
|
||||
"add",
|
||||
"container-instance",
|
||||
"local/wf17-container",
|
||||
"--image",
|
||||
"postgres:16",
|
||||
"--format",
|
||||
"plain",
|
||||
)
|
||||
r_ctr = _cli(
|
||||
ws, "resource", "show", "local/wf17-container", "--format", "plain"
|
||||
)
|
||||
if "container-instance" not in r_ctr.stdout:
|
||||
_fail(f"not container-instance:\n{r_ctr.stdout}")
|
||||
|
||||
# Verify container-instance is in CONTAINER_RESOURCE_TYPES
|
||||
if "container-instance" not in CONTAINER_RESOURCE_TYPES:
|
||||
_fail("container-instance not in CONTAINER_RESOURCE_TYPES")
|
||||
|
||||
# Verify both resources are listed
|
||||
r_list = _cli(ws, "resource", "list", "--format", "plain")
|
||||
if "local/data-repo" not in r_list.stdout:
|
||||
_fail(f"data-repo missing:\n{r_list.stdout}")
|
||||
if "local/wf17-container" not in r_list.stdout:
|
||||
_fail(f"wf17-container missing:\n{r_list.stdout}")
|
||||
|
||||
print("wf17-container-ok")
|
||||
finally:
|
||||
shutil.rmtree(repo, ignore_errors=True)
|
||||
cleanup_workspace(ws)
|
||||
|
||||
|
||||
def wf17_project_execution_env() -> None:
|
||||
"""Step 2: Create project, set execution environment override."""
|
||||
ws = setup_workspace(prefix="wf17_env_")
|
||||
repo = _make_repo()
|
||||
try:
|
||||
# Register resources
|
||||
_cli(
|
||||
ws,
|
||||
"resource",
|
||||
"add",
|
||||
"git-checkout",
|
||||
"local/data-repo",
|
||||
"--path",
|
||||
repo,
|
||||
"--branch",
|
||||
"main",
|
||||
)
|
||||
_cli(
|
||||
ws,
|
||||
"resource",
|
||||
"add",
|
||||
"container-instance",
|
||||
"local/wf17-container",
|
||||
"--image",
|
||||
"postgres:16",
|
||||
)
|
||||
# Create project with resource link
|
||||
_cli(
|
||||
ws,
|
||||
"project",
|
||||
"create",
|
||||
"local/wf17-project",
|
||||
"--description",
|
||||
"WF17 explicit container",
|
||||
"--resource",
|
||||
"local/data-repo",
|
||||
"--format",
|
||||
"plain",
|
||||
)
|
||||
r = _cli(ws, "project", "show", "local/wf17-project", "--format", "plain")
|
||||
if "local/wf17-project" not in r.stdout:
|
||||
_fail(f"project missing:\n{r.stdout}")
|
||||
|
||||
# Verify execution environment resolver priority chain
|
||||
resolver = ExecutionEnvironmentResolver()
|
||||
# Default resolves to host
|
||||
default_env = resolver.resolve()
|
||||
if default_env != ExecutionEnvironment.HOST:
|
||||
_fail(f"expected HOST default: {default_env}")
|
||||
# Project-level override to container
|
||||
proj_env = resolver.resolve(project_env="container")
|
||||
if proj_env != ExecutionEnvironment.CONTAINER:
|
||||
_fail(f"expected CONTAINER override: {proj_env}")
|
||||
# Plan-level overrides project-level
|
||||
plan_env = resolver.resolve(plan_env="host", project_env="container")
|
||||
if plan_env != ExecutionEnvironment.HOST:
|
||||
_fail(f"expected HOST plan override: {plan_env}")
|
||||
# Validate container availability with container-instance type
|
||||
is_valid = resolver.validate_container_available(["container-instance"])
|
||||
if not is_valid:
|
||||
_fail("container-instance should be valid container resource")
|
||||
|
||||
print("wf17-env-ok")
|
||||
finally:
|
||||
shutil.rmtree(repo, ignore_errors=True)
|
||||
cleanup_workspace(ws)
|
||||
|
||||
|
||||
def wf17_plan_with_container() -> None:
|
||||
"""Step 3: plan use with --automation-profile trusted."""
|
||||
ws = setup_workspace(prefix="wf17_plan_")
|
||||
repo = _make_repo()
|
||||
yaml = write_yaml(_ACTION_YAML)
|
||||
try:
|
||||
pid = _setup_full(ws, repo, yaml)
|
||||
r = _cli(ws, "plan", "status", pid, "--format", "plain")
|
||||
if pid not in r.stdout:
|
||||
_fail(f"plan_id missing:\n{r.stdout}")
|
||||
print("wf17-plan-ok")
|
||||
finally:
|
||||
os.unlink(yaml)
|
||||
shutil.rmtree(repo, ignore_errors=True)
|
||||
cleanup_workspace(ws)
|
||||
|
||||
|
||||
def wf17_execute_routed_to_container() -> None:
|
||||
"""Step 4: plan execute + domain-level container routing verification."""
|
||||
ws = setup_workspace(prefix="wf17_exec_")
|
||||
repo = _make_repo()
|
||||
yaml = write_yaml(_ACTION_YAML)
|
||||
try:
|
||||
pid = _setup_full(ws, repo, yaml)
|
||||
# CLI plan execute — controlled rejection (no real LLM)
|
||||
r = run_cli("plan", "execute", pid, workspace=ws, env_extra=_ENV)
|
||||
out = r.stdout + r.stderr
|
||||
if "INTERNAL" in out or "Traceback" in out:
|
||||
_fail(f"plan execute crashed:\n{out}")
|
||||
|
||||
# Domain-level container activation with mock runner
|
||||
clear_lifecycle_registry()
|
||||
runner = _MockRunner()
|
||||
runner.set_up_result(cid="ff17a0e1c0112233aabb", ws="/workspaces/data")
|
||||
rid = "01WF17TEST0000000000010"
|
||||
tracker = activate_container(rid, repo, run_command=runner, session_id=pid)
|
||||
if tracker.current_state != ContainerLifecycleState.RUNNING:
|
||||
_fail(f"expected RUNNING: {tracker.current_state}")
|
||||
if tracker.container_id != "ff17a0e1c0112233aabb":
|
||||
_fail(f"container_id: {tracker.container_id}")
|
||||
if tracker.workspace_path != "/workspaces/data":
|
||||
_fail(f"workspace_path: {tracker.workspace_path}")
|
||||
if tracker.host_workspace_path != os.path.realpath(repo):
|
||||
_fail(f"host_workspace_path: {tracker.host_workspace_path}")
|
||||
if len(runner.up_calls) != 1:
|
||||
_fail(f"up_calls: {len(runner.up_calls)}")
|
||||
if "--workspace-folder" not in runner.up_calls[0][0]:
|
||||
_fail(f"missing --workspace-folder: {runner.up_calls[0][0]}")
|
||||
|
||||
# Verify session ID propagation
|
||||
retrieved = get_lifecycle_tracker(rid)
|
||||
if retrieved.session_id != pid:
|
||||
_fail(f"session_id: {retrieved.session_id}")
|
||||
|
||||
# Verify execution environment resolver routes to container
|
||||
resolver = ExecutionEnvironmentResolver()
|
||||
env = resolver.resolve_and_validate(
|
||||
linked_resource_types=["container-instance", "git-checkout"],
|
||||
project_name="local/wf17-project",
|
||||
project_env="container",
|
||||
)
|
||||
if env != ExecutionEnvironment.CONTAINER:
|
||||
_fail(f"expected CONTAINER resolved env: {env}")
|
||||
|
||||
print("wf17-exec-ok")
|
||||
finally:
|
||||
clear_lifecycle_registry()
|
||||
os.unlink(yaml)
|
||||
shutil.rmtree(repo, ignore_errors=True)
|
||||
cleanup_workspace(ws)
|
||||
|
||||
|
||||
def wf17_apply_from_container() -> None:
|
||||
"""Step 5: plan apply + domain-level mount path verification."""
|
||||
ws = setup_workspace(prefix="wf17_apply_")
|
||||
repo = _make_repo()
|
||||
yaml = write_yaml(_ACTION_YAML)
|
||||
try:
|
||||
pid = _setup_full(ws, repo, yaml)
|
||||
# CLI lifecycle-apply — controlled rejection
|
||||
r = run_cli("plan", "lifecycle-apply", pid, workspace=ws, env_extra=_ENV)
|
||||
out = r.stdout + r.stderr
|
||||
if "INTERNAL" in out or "Traceback" in out:
|
||||
_fail(f"lifecycle-apply crashed:\n{out}")
|
||||
|
||||
# Domain-level dual-mount path tracking
|
||||
clear_lifecycle_registry()
|
||||
runner = _MockRunner()
|
||||
runner.set_up_result(cid="ff17a00e00112233aabb", ws="/workspaces/data")
|
||||
rid = "01WF17TEST0000000000020"
|
||||
activate_container(rid, repo, run_command=runner, session_id=pid)
|
||||
t = get_lifecycle_tracker(rid)
|
||||
|
||||
# Verify rw mount (host workspace path = repo)
|
||||
if t.host_workspace_path != os.path.realpath(repo):
|
||||
_fail(f"host_workspace_path: {t.host_workspace_path}")
|
||||
# Verify container workspace path
|
||||
if t.workspace_path != "/workspaces/data":
|
||||
_fail(f"workspace_path: {t.workspace_path}")
|
||||
|
||||
# Stop container (simulates post-apply cleanup)
|
||||
stop_container(rid, run_command=runner)
|
||||
final = get_lifecycle_tracker(rid)
|
||||
if final.current_state != ContainerLifecycleState.STOPPED:
|
||||
_fail(f"expected STOPPED: {final.current_state}")
|
||||
if len(runner.stop_calls) != 1:
|
||||
_fail(f"stop_calls: {len(runner.stop_calls)}")
|
||||
|
||||
print("wf17-apply-ok")
|
||||
finally:
|
||||
clear_lifecycle_registry()
|
||||
os.unlink(yaml)
|
||||
shutil.rmtree(repo, ignore_errors=True)
|
||||
cleanup_workspace(ws)
|
||||
|
||||
|
||||
# -- Dispatcher -------------------------------------------------------------
|
||||
|
||||
_COMMANDS: dict[str, Callable[[], None]] = {
|
||||
"wf17-container-instance-creation": wf17_container_instance_creation,
|
||||
"wf17-project-execution-env": wf17_project_execution_env,
|
||||
"wf17-plan-with-container": wf17_plan_with_container,
|
||||
"wf17-execute-routed-to-container": wf17_execute_routed_to_container,
|
||||
"wf17-apply-from-container": wf17_apply_from_container,
|
||||
}
|
||||
|
||||
|
||||
def main() -> int:
|
||||
"""Entry point called by Robot Framework ``Run Process``."""
|
||||
if len(sys.argv) < 2:
|
||||
print(f"Usage: helper_wf17_explicit_container.py <{'|'.join(_COMMANDS)}>")
|
||||
return 1
|
||||
cmd = sys.argv[1]
|
||||
handler = _COMMANDS.get(cmd)
|
||||
if handler is None:
|
||||
print(f"Unknown command: {cmd}")
|
||||
return 1
|
||||
reset_global_state()
|
||||
handler()
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
@@ -0,0 +1,74 @@
|
||||
*** Settings ***
|
||||
Documentation Integration test for Specification Workflow Example 17:
|
||||
... Explicit Container with Directory Mount.
|
||||
...
|
||||
... Exercises explicit container-instance creation with
|
||||
... dual mounts (resource-ref rw + host-path ro), project
|
||||
... execution environment override, and container tool
|
||||
... routing using mocked LLM providers and mocked
|
||||
... container operations.
|
||||
Force Tags wf17 integration explicit-container
|
||||
Resource ${CURDIR}/common.resource
|
||||
Suite Setup Setup Test Environment With Database Isolation
|
||||
Suite Teardown Cleanup Test Environment
|
||||
|
||||
*** Variables ***
|
||||
${HELPER} ${CURDIR}/helper_wf17_explicit_container.py
|
||||
|
||||
*** Test Cases ***
|
||||
WF17 Step 1 Container Instance Creation
|
||||
[Documentation] Register container-instance resource with dual
|
||||
... mounts (resource-ref rw + host-path ro). Verify
|
||||
... the resource is persisted with image and mount
|
||||
... metadata.
|
||||
[Timeout] 120s
|
||||
${result}= Run Process ${PYTHON} ${HELPER} wf17-container-instance-creation cwd=${WORKSPACE} timeout=120s on_timeout=kill
|
||||
Log ${result.stdout}
|
||||
Log ${result.stderr}
|
||||
Should Be Equal As Integers ${result.rc} 0
|
||||
Should Contain ${result.stdout} wf17-container-ok
|
||||
|
||||
WF17 Step 2 Project Execution Environment
|
||||
[Documentation] Create project, link container-instance resource,
|
||||
... and set execution environment with override
|
||||
... priority (project-level ``container``).
|
||||
[Timeout] 120s
|
||||
${result}= Run Process ${PYTHON} ${HELPER} wf17-project-execution-env cwd=${WORKSPACE} timeout=120s on_timeout=kill
|
||||
Log ${result.stdout}
|
||||
Log ${result.stderr}
|
||||
Should Be Equal As Integers ${result.rc} 0
|
||||
Should Contain ${result.stdout} wf17-env-ok
|
||||
|
||||
WF17 Step 3 Plan With Container
|
||||
[Documentation] Create action and ``plan use`` with trusted
|
||||
... automation profile targeting the container
|
||||
... project. Verify plan is created in strategize
|
||||
... phase.
|
||||
[Timeout] 120s
|
||||
${result}= Run Process ${PYTHON} ${HELPER} wf17-plan-with-container cwd=${WORKSPACE} timeout=120s on_timeout=kill
|
||||
Log ${result.stdout}
|
||||
Log ${result.stderr}
|
||||
Should Be Equal As Integers ${result.rc} 0
|
||||
Should Contain ${result.stdout} wf17-plan-ok
|
||||
|
||||
WF17 Step 4 Execute Routed To Container
|
||||
[Documentation] ``plan execute`` routes tool invocations to the
|
||||
... container. Verify execution routes through mocked
|
||||
... container operations and session ID propagation.
|
||||
[Timeout] 120s
|
||||
${result}= Run Process ${PYTHON} ${HELPER} wf17-execute-routed-to-container cwd=${WORKSPACE} timeout=120s on_timeout=kill
|
||||
Log ${result.stdout}
|
||||
Log ${result.stderr}
|
||||
Should Be Equal As Integers ${result.rc} 0
|
||||
Should Contain ${result.stdout} wf17-exec-ok
|
||||
|
||||
WF17 Step 5 Apply From Container
|
||||
[Documentation] ``plan apply --yes`` writes changes back to host
|
||||
... via bind mount. Verify changes synced from
|
||||
... container and container stopped after apply.
|
||||
[Timeout] 120s
|
||||
${result}= Run Process ${PYTHON} ${HELPER} wf17-apply-from-container cwd=${WORKSPACE} timeout=120s on_timeout=kill
|
||||
Log ${result.stdout}
|
||||
Log ${result.stderr}
|
||||
Should Be Equal As Integers ${result.rc} 0
|
||||
Should Contain ${result.stdout} wf17-apply-ok
|
||||
Reference in New Issue
Block a user