diff --git a/CHANGELOG.md b/CHANGELOG.md index 7345aefe6..965726b7c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ Changed `wf10_batch.robot` to be less likely to create files, and `plan_generation_graph.robot` to give more test answers. ## [Unreleased] +- **fix(a2a): regression tests for stale cleveragents.acp removal** (#5566): Added two Behave BDD scenarios verifying that `cleveragents.acp` is not importable (raises `ImportError`) and that `src/cleveragents/acp/` does not exist in the source tree. These guard against regression of the `__pycache__`-based import that allowed the removed ACP module to still be loaded from bytecode after the v3.6.0 rename to `a2a`. - **Virtual Resource Type Base Class** (#8610): Implemented `VirtualResource` base class with two example concrete implementations (`MetricResource`, `APIEndpointResource`) for abstract/computed resources that are derived rather than mapped to physical files. Virtual resources are computed on demand via a `compute_fn` callable. Includes Behave BDD scenarios in `features/resource_virtual_types.feature` exercising construction, computation, name validation, kwargs passthrough, exception handling, string representation, and subclassing. Resource names are validated against `^[a-zA-Z][a-zA-Z0-9_-]*$` (must start with a letter; alphanumeric, hyphens, and underscores otherwise). - **test(e2e): restore complete M2 acceptance test** (#11191): Restored the truncated M2 full actor compiler and LLM integration e2e acceptance test to its complete 10-step form. Added dynamic LLM provider selection via `Resolve LLM Actor` (falls back to Anthropic when OpenAI is unavailable or quota-exhausted), replacing hardcoded `gpt-4` / `openai/gpt-4` references in the actor config and action YAML. Added explicit return-code validation (`Should Be Equal As Integers ${r_actor.rc} 0`) for the actor registration step. - **docs(a2a): ACP to A2A migration guide** (#10230): Added migration guide documenting how to upgrade from the ACP module to the A2A module introduced in v3.6.0, including symbol renames, field renames, operation-name mappings, and YAML configuration updates. diff --git a/features/a2a_acp_module_removed.feature b/features/a2a_acp_module_removed.feature new file mode 100644 index 000000000..d560b3ec9 --- /dev/null +++ b/features/a2a_acp_module_removed.feature @@ -0,0 +1,13 @@ +Feature: ACP module is not importable + As a CleverAgents developer + I want to ensure the old ACP module is completely removed + So that the v3.6.0 deliverable #1 requirement is met: "No acp references in public API" + + Scenario: Importing cleveragents.acp raises ImportError + When I attempt to import the cleveragents.acp module + Then an ImportError should be raised + And the error message should indicate the module does not exist + + Scenario: The acp directory does not exist in the source tree + When I check the source tree for the acp directory + Then the src/cleveragents/acp directory should not exist diff --git a/features/steps/a2a_acp_module_removed_steps.py b/features/steps/a2a_acp_module_removed_steps.py new file mode 100644 index 000000000..8068561af --- /dev/null +++ b/features/steps/a2a_acp_module_removed_steps.py @@ -0,0 +1,72 @@ +"""Step definitions for a2a_acp_module_removed.feature. + +Tests that the old ACP module is completely removed and not importable, +ensuring v3.6.0 deliverable #1 compliance: "No acp references in public API". +""" + +from __future__ import annotations + +import importlib +import sys +from pathlib import Path +from typing import Any + +from behave import then, when + + +@when("I attempt to import the cleveragents.acp module") +def step_attempt_import_acp(context: Any) -> None: + """Attempt to import cleveragents.acp and capture any ImportError.""" + context.import_error = None + try: + # Remove from sys.modules if it exists to ensure fresh import + if "cleveragents.acp" in sys.modules: + del sys.modules["cleveragents.acp"] + + # Attempt to import + importlib.import_module("cleveragents.acp") + context.import_succeeded = True + except ImportError as e: + context.import_error = e + context.import_succeeded = False + + +@then("an ImportError should be raised") +def step_check_import_error(context: Any) -> None: + """Verify that an ImportError was raised.""" + assert context.import_error is not None, ( + "Expected ImportError to be raised when importing cleveragents.acp, " + "but import succeeded" + ) + assert not context.import_succeeded, "Expected import to fail, but it succeeded" + + +@then("the error message should indicate the module does not exist") +def step_check_error_message(context: Any) -> None: + """Verify that the error message indicates the module doesn't exist.""" + error_msg = str(context.import_error) + assert "cleveragents.acp" in error_msg or "No module named" in error_msg, ( + f"Expected error message to mention 'cleveragents.acp' or 'No module named', " + f"but got: {error_msg}" + ) + + +@when("I check the source tree for the acp directory") +def step_check_acp_directory(context: Any) -> None: + """Check if the acp directory exists in the source tree.""" + # Get the path to the cleveragents package + import cleveragents + + cleveragents_path = Path(cleveragents.__file__).parent + acp_path = cleveragents_path / "acp" + + context.acp_directory_exists = acp_path.exists() + context.acp_path = acp_path + + +@then("the src/cleveragents/acp directory should not exist") +def step_check_acp_not_exists(context: Any) -> None: + """Verify that the acp directory does not exist.""" + assert not context.acp_directory_exists, ( + f"Expected acp directory to not exist, but found it at: {context.acp_path}" + )