Files
cleveragents-core/robot/helper_m5_e2e_verification.py
HAL9000 80bc9c552d
CI / benchmark-publish (pull_request) Has been skipped
CI / push-validation (pull_request) Successful in 33s
CI / helm (pull_request) Successful in 45s
CI / build (pull_request) Successful in 1m4s
CI / lint (pull_request) Successful in 1m13s
CI / typecheck (pull_request) Successful in 1m31s
CI / quality (pull_request) Successful in 1m37s
CI / security (pull_request) Successful in 1m49s
CI / integration_tests (pull_request) Successful in 3m34s
CI / e2e_tests (pull_request) Successful in 5m6s
CI / unit_tests (pull_request) Successful in 6m14s
CI / docker (pull_request) Successful in 1m36s
CI / coverage (pull_request) Successful in 12m27s
CI / status-check (push) Blocked by required conditions
CI / coverage (push) Blocked by required conditions
CI / docker (push) Blocked by required conditions
CI / unit_tests (push) Has started running
CI / status-check (pull_request) Successful in 4s
CI / helm (push) Successful in 31s
CI / build (push) Successful in 53s
CI / lint (push) Successful in 1m3s
CI / quality (push) Successful in 1m13s
CI / typecheck (push) Successful in 1m46s
CI / security (push) Successful in 1m46s
CI / push-validation (push) Successful in 20s
CI / benchmark-publish (push) Failing after 43s
CI / e2e_tests (push) Successful in 4m9s
CI / integration_tests (push) Successful in 6m57s
test: restore and enhance e2e test coverage
Fix malformed imports in helper_m1_e2e_verification.py and
helper_m4_e2e_cli.py where 'from helpers_common import reset_global_state'
was incorrectly inserted inside a parenthesized import block, causing
Python syntax errors and breaking the lint and unit_tests CI gates.

Also fix import ordering in helper_m2_e2e_verification.py,
helper_m5_e2e_context.py, helper_m5_e2e_support.py, and
helper_m5_e2e_verification.py to satisfy ruff I001 import-sort rules
by placing helpers_common imports in the correct group alongside other
local robot/ helper imports.

ISSUES CLOSED: #8459
2026-05-01 00:59:02 +00:00

270 lines
8.9 KiB
Python

