perf(tests): optimize the 8 slowest BDD feature files #488
+49
-9
@@ -62,9 +62,41 @@ def before_all(context):
|
||||
# MigrationRunner.init_or_upgrade so that fresh file-based SQLite
|
||||
# databases are created by copying the pre-migrated template (~1ms)
|
||||
# instead of running 25 Alembic migrations (~0.5-3s each).
|
||||
#
|
||||
# If running outside of nox (i.e. direct `behave` invocation), auto-
|
||||
# create the template DB so the fast-path is always active.
|
||||
_ensure_template_db()
|
||||
_install_template_db_patch()
|
||||
|
||||
|
||||
def _ensure_template_db() -> None:
|
||||
"""Auto-create the template DB when CLEVERAGENTS_TEMPLATE_DB is not set.
|
||||
|
||||
When running tests directly via ``behave`` (without nox), the env var
|
||||
is missing. This function creates the template on the fly using
|
||||
``scripts/create_template_db.py`` so the fast-path is always active.
|
||||
"""
|
||||
if os.environ.get("CLEVERAGENTS_TEMPLATE_DB"):
|
||||
return # Already set by nox or CI
|
||||
|
||||
template_path = Path(__file__).parent.parent / "build" / ".template-migrated.db"
|
||||
if template_path.is_file():
|
||||
# Template already exists from a prior run — reuse it.
|
||||
os.environ["CLEVERAGENTS_TEMPLATE_DB"] = str(template_path.resolve())
|
||||
return
|
||||
|
||||
try:
|
||||
# Import the template creation script
|
||||
scripts_dir = Path(__file__).parent.parent / "scripts"
|
||||
sys.path.insert(0, str(scripts_dir))
|
||||
from create_template_db import create_template
|
||||
|
||||
create_template(str(template_path))
|
||||
os.environ["CLEVERAGENTS_TEMPLATE_DB"] = str(template_path.resolve())
|
||||
except Exception:
|
||||
pass # Fall back to normal Alembic migrations
|
||||
|
||||
|
||||
def _install_template_db_patch() -> None:
|
||||
"""Monkey-patch MigrationRunner to copy a template DB for fresh SQLite files."""
|
||||
template_path = os.environ.get("CLEVERAGENTS_TEMPLATE_DB")
|
||||
@@ -80,8 +112,10 @@ def _install_template_db_patch() -> None:
|
||||
|
||||
_original_init_or_upgrade = MigrationRunner.init_or_upgrade
|
||||
|
||||
# Prefixes used by before_scenario when creating per-scenario temp DBs.
|
||||
_SCENARIO_DB_PREFIXES = ("cleveragents_", "cleveragents_test_")
|
||||
# Prefixes used by before_scenario and step files when creating temp DBs.
|
||||
# "cleveragents_" / "cleveragents_test_" — before_scenario databases
|
||||
# "test_" — databases created inside step files (services_coverage, etc.)
|
||||
_SCENARIO_DB_PREFIXES = ("cleveragents_", "cleveragents_test_", "test_")
|
||||
|
||||
def _fast_init_or_upgrade(self: Any, **kwargs: Any) -> None:
|
||||
"""Copy the template DB instead of running Alembic migrations.
|
||||
@@ -168,14 +202,20 @@ def before_scenario(context, scenario):
|
||||
# Give each scenario a unique database file so scenarios cannot share
|
||||
# persisted state AND parallel subprocesses never collide on the same
|
||||
# SQLite file. Store the paths for cleanup in after_scenario.
|
||||
#
|
||||
# Features tagged @mock_only use fully mocked services and never touch
|
||||
# the database, so skip the temp-file creation for them (~0.5ms each,
|
||||
# but the real savings come from not triggering MigrationRunner later).
|
||||
context._scenario_db_paths = []
|
||||
for env_var, prefix in (
|
||||
("CLEVERAGENTS_DATABASE_URL", "cleveragents_"),
|
||||
("CLEVERAGENTS_TEST_DATABASE_URL", "cleveragents_test_"),
|
||||
):
|
||||
db_path = tempfile.mktemp(suffix=".db", prefix=prefix)
|
||||
os.environ[env_var] = f"sqlite:///{db_path}"
|
||||
context._scenario_db_paths.append(db_path)
|
||||
_is_mock_only = "mock_only" in scenario.effective_tags
|
||||
if not _is_mock_only:
|
||||
for env_var, prefix in (
|
||||
("CLEVERAGENTS_DATABASE_URL", "cleveragents_"),
|
||||
("CLEVERAGENTS_TEST_DATABASE_URL", "cleveragents_test_"),
|
||||
):
|
||||
db_path = tempfile.mktemp(suffix=".db", prefix=prefix)
|
||||
os.environ[env_var] = f"sqlite:///{db_path}"
|
||||
context._scenario_db_paths.append(db_path)
|
||||
|
||||
# Re-apply mock AI provider after container reset
|
||||
try:
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
@mock_only
|
||||
Feature: Plan Commands Coverage
|
||||
As a developer
|
||||
I want to test all plan command paths
|
||||
|
||||
@@ -23,21 +23,21 @@ Feature: Plan Service
|
||||
When I build the plan
|
||||
Then changes should be generated
|
||||
And the changes should include file operations
|
||||
|
||||
|
||||
Scenario: Build plan uses actor selection
|
||||
Given I have a plan service with stub provider registry
|
||||
And I have created a plan with "Generate example code"
|
||||
When I build the plan with actor "anthropic/claude-dev"
|
||||
Then changes should be generated
|
||||
And the stub provider registry should record provider "anthropic" and model "claude-dev"
|
||||
|
||||
|
||||
Scenario: Build plan fails when no provider configured
|
||||
Given I have a plan service without providers configured
|
||||
And I have created a plan with "Generate example code"
|
||||
When I try to build the plan
|
||||
Then a PlanError should be raised with message "No AI provider configured"
|
||||
And the PlanError details should include provider diagnostics
|
||||
|
||||
|
||||
Scenario: Apply generated changes
|
||||
|
||||
Given I have a plan service
|
||||
@@ -81,154 +81,150 @@ Feature: Plan Service
|
||||
And the plan has a pending MOVE change to an absolute path
|
||||
When I apply the plan changes
|
||||
Then the absolute destination should exist and the source should be removed
|
||||
|
||||
|
||||
Scenario: Stream plan generation and persist usage
|
||||
Given I have a plan service with a streaming stub provider
|
||||
When I stream plan generation with prompt "Streamed instructions"
|
||||
Then the streaming events should include nodes "load_context, analyze_requirements, generate_plan, validate, __end__"
|
||||
And the streamed plan should persist token count 321
|
||||
|
||||
|
||||
Scenario: Stream plan generation fails when provider never completes
|
||||
Given I have a plan service with an incomplete streaming provider
|
||||
When I try to stream plan generation with prompt "Incomplete stream"
|
||||
Then a PlanError should be raised with message "Provider streaming ended before completion"
|
||||
|
||||
|
||||
Scenario: Stream plan generation coerces dict payloads
|
||||
Given I have a plan service with a dict streaming provider
|
||||
When I stream plan generation with prompt "Dict payload"
|
||||
Then the streaming events should include nodes "generate_plan, __end__"
|
||||
And the streamed plan should persist token count 0
|
||||
|
||||
|
||||
Scenario: Stream plan generation surfaces provider error strings
|
||||
Given I have a plan service with a string error streaming provider
|
||||
When I try to stream plan generation with prompt "String error"
|
||||
Then the streaming failure events should include an error with message "stub failure"
|
||||
And a PlanError should be raised with message "stub failure"
|
||||
|
||||
|
||||
Scenario: Stream plan generation rejects non-list change payloads
|
||||
Given I have a plan service with a non-list change streaming provider
|
||||
When I try to stream plan generation with prompt "Non list payload"
|
||||
Then a PlanError should be raised with message "Provider stream returned an invalid change payload"
|
||||
|
||||
|
||||
Scenario: Stream plan generation rejects invalid change entries
|
||||
Given I have a plan service with an invalid change entry streaming provider
|
||||
When I try to stream plan generation with prompt "Invalid change entry"
|
||||
Then a PlanError should be raised with message "Provider stream returned a non-change entry"
|
||||
|
||||
|
||||
Scenario: Mock provider resolution keeps nameless provider metadata
|
||||
Given I have a plan service
|
||||
Given I have a lightweight plan service for actor testing
|
||||
And mock provider mode is forced
|
||||
And the plan service uses a nameless AI provider
|
||||
And the plan service actor lookup returns actor "anthropic/claude-mock" with provider "anthropic" and model "claude-mock"
|
||||
When I resolve provider for actor "anthropic/claude-mock"
|
||||
Then the nameless provider resolution should return provider "anthropic" and model "claude-mock"
|
||||
|
||||
|
||||
Scenario: Actor resolution triggers lazy registry creation
|
||||
Given I have a plan service
|
||||
Given I have a lightweight plan service for actor testing
|
||||
And I stub the provider registry factory for lazy initialization
|
||||
And the plan service actor lookup returns actor "anthropic/claude-dev" with provider "anthropic" and model "claude-dev"
|
||||
When I resolve provider for actor "anthropic/claude-dev"
|
||||
Then the lazy registry should memoize provider "anthropic" and model "claude-dev"
|
||||
|
||||
|
||||
Scenario: LangSmith config omits missing metadata
|
||||
Given I have a temporary test directory for plan service
|
||||
And LangSmith integration is enabled for plan service
|
||||
When I prepare a LangSmith config without plan metadata for project "ephemeral-project"
|
||||
Then the LangSmith builder should receive only base metadata for project "ephemeral-project"
|
||||
And the prepared LangSmith config should include a generated thread id
|
||||
|
||||
|
||||
Scenario: Build fails when plan ID disappears mid-transaction
|
||||
Given I have a temporary test directory for plan service
|
||||
And I configure a stub plan service whose current plan loses its ID after the transaction
|
||||
When I try to build the plan with the stubbed service
|
||||
Then a PlanError should be raised with message "Plan does not have a valid ID"
|
||||
|
||||
|
||||
Scenario: Clearing memory without forgetting history keeps cached messages
|
||||
Given I have a plan service
|
||||
Given I have a lightweight plan service for actor testing
|
||||
And I stored a chat message in session "ephemeral-branch"
|
||||
When I clear the session "ephemeral-branch" memory without forgetting history
|
||||
Then the session "ephemeral-branch" memory should retain its stored messages
|
||||
|
||||
Scenario: Actor resolution fails when actor service is missing
|
||||
Given I have a plan service
|
||||
Given I have a lightweight plan service for actor testing
|
||||
When I try to resolve actor "ghost/actor"
|
||||
Then a PlanError should be raised with message "Actor support is not configured"
|
||||
|
||||
Scenario: Actor lookup validation errors surface as plan errors
|
||||
Given I have a plan service
|
||||
Given I have a lightweight plan service for actor testing
|
||||
And the plan service actor lookup raises ValidationError "invalid actor selection"
|
||||
When I try to resolve actor "invalid/actor"
|
||||
Then a PlanError should be raised with message "invalid actor selection"
|
||||
And the PlanError should include actor detail "invalid/actor"
|
||||
|
||||
Scenario: Actor fallback fails when mock provisioning returns nothing
|
||||
Given I have a plan service
|
||||
Given I have a lightweight plan service for actor testing
|
||||
And the plan service actor lookup returns no actor and mock provisioning fails
|
||||
When I try to resolve actor "openai/gpt-4o"
|
||||
Then a PlanError should be raised with message "No actor configured"
|
||||
|
||||
Scenario: Actor resolution returns explicit actors
|
||||
Given I have a plan service
|
||||
Given I have a lightweight plan service for actor testing
|
||||
And the plan service actor lookup returns actor "openai/gpt-4o" with provider "openai" and model "gpt-4o"
|
||||
When I try to resolve actor "openai/gpt-4o"
|
||||
Then the actor resolution should return actor "openai/gpt-4o" from source "explicit"
|
||||
|
||||
|
||||
Scenario: Mock actor provider resolution requires configured AI provider
|
||||
Given I have a plan service
|
||||
Given I have a lightweight plan service for actor testing
|
||||
And mock provider mode is forced
|
||||
And the plan service actor lookup returns actor "mock/provider" with provider "mock-provider" and model "mock-model"
|
||||
When I resolve provider for actor "mock/provider"
|
||||
Then a PlanError should be raised with message "No AI provider configured"
|
||||
|
||||
Scenario: Mock actor provider resolution uses injected provider defaults
|
||||
Given I have a plan service
|
||||
Given I have a lightweight plan service for actor testing
|
||||
And mock provider mode is forced
|
||||
And the plan service AI provider is "injected-provider" with model "injected-model"
|
||||
And the plan service actor lookup returns actor "mock/provider" with provider "mock-provider" and model "mock-model"
|
||||
When I resolve provider for actor "mock/provider"
|
||||
Then the provider resolution should return provider "mock-provider" and model "mock-model"
|
||||
|
||||
|
||||
Scenario: Mock actor provider appears after initial check
|
||||
Given I have a Unit of Work instance for plan testing
|
||||
And the plan service uses a delayed mock provider
|
||||
And the plan service actor lookup returns actor "mock/provider" with provider "mock-provider" and model "mock-model"
|
||||
When I resolve provider for actor "mock/provider"
|
||||
Then the provider resolution should return provider "mock-provider" and model "mock-model"
|
||||
|
||||
|
||||
Scenario: Actor provider registry factory failure surfaces PlanError
|
||||
Given I have a plan service
|
||||
Given I have a lightweight plan service for actor testing
|
||||
And the plan service actor lookup returns actor "broken/provider" with provider "broken-provider" and model "broken-model"
|
||||
And the provider registry factory raises ValueError "actor registry missing" for actor providers
|
||||
When I resolve provider for actor "broken/provider"
|
||||
Then a PlanError should be raised with message "actor registry missing"
|
||||
|
||||
|
||||
Scenario: Actor provider registry errors surface as PlanError
|
||||
Given I have a plan service
|
||||
Given I have a lightweight plan service for actor testing
|
||||
And the plan service actor lookup returns actor "anthropic/haiku" with provider "anthropic" and model "haiku"
|
||||
And the provider registry raises ValueError "actor registry unavailable" for actor providers
|
||||
When I resolve provider for actor "anthropic/haiku"
|
||||
Then a PlanError should be raised with message "actor registry unavailable"
|
||||
|
||||
|
||||
Scenario: Actor provider registry resolves provider and model
|
||||
Given I have a plan service
|
||||
Given I have a lightweight plan service for actor testing
|
||||
And the plan service actor lookup returns actor "openai/gpt-4o" with provider "openai" and model "gpt-4o"
|
||||
And the provider registry returns provider "openai" with model "gpt-4o"
|
||||
When I resolve provider for actor "openai/gpt-4o"
|
||||
Then the provider resolution should return provider "openai" and model "gpt-4o"
|
||||
|
||||
|
||||
Scenario: Actor provider resolution uses lazy registry fallback
|
||||
Given I have a plan service
|
||||
Given I have a lightweight plan service for actor testing
|
||||
And the plan service actor lookup returns actor "openai/gpt-4o" with provider "openai" and model "gpt-4o"
|
||||
And I stub the provider registry factory for lazy initialization
|
||||
When I resolve provider for actor "openai/gpt-4o"
|
||||
Then the lazy registry should record actor provider "openai" and model "gpt-4o"
|
||||
|
||||
|
||||
Scenario: Streaming sanitization reports unrecoverable Python syntax
|
||||
Given I have a plan service with an unrecoverable streaming provider
|
||||
When I try to stream plan generation with prompt "Fatal stream"
|
||||
Then a PlanError should be raised containing "Validation failed: Syntax error"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -89,6 +89,24 @@ def step_create_plan_service(context: Context) -> None:
|
||||
)
|
||||
|
||||
|
||||
@given("I have a lightweight plan service for actor testing")
|
||||
def step_create_lightweight_plan_service(context: Context) -> None:
|
||||
"""Create a lightweight PlanService using in-memory DB for actor resolution tests.
|
||||
|
||||
This avoids the overhead of file-based DB creation, temp directories, and
|
||||
project initialization — none of which are needed for testing actor/provider
|
||||
resolution logic.
|
||||
"""
|
||||
if not hasattr(context, "unit_of_work"):
|
||||
step_create_unit_of_work_plan(context)
|
||||
if not hasattr(context, "temp_dir"):
|
||||
context.temp_dir = Path(tempfile.mkdtemp(prefix="plan_actor_"))
|
||||
settings = Settings()
|
||||
context.plan_service = PlanService(
|
||||
settings=settings, unit_of_work=context.unit_of_work, ai_provider=None
|
||||
)
|
||||
|
||||
|
||||
@given("I have a plan service with stub provider registry")
|
||||
def step_plan_service_with_stub_registry(context: Context) -> None:
|
||||
"""Create a PlanService that uses a stub provider registry for overrides."""
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
import os
|
||||
import tempfile
|
||||
import uuid
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
|
||||
@@ -17,79 +18,81 @@ from cleveragents.application.services.project_service import ProjectService
|
||||
from cleveragents.config.settings import Settings
|
||||
from cleveragents.core.exceptions import NotFoundError
|
||||
from cleveragents.domain.models.core import Project, ProjectSettings
|
||||
from cleveragents.infrastructure.database.unit_of_work import UnitOfWork
|
||||
from features.mocks.mock_ai_provider import MockAIProvider
|
||||
|
||||
|
||||
def _setup_context_service(context, *, with_plan: bool = True):
|
||||
"""Common setup for context service tests.
|
||||
|
||||
Creates a temp dir, unique DB, ContextService, Project, and optionally
|
||||
a Plan — consolidating the duplicated boilerplate across multiple Given
|
||||
steps.
|
||||
"""
|
||||
context.temp_dir = tempfile.mkdtemp()
|
||||
os.chdir(context.temp_dir)
|
||||
Path(context.temp_dir, ".cleveragents").mkdir(exist_ok=True)
|
||||
settings = Settings()
|
||||
|
||||
db_file = Path(context.temp_dir) / f"test_{uuid.uuid4().hex}.db"
|
||||
unit_of_work = UnitOfWork(f"sqlite:///{db_file}")
|
||||
unit_of_work.init_database()
|
||||
|
||||
context.context_service = ContextService(settings, unit_of_work)
|
||||
|
||||
project_service = ProjectService(settings, unit_of_work)
|
||||
context.test_project = project_service.initialize_project(
|
||||
name="test-project", path=Path(context.temp_dir), force=True
|
||||
)
|
||||
|
||||
if with_plan:
|
||||
mock_provider = MockAIProvider()
|
||||
plan_service = PlanService(settings, unit_of_work, ai_provider=mock_provider)
|
||||
context.test_plan = plan_service.create_plan(
|
||||
project=context.test_project, prompt="Test plan for context"
|
||||
)
|
||||
|
||||
return settings, unit_of_work
|
||||
|
||||
|
||||
def _setup_plan_service(context):
|
||||
"""Common setup for plan service tests.
|
||||
|
||||
Creates a temp dir, unique DB, PlanService, and Project — consolidating
|
||||
the duplicated boilerplate across multiple Given steps.
|
||||
"""
|
||||
context.temp_dir = tempfile.mkdtemp()
|
||||
os.chdir(context.temp_dir)
|
||||
Path(context.temp_dir, ".cleveragents").mkdir(exist_ok=True)
|
||||
settings = Settings()
|
||||
|
||||
db_file = Path(context.temp_dir) / f"test_{uuid.uuid4().hex}.db"
|
||||
unit_of_work = UnitOfWork(f"sqlite:///{db_file}")
|
||||
unit_of_work.init_database()
|
||||
|
||||
mock_provider = MockAIProvider()
|
||||
context.plan_service = PlanService(
|
||||
settings, unit_of_work, ai_provider=mock_provider
|
||||
)
|
||||
|
||||
project_service = ProjectService(settings, unit_of_work)
|
||||
context.test_project = project_service.initialize_project(
|
||||
name="test-project", path=Path(context.temp_dir), force=True
|
||||
)
|
||||
|
||||
return settings, unit_of_work
|
||||
|
||||
|
||||
@given("a context service instance")
|
||||
def step_create_context_service(context):
|
||||
"""Create a context service instance."""
|
||||
import uuid
|
||||
|
||||
context.temp_dir = tempfile.mkdtemp()
|
||||
os.chdir(context.temp_dir)
|
||||
# Create .cleveragents directory
|
||||
Path(context.temp_dir, ".cleveragents").mkdir(exist_ok=True)
|
||||
settings = Settings()
|
||||
|
||||
# Create unit of work with unique database
|
||||
from cleveragents.infrastructure.database.unit_of_work import UnitOfWork
|
||||
|
||||
db_file = Path(context.temp_dir) / f"test_{uuid.uuid4().hex}.db"
|
||||
unit_of_work = UnitOfWork(f"sqlite:///{db_file}")
|
||||
unit_of_work.init_database()
|
||||
|
||||
context.context_service = ContextService(settings, unit_of_work)
|
||||
|
||||
# Also create project and plan for context to work with
|
||||
from cleveragents.application.services.plan_service import PlanService
|
||||
from cleveragents.application.services.project_service import ProjectService
|
||||
|
||||
project_service = ProjectService(settings, unit_of_work)
|
||||
context.test_project = project_service.initialize_project(
|
||||
name="test-project", path=Path(context.temp_dir), force=True
|
||||
)
|
||||
|
||||
mock_provider = MockAIProvider()
|
||||
plan_service = PlanService(settings, unit_of_work, ai_provider=mock_provider)
|
||||
context.test_plan = plan_service.create_plan(
|
||||
project=context.test_project, prompt="Test plan for context"
|
||||
)
|
||||
_setup_context_service(context)
|
||||
|
||||
|
||||
@given("a context service instance with files")
|
||||
def step_create_context_service_with_files(context):
|
||||
"""Create a context service with some files."""
|
||||
import uuid
|
||||
|
||||
context.temp_dir = tempfile.mkdtemp()
|
||||
os.chdir(context.temp_dir)
|
||||
# Create .cleveragents directory
|
||||
Path(context.temp_dir, ".cleveragents").mkdir(exist_ok=True)
|
||||
settings = Settings()
|
||||
|
||||
# Create unit of work with unique database
|
||||
from cleveragents.infrastructure.database.unit_of_work import UnitOfWork
|
||||
|
||||
db_file = Path(context.temp_dir) / f"test_{uuid.uuid4().hex}.db"
|
||||
unit_of_work = UnitOfWork(f"sqlite:///{db_file}")
|
||||
unit_of_work.init_database()
|
||||
|
||||
context.context_service = ContextService(settings, unit_of_work)
|
||||
|
||||
# Also create project and plan for context to work with
|
||||
from cleveragents.application.services.plan_service import PlanService
|
||||
from cleveragents.application.services.project_service import ProjectService
|
||||
|
||||
project_service = ProjectService(settings, unit_of_work)
|
||||
context.test_project = project_service.initialize_project(
|
||||
name="test-project", path=Path(context.temp_dir), force=True
|
||||
)
|
||||
|
||||
mock_provider = MockAIProvider()
|
||||
plan_service = PlanService(settings, unit_of_work, ai_provider=mock_provider)
|
||||
context.test_plan = plan_service.create_plan(
|
||||
project=context.test_project, prompt="Test plan for context"
|
||||
)
|
||||
_setup_context_service(context)
|
||||
|
||||
# Add some test files
|
||||
for i in range(3):
|
||||
@@ -287,67 +290,14 @@ def step_verify_context_persisted(context):
|
||||
@given("a plan service instance")
|
||||
def step_create_plan_service(context):
|
||||
"""Create a plan service instance."""
|
||||
import uuid
|
||||
|
||||
context.temp_dir = tempfile.mkdtemp()
|
||||
os.chdir(context.temp_dir)
|
||||
# Create .cleveragents directory
|
||||
Path(context.temp_dir, ".cleveragents").mkdir(exist_ok=True)
|
||||
settings = Settings()
|
||||
|
||||
# Create unit of work with unique database
|
||||
from cleveragents.infrastructure.database.unit_of_work import UnitOfWork
|
||||
|
||||
db_file = Path(context.temp_dir) / f"test_{uuid.uuid4().hex}.db"
|
||||
unit_of_work = UnitOfWork(f"sqlite:///{db_file}")
|
||||
unit_of_work.init_database()
|
||||
|
||||
mock_provider = MockAIProvider()
|
||||
context.plan_service = PlanService(
|
||||
settings, unit_of_work, ai_provider=mock_provider
|
||||
)
|
||||
|
||||
# Also create a project for the plan service to work with
|
||||
from cleveragents.application.services.project_service import ProjectService
|
||||
|
||||
project_service = ProjectService(settings, unit_of_work)
|
||||
context.test_project = project_service.initialize_project(
|
||||
name="test-project", path=Path(context.temp_dir), force=True
|
||||
)
|
||||
_setup_plan_service(context)
|
||||
|
||||
|
||||
@given("a plan service instance with a plan")
|
||||
def step_create_plan_service_with_plan(context):
|
||||
"""Create a plan service with a plan."""
|
||||
import uuid
|
||||
_setup_plan_service(context)
|
||||
|
||||
context.temp_dir = tempfile.mkdtemp()
|
||||
os.chdir(context.temp_dir)
|
||||
# Create .cleveragents directory
|
||||
Path(context.temp_dir, ".cleveragents").mkdir(exist_ok=True)
|
||||
settings = Settings()
|
||||
|
||||
# Create unit of work with unique database
|
||||
from cleveragents.infrastructure.database.unit_of_work import UnitOfWork
|
||||
|
||||
db_file = Path(context.temp_dir) / f"test_{uuid.uuid4().hex}.db"
|
||||
unit_of_work = UnitOfWork(f"sqlite:///{db_file}")
|
||||
unit_of_work.init_database()
|
||||
|
||||
mock_provider = MockAIProvider()
|
||||
context.plan_service = PlanService(
|
||||
settings, unit_of_work, ai_provider=mock_provider
|
||||
)
|
||||
|
||||
# Create a project and plan
|
||||
from cleveragents.application.services.project_service import ProjectService
|
||||
|
||||
project_service = ProjectService(settings, unit_of_work)
|
||||
context.test_project = project_service.initialize_project(
|
||||
name="test-project", path=Path(context.temp_dir), force=True
|
||||
)
|
||||
|
||||
# Create a plan using the service
|
||||
context.test_plan = context.plan_service.create_plan(
|
||||
project=context.test_project, prompt="Test plan", name="test-plan"
|
||||
)
|
||||
@@ -356,74 +306,19 @@ def step_create_plan_service_with_plan(context):
|
||||
@given("a plan service instance with a built plan")
|
||||
def step_create_plan_service_with_built_plan(context):
|
||||
"""Create a plan service with a built plan."""
|
||||
import uuid
|
||||
_setup_plan_service(context)
|
||||
|
||||
context.temp_dir = tempfile.mkdtemp()
|
||||
os.chdir(context.temp_dir)
|
||||
# Create .cleveragents directory
|
||||
Path(context.temp_dir, ".cleveragents").mkdir(exist_ok=True)
|
||||
settings = Settings()
|
||||
|
||||
# Create unit of work with unique database
|
||||
from cleveragents.infrastructure.database.unit_of_work import UnitOfWork
|
||||
|
||||
db_file = Path(context.temp_dir) / f"test_{uuid.uuid4().hex}.db"
|
||||
unit_of_work = UnitOfWork(f"sqlite:///{db_file}")
|
||||
unit_of_work.init_database()
|
||||
|
||||
mock_provider = MockAIProvider()
|
||||
context.plan_service = PlanService(
|
||||
settings, unit_of_work, ai_provider=mock_provider
|
||||
)
|
||||
|
||||
# Create a project and plan
|
||||
from cleveragents.application.services.project_service import ProjectService
|
||||
|
||||
project_service = ProjectService(settings, unit_of_work)
|
||||
context.test_project = project_service.initialize_project(
|
||||
name="test-project", path=Path(context.temp_dir), force=True
|
||||
)
|
||||
|
||||
# Create a plan and build it
|
||||
context.test_plan = context.plan_service.create_plan(
|
||||
project=context.test_project, prompt="Built plan", name="built-plan"
|
||||
)
|
||||
# Build the plan to generate changes
|
||||
context.changes = context.plan_service.build_plan(project=context.test_project)
|
||||
|
||||
|
||||
@given("a plan service instance with multiple plans")
|
||||
def step_create_plan_service_with_multiple_plans(context):
|
||||
"""Create a plan service with multiple plans."""
|
||||
import uuid
|
||||
_setup_plan_service(context)
|
||||
|
||||
context.temp_dir = tempfile.mkdtemp()
|
||||
os.chdir(context.temp_dir)
|
||||
# Create .cleveragents directory
|
||||
Path(context.temp_dir, ".cleveragents").mkdir(exist_ok=True)
|
||||
settings = Settings()
|
||||
|
||||
# Create unit of work with unique database
|
||||
from cleveragents.infrastructure.database.unit_of_work import UnitOfWork
|
||||
|
||||
db_file = Path(context.temp_dir) / f"test_{uuid.uuid4().hex}.db"
|
||||
unit_of_work = UnitOfWork(f"sqlite:///{db_file}")
|
||||
unit_of_work.init_database()
|
||||
|
||||
mock_provider = MockAIProvider()
|
||||
context.plan_service = PlanService(
|
||||
settings, unit_of_work, ai_provider=mock_provider
|
||||
)
|
||||
|
||||
# Create a project
|
||||
from cleveragents.application.services.project_service import ProjectService
|
||||
|
||||
project_service = ProjectService(settings, unit_of_work)
|
||||
context.test_project = project_service.initialize_project(
|
||||
name="test-project", path=Path(context.temp_dir), force=True
|
||||
)
|
||||
|
||||
# Create multiple plans
|
||||
context.plans = []
|
||||
for i in range(3):
|
||||
plan = context.plan_service.create_plan(
|
||||
@@ -435,41 +330,12 @@ def step_create_plan_service_with_multiple_plans(context):
|
||||
@given("a plan service instance with an applied plan")
|
||||
def step_create_plan_service_with_applied_plan(context):
|
||||
"""Create a plan service with an applied plan."""
|
||||
import uuid
|
||||
_setup_plan_service(context)
|
||||
|
||||
context.temp_dir = tempfile.mkdtemp()
|
||||
os.chdir(context.temp_dir)
|
||||
# Create .cleveragents directory
|
||||
Path(context.temp_dir, ".cleveragents").mkdir(exist_ok=True)
|
||||
settings = Settings()
|
||||
|
||||
# Create unit of work with unique database
|
||||
from cleveragents.infrastructure.database.unit_of_work import UnitOfWork
|
||||
|
||||
db_file = Path(context.temp_dir) / f"test_{uuid.uuid4().hex}.db"
|
||||
unit_of_work = UnitOfWork(f"sqlite:///{db_file}")
|
||||
unit_of_work.init_database()
|
||||
|
||||
mock_provider = MockAIProvider()
|
||||
context.plan_service = PlanService(
|
||||
settings, unit_of_work, ai_provider=mock_provider
|
||||
)
|
||||
|
||||
# Create a project and plan
|
||||
from cleveragents.application.services.project_service import ProjectService
|
||||
|
||||
project_service = ProjectService(settings, unit_of_work)
|
||||
context.test_project = project_service.initialize_project(
|
||||
name="test-project", path=Path(context.temp_dir), force=True
|
||||
)
|
||||
|
||||
# Create a plan, build it, and apply it
|
||||
context.test_plan = context.plan_service.create_plan(
|
||||
project=context.test_project, prompt="Applied plan", name="applied-plan"
|
||||
)
|
||||
# Build the plan
|
||||
context.changes = context.plan_service.build_plan(project=context.test_project)
|
||||
# Apply the changes
|
||||
context.applied_count = context.plan_service.apply_changes(
|
||||
project=context.test_project
|
||||
)
|
||||
@@ -603,44 +469,31 @@ def step_verify_changes_reverted(context):
|
||||
|
||||
|
||||
# Project Service steps
|
||||
@given("a project service instance")
|
||||
def step_create_project_service(context):
|
||||
"""Create a project service instance."""
|
||||
import uuid
|
||||
|
||||
def _setup_project_service(context):
|
||||
"""Common setup for project service tests."""
|
||||
context.temp_dir = tempfile.mkdtemp()
|
||||
os.chdir(context.temp_dir)
|
||||
settings = Settings()
|
||||
|
||||
# Create unit of work with unique database
|
||||
from cleveragents.infrastructure.database.unit_of_work import UnitOfWork
|
||||
|
||||
db_file = Path(context.temp_dir) / f"test_{uuid.uuid4().hex}.db"
|
||||
unit_of_work = UnitOfWork(f"sqlite:///{db_file}")
|
||||
unit_of_work.init_database()
|
||||
|
||||
context.project_service = ProjectService(settings, unit_of_work)
|
||||
return settings, unit_of_work
|
||||
|
||||
|
||||
@given("a project service instance")
|
||||
def step_create_project_service(context):
|
||||
"""Create a project service instance."""
|
||||
_setup_project_service(context)
|
||||
|
||||
|
||||
@given("a project service instance with a project")
|
||||
def step_create_project_service_with_project(context):
|
||||
"""Create a project service with an existing project."""
|
||||
import uuid
|
||||
_setup_project_service(context)
|
||||
|
||||
context.temp_dir = tempfile.mkdtemp()
|
||||
os.chdir(context.temp_dir)
|
||||
settings = Settings()
|
||||
|
||||
# Create unit of work with unique database
|
||||
from cleveragents.infrastructure.database.unit_of_work import UnitOfWork
|
||||
|
||||
db_file = Path(context.temp_dir) / f"test_{uuid.uuid4().hex}.db"
|
||||
unit_of_work = UnitOfWork(f"sqlite:///{db_file}")
|
||||
unit_of_work.init_database()
|
||||
|
||||
context.project_service = ProjectService(settings, unit_of_work)
|
||||
|
||||
# Initialize a project using the service
|
||||
context.project = context.project_service.initialize_project(
|
||||
name="test_project", path=Path(context.temp_dir)
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user