e2b127b7e5
CI / lint (pull_request) Successful in 37s
CI / typecheck (pull_request) Successful in 1m18s
CI / security (pull_request) Successful in 56s
CI / quality (pull_request) Successful in 48s
CI / build (pull_request) Successful in 30s
CI / helm (pull_request) Successful in 41s
CI / push-validation (pull_request) Successful in 28s
CI / integration_tests (pull_request) Successful in 4m32s
CI / e2e_tests (pull_request) Successful in 4m42s
CI / coverage (pull_request) Successful in 13m24s
CI / unit_tests (pull_request) Successful in 3m13s
CI / docker (pull_request) Successful in 1m36s
CI / status-check (pull_request) Successful in 1s
CI / benchmark-regression (push) Failing after 0s
CI / benchmark-publish (push) Failing after 0s
CI / push-validation (push) Successful in 12s
CI / build (push) Successful in 15s
CI / helm (push) Successful in 16s
CI / lint (push) Successful in 43s
CI / typecheck (push) Successful in 51s
CI / security (push) Successful in 51s
CI / e2e_tests (push) Successful in 2m14s
CI / quality (push) Successful in 3m44s
CI / integration_tests (push) Successful in 7m0s
CI / unit_tests (push) Successful in 8m33s
CI / coverage (push) Successful in 6m21s
CI / docker (push) Successful in 1m31s
CI / status-check (push) Successful in 2s
The existing actor-selection logic in several E2E suite setups checked only
whether OPENAI_API_KEY was present (non-empty). A valid key that has hit its
quota limit passes that check but fails at runtime with HTTP 429, causing the
test to fail even though Anthropic credits are available.
Changes:
- Add robot/e2e/check_openai_key.py: stdlib-only (urllib.request) script that
sends a minimal chat-completion request ('Hi', max_tokens=1, gpt-4o-mini) to
the OpenAI API. Exits 0 on HTTP 200; exits 1 for quota (429), auth (401),
network errors, or any other failure.
- Add 'Resolve LLM Actor' keyword to robot/e2e/common_e2e.resource: runs the
probe script via ${PYTHON} and returns the openai_model argument (default
openai/gpt-4o) on success, or the anthropic_model argument (default
anthropic/claude-sonnet-4-20250514) on failure. Skips the probe entirely when
OPENAI_API_KEY is not set.
- Update m6_acceptance.robot, wf04_multi_project.robot, wf05_db_migration.robot,
wf07_cicd.robot, and wf16_devcontainer.robot to use 'Resolve LLM Actor'
instead of the inline has_openai boolean check.
No production source code (src/) is modified. The decision to fall back to
Anthropic is made once per suite setup, before any test runs.
Closes #10198
146 lines
6.0 KiB
Plaintext
146 lines
6.0 KiB
Plaintext
*** Settings ***
|
|
Documentation E2E test for Workflow Example 5: Database Schema Migration with Safety Nets.
|
|
...
|
|
... Advanced scenario using the **review** automation profile.
|
|
... Registers a custom resource type (postgres-db), creates custom
|
|
... skills with spec-aligned database tools (query_db, execute_migration,
|
|
... backfill_column), exercises phased child plan execution via
|
|
... ``plan tree``, attempts checkpoint-based rollback via
|
|
... ``plan rollback``, and verifies migration changes after apply.
|
|
...
|
|
... Zero mocking — real CLI, real LLM API keys.
|
|
Resource common_e2e.resource
|
|
Suite Setup WF05 Suite Setup
|
|
Suite Teardown E2E Suite Teardown
|
|
Force Tags E2E
|
|
|
|
*** Variables ***
|
|
${ACTION_NAME} local/wf05-db-migration
|
|
${SKILL_NAME} local/wf05-db-tools
|
|
${RESOURCE_TYPE_NAME} local/wf05-postgres-db
|
|
|
|
*** Keywords ***
|
|
WF05 Suite Setup
|
|
[Documentation] E2E Suite Setup plus dynamic actor selection.
|
|
E2E Suite Setup
|
|
# Generate unique suffix for resource/project names to avoid UNIQUE
|
|
# constraint collisions on repeated E2E runs against the same database.
|
|
${suffix}= Evaluate __import__('uuid').uuid4().hex[:12]
|
|
Set Suite Variable ${RUN_SUFFIX} ${suffix}
|
|
# Probe the OpenAI API to confirm the key is usable before selecting actor.
|
|
# Falls back to Anthropic when the key is absent or quota-exhausted.
|
|
${actor}= Resolve LLM Actor
|
|
Set Suite Variable ${WF05_ACTOR} ${actor}
|
|
|
|
Create DB App Repo
|
|
[Documentation] Create temp git repo with a Python app simulating
|
|
... a database schema and application code.
|
|
${repo}= Create Temp Git Repo wf05-db-app-${RUN_SUFFIX}
|
|
Create Directory ${repo}${/}src
|
|
Create Directory ${repo}${/}migrations
|
|
Create Directory ${repo}${/}tests
|
|
${schema_content}= Catenate SEPARATOR=\n
|
|
... """Database schema — users table (missing last_login_at)."""
|
|
... ${EMPTY}
|
|
... USERS_SCHEMA = {
|
|
... ${SPACE}${SPACE}${SPACE}${SPACE}"table": "users",
|
|
... ${SPACE}${SPACE}${SPACE}${SPACE}"columns": [
|
|
... ${SPACE}${SPACE}${SPACE}${SPACE}${SPACE}${SPACE}${SPACE}${SPACE}{"name": "id", "type": "INTEGER", "primary_key": True},
|
|
... ${SPACE}${SPACE}${SPACE}${SPACE}${SPACE}${SPACE}${SPACE}${SPACE}{"name": "email", "type": "VARCHAR(255)"},
|
|
... ${SPACE}${SPACE}${SPACE}${SPACE}${SPACE}${SPACE}${SPACE}${SPACE}{"name": "created_at", "type": "TIMESTAMP"},
|
|
... ${SPACE}${SPACE}${SPACE}${SPACE}],
|
|
... }
|
|
Create File ${repo}${/}src${/}schema.py ${schema_content}
|
|
${app_content}= Catenate SEPARATOR=\n
|
|
... """Application code — user service."""
|
|
... from src.schema import USERS_SCHEMA
|
|
... ${EMPTY}
|
|
... ${EMPTY}
|
|
... def get_user(user_id):
|
|
... ${SPACE}${SPACE}${SPACE}${SPACE}"""Fetch a user by ID."""
|
|
... ${SPACE}${SPACE}${SPACE}${SPACE}return {"id": user_id, "email": "user@example.com"}
|
|
... ${EMPTY}
|
|
... ${EMPTY}
|
|
... def get_user_activity(user_id):
|
|
... ${SPACE}${SPACE}${SPACE}${SPACE}"""Get user activity — needs last_login_at but column is missing."""
|
|
... ${SPACE}${SPACE}${SPACE}${SPACE}user = get_user(user_id)
|
|
... ${SPACE}${SPACE}${SPACE}${SPACE}# BUG: no last_login_at field available
|
|
... ${SPACE}${SPACE}${SPACE}${SPACE}return {"user": user, "last_login": None}
|
|
Create File ${repo}${/}src${/}app.py ${app_content}
|
|
${test_content}= Catenate SEPARATOR=\n
|
|
... """Tests for user service."""
|
|
... from src.app import get_user, get_user_activity
|
|
... ${EMPTY}
|
|
... ${EMPTY}
|
|
... def test_get_user():
|
|
... ${SPACE}${SPACE}${SPACE}${SPACE}user = get_user(1)
|
|
... ${SPACE}${SPACE}${SPACE}${SPACE}assert user["id"] == 1
|
|
... ${EMPTY}
|
|
... ${EMPTY}
|
|
... def test_get_user_activity():
|
|
... ${SPACE}${SPACE}${SPACE}${SPACE}result = get_user_activity(1)
|
|
... ${SPACE}${SPACE}${SPACE}${SPACE}assert result["last_login"] is None
|
|
Create File ${repo}${/}tests${/}test_app.py ${test_content}
|
|
Create File ${repo}${/}src${/}__init__.py \n
|
|
Create File ${repo}${/}tests${/}__init__.py \n
|
|
Create File ${repo}${/}migrations${/}__init__.py \n
|
|
Create File ${repo}${/}requirements.txt pytest>=7.0\n
|
|
${git_add}= Run Process git add . cwd=${repo} timeout=60s on_timeout=kill
|
|
Should Be Equal As Integers ${git_add.rc} 0 git add failed: ${git_add.stderr}
|
|
${git_commit}= Run Process git commit -m Initial DB app with missing last_login_at cwd=${repo} timeout=60s on_timeout=kill
|
|
Should Be Equal As Integers ${git_commit.rc} 0 git commit failed: ${git_commit.stderr}
|
|
RETURN ${repo}
|
|
|
|
WF05 Test Teardown
|
|
[Documentation] Log diagnostic context on failure for debugging.
|
|
${plan_id}= Get Variable Value ${WF05_PLAN_ID} ${EMPTY}
|
|
IF '${plan_id}' != ''
|
|
${status} ${result}= Run Keyword And Ignore Error
|
|
... Run CleverAgents Command plan status ${plan_id} --format json expected_rc=None timeout=30s
|
|
IF '${status}' == 'PASS'
|
|
Log Teardown plan status: ${result.stdout} WARN
|
|
END
|
|
${tree_status} ${tree_result}= Run Keyword And Ignore Error
|
|
... Run CleverAgents Command plan tree ${plan_id} --format json expected_rc=None timeout=30s
|
|
IF '${tree_status}' == 'PASS'
|
|
Log Teardown plan tree: ${tree_result.stdout} WARN
|
|
END
|
|
END
|
|
|
|
*** Test Cases ***
|
|
WF05 Database Schema Migration With Safety Nets Review Profile
|
|
[Documentation] Full review-profile workflow: register custom resource type,
|
|
... register git-checkout resource, create custom skill with
|
|
... spec-aligned DB tools (query_db, execute_migration,
|
|
... backfill_column), create migration action with review
|
|
[Tags] tdd_issue tdd_issue_4189
|
|
... automation profile, exercise phased child plan execution,
|
|
... attempt checkpoint-based rollback, verify migration changes.
|
|
[Timeout] 30 minutes
|
|
[Teardown] WF05 Test Teardown
|
|
Skip If No LLM Keys
|
|
# Initialise test variable for teardown access.
|
|
Set Test Variable ${WF05_PLAN_ID} ${EMPTY}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|