"""Robot Framework helper for M5 E2E verification tests.
Exercises the complete M5 success criteria sequence:
1. Large project creation with 10,000+ simulated files
2. Resource registration and linking to a project
3. Indexing verification (resource linked, project shows correctly)
4. Context tier management (hot/warm/cold) via ContextConfig
5. ACMS v1 context policy set/show with persistence round-trip
6. Phase view inheritance (default -> strategize -> execute -> apply)
7. Scoped context output per ACMS phase
8. Policy clear and inheritance fallback
Each subcommand prints a sentinel string on success and exits 0.
On failure it prints a diagnostic to stderr and exits 1.
Usage:
python robot/helper_m5_e2e_verification.py <command>
"""
from __future__ import annotations
import sys
import tempfile
import time
from collections.abc import Callable
from pathlib import Path
# Ensure src is importable when run from workspace root
_SRC = str(Path(__file__).resolve().parents[1] / "src")
if _SRC not in sys.path:
sys.path.insert(0, _SRC)
from helper_m5_e2e_context import ( # noqa: E402
acms_phase_inheritance,
acms_scoped_context,
context_policy_clear,
context_policy_set_show,
context_tier_config,
context_view_validation,
llm_execute_acms_context,
)
from helper_m5_e2e_support import ( # noqa: E402
_create_large_python_repo,
_create_project,
_fail,
_setup_db,
)
from helpers_common import reset_global_state # noqa: E402
from cleveragents.application.services.repo_indexing_service import ( # noqa: E402
RepoIndexingService,
)
from cleveragents.domain.models.core.repo_index import IndexStatus # noqa: E402
# -------------------------------------------------------------------
# Subcommand: project-create-large
# -------------------------------------------------------------------
def project_create_large() -> None:
"""Create a project and simulate a 10,000+ file repository.
Verifies project creation, resource registration, linking,
and that the project show reflects the linked resource.
"""
reset_global_state()
proj_repo, link_repo, svc, _sf = _setup_db()
proj = _create_project(
proj_repo,
"local/large-project",
description="Large project with 10,000+ file repo",
)
if proj.namespaced_name != "local/large-project":
_fail(f"project name mismatch: {proj.namespaced_name}")
with tempfile.TemporaryDirectory() as tmp:
repo_path = Path(tmp) / "large-repo"
repo_path.mkdir()
file_count = _create_large_python_repo(repo_path)
if file_count < 10_000:
_fail(f"expected >= 10,000 files, created {file_count}")
res = svc.register_resource(
type_name="git-checkout",
name="local/large-repo",
location=str(repo_path),
description="Large repository (10K+ files)",
properties={"path": str(repo_path), "branch": "main"},
)
if not res.resource_id:
_fail("resource_id is empty")
link_repo.create_link(
project_name="local/large-project",
resource_id=res.resource_id,
)
links = link_repo.list_links("local/large-project")
if len(links) != 1:
_fail(f"expected 1 link, got {len(links)}")
fetched = proj_repo.get("local/large-project")
if fetched.description != "Large project with 10,000+ file repo":
_fail(f"description mismatch: {fetched.description}")
print("m5-project-create-large-ok")
# -------------------------------------------------------------------
# Subcommand: resource-register-link
# -------------------------------------------------------------------
def resource_register_link() -> None:
"""Register a git-checkout resource and link it to a project."""
reset_global_state()
proj_repo, link_repo, svc, _sf = _setup_db()
proj = _create_project(proj_repo, "local/link-test")
res1 = svc.register_resource(
type_name="git-checkout",
name="local/repo-alpha",
location="/tmp/alpha",
description="Alpha repo",
properties={"path": "/tmp/alpha", "branch": "main"},
)
res2 = svc.register_resource(
type_name="git-checkout",
name="local/repo-beta",
location="/tmp/beta",
description="Beta repo",
properties={"path": "/tmp/beta", "branch": "develop"},
)
link_repo.create_link(
project_name=proj.namespaced_name,
resource_id=res1.resource_id,
)
link_repo.create_link(
project_name=proj.namespaced_name,
resource_id=res2.resource_id,
)
links = link_repo.list_links(proj.namespaced_name)
if len(links) != 2:
_fail(f"expected 2 links, got {len(links)}")
shown = svc.show_resource("local/repo-alpha")
if shown.name != "local/repo-alpha":
_fail(f"resource name mismatch: {shown.name}")
if shown.resource_type_name != "git-checkout":
_fail(f"type mismatch: {shown.resource_type_name}")
print("m5-resource-register-link-ok")
# -------------------------------------------------------------------
# Subcommand: indexing-complete
# -------------------------------------------------------------------
def indexing_complete() -> None:
"""Verify indexing completes: resource is linked, project shows OK."""
reset_global_state()
proj_repo, link_repo, svc, sf = _setup_db()
proj = _create_project(proj_repo, "local/idx-project")
with tempfile.TemporaryDirectory(prefix="m5_idx_repo_") as tmp:
repo_root = Path(tmp) / "idx-repo"
repo_root.mkdir(parents=True, exist_ok=True)
file_count = _create_large_python_repo(repo_root)
if file_count < 10_000:
_fail(f"expected >= 10,000 files, created {file_count}")
res = svc.register_resource(
type_name="git-checkout",
name="local/idx-repo",
location=str(repo_root),
description="Index test",
properties={"path": str(repo_root), "branch": "main"},
)
link_repo.create_link(
project_name=proj.namespaced_name,
resource_id=res.resource_id,
)
links = link_repo.list_links(proj.namespaced_name)
if len(links) != 1:
_fail(f"expected 1 link, got {len(links)}")
index_service = RepoIndexingService(session_factory=sf)
timeout_seconds = 120.0
started = time.monotonic()
idx = index_service.index_resource(
res.resource_id,
repo_root,
timeout_seconds=timeout_seconds,
)
elapsed = time.monotonic() - started
if elapsed > timeout_seconds:
_fail(
"indexing exceeded timeout bound: "
f"{elapsed:.2f}s > {timeout_seconds:.2f}s"
)
if idx.metadata.file_count < 10_000:
_fail(f"expected >= 10,000 indexed files, got {idx.metadata.file_count}")
if idx.metadata.status != IndexStatus.READY:
_fail(f"expected READY status, got {idx.metadata.status}")
fetched_res = svc.show_resource("local/idx-repo")
if fetched_res.resource_id != res.resource_id:
_fail(f"resource_id mismatch after fetch: {fetched_res.resource_id}")
if fetched_res.location != str(repo_root):
_fail(f"location mismatch: {fetched_res.location}")
status = index_service.get_index_status(res.resource_id)
if status is None:
_fail("index status missing after indexing")
if status.file_count != idx.metadata.file_count:
_fail(
"index status file_count mismatch: "
f"{status.file_count} != {idx.metadata.file_count}"
)
print("m5-indexing-complete-ok")
# -------------------------------------------------------------------
# Dispatcher
# -------------------------------------------------------------------
_COMMANDS: dict[str, Callable[[], None]] = {
"project-create-large": project_create_large,
"resource-register-link": resource_register_link,
"indexing-complete": indexing_complete,
"context-tier-config": context_tier_config,
"context-policy-set-show": context_policy_set_show,
"acms-phase-inheritance": acms_phase_inheritance,
"acms-scoped-context": acms_scoped_context,
"context-policy-clear": context_policy_clear,
"context-view-validation": context_view_validation,
"llm-execute-acms-context": llm_execute_acms_context,
}
def main() -> int:
"""Entry point called by Robot Framework ``Run Process``."""
if len(sys.argv) < 2:
print(
f"Usage: helper_m5_e2e_verification.py <{'|'.join(_COMMANDS)}>",
)
return 1
command = sys.argv[1]
handler = _COMMANDS.get(command)
if handler is None:
print(f"Unknown command: {command}")
return 1
handler()
return 0
if __name__ == "__main__":
sys.exit(main())