perf(tests): optimize the 8 slowest BDD feature files #488

Closed
brent.edwards wants to merge 1 commits from perf/optimize-slowest-features into perf/shared-fixtures-lazy-imports
5 changed files with 181 additions and 273 deletions
+49 -9
View File
@@ -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
View File
@@ -1,3 +1,4 @@
@mock_only
Feature: Plan Commands Coverage
As a developer
I want to test all plan command paths
+33 -37
View File
@@ -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"
+18
View File
@@ -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."""
+80 -227
View File
@@ -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)
)