92e2585358
CI / lint (pull_request) Successful in 39s
CI / helm (pull_request) Successful in 32s
CI / build (pull_request) Successful in 32s
CI / push-validation (pull_request) Successful in 31s
CI / quality (pull_request) Successful in 1m0s
CI / security (pull_request) Successful in 1m2s
CI / typecheck (pull_request) Successful in 1m40s
CI / unit_tests (pull_request) Successful in 6m25s
CI / docker (pull_request) Successful in 1m27s
CI / coverage (pull_request) Successful in 10m51s
CI / integration_tests (pull_request) Successful in 22m36s
CI / status-check (pull_request) Successful in 3s
Add the missing workflow validation example and keep the #1039 TDD regression active by removing the expected-fail tag and updating scenario narrative.\n\nTo satisfy the required full quality gates, stabilize flaky integration behavior encountered during this issue run: use a shared SQLAlchemy session in resource DAG scripts, isolate RxPY validation temp paths per test run, extend transient subprocess timeouts/retry behavior, and clear stale pabot worker artifacts before integration runs so repeated nox executions are reliable.\n\nISSUES CLOSED: #1039
792 lines
36 KiB
Plaintext
792 lines
36 KiB
Plaintext
*** Settings ***
|
|
Documentation Integration tests for database layer with repositories and Unit of Work
|
|
Library OperatingSystem
|
|
Library String
|
|
Library Collections
|
|
Library Process
|
|
Library indentation_library.py
|
|
Resource ${CURDIR}/common.resource
|
|
|
|
*** Variables ***
|
|
${PYTHON} python
|
|
${TEST_PROJECT_NAME} test-db-project
|
|
${TEST_PLAN_NAME} test-plan
|
|
${TEST_FILE} test_file.py
|
|
|
|
*** Test Cases ***
|
|
Database Can Be Initialized
|
|
[Documentation] Verify database initialization works
|
|
Create Temporary Project Directory
|
|
Initialize Database
|
|
Database Should Exist
|
|
Cleanup Test Environment
|
|
|
|
Project Repository CRUD Operations
|
|
[Documentation] Test Create, Read, Update, Delete operations for projects
|
|
Create Temporary Project Directory
|
|
Initialize Database
|
|
${project_id}= Create Project In Database ${TEST_PROJECT_NAME}
|
|
Should Be True ${project_id} > 0
|
|
${project}= Get Project By ID ${project_id}
|
|
Should Be Equal ${project['name']} ${TEST_PROJECT_NAME}
|
|
Update Project Name ${project_id} updated-project
|
|
${updated}= Get Project By ID ${project_id}
|
|
Should Be Equal ${updated['name']} updated-project
|
|
Cleanup Test Environment
|
|
|
|
Plan Repository Operations
|
|
[Documentation] Test plan repository operations
|
|
Create Temporary Project Directory
|
|
Initialize Database
|
|
${project_id}= Create Project In Database ${TEST_PROJECT_NAME}
|
|
${plan_id}= Create Plan For Project ${project_id} plan-1
|
|
Should Be True ${plan_id} > 0
|
|
${plan2_id}= Create Plan For Project ${project_id} plan-2
|
|
Set Current Plan ${project_id} ${plan2_id}
|
|
${current}= Get Current Plan For Project ${project_id}
|
|
Should Be Equal ${current['name']} plan-2
|
|
${all_plans}= Get All Plans For Project ${project_id}
|
|
Length Should Be ${all_plans} 2
|
|
Cleanup Test Environment
|
|
|
|
Context Repository Operations
|
|
[Documentation] Test context file management
|
|
Create Temporary Project Directory
|
|
Initialize Database
|
|
${project_id}= Create Project In Database ${TEST_PROJECT_NAME}
|
|
${plan_id}= Create Plan For Project ${project_id} ${TEST_PLAN_NAME}
|
|
${context_id}= Add File To Context ${plan_id} /tmp/test.py 100
|
|
Should Be True ${context_id} > 0
|
|
Add File To Context ${plan_id} /tmp/main.py 200
|
|
${contexts}= Get Context For Plan ${plan_id}
|
|
Length Should Be ${contexts} 2
|
|
Remove Context Item ${context_id}
|
|
${remaining}= Get Context For Plan ${plan_id}
|
|
Length Should Be ${remaining} 1
|
|
Clear Context For Plan ${plan_id}
|
|
${empty}= Get Context For Plan ${plan_id}
|
|
Length Should Be ${empty} 0
|
|
Cleanup Test Environment
|
|
|
|
Change Repository Operations
|
|
[Documentation] Test change tracking
|
|
Create Temporary Project Directory
|
|
Initialize Database
|
|
${project_id}= Create Project In Database ${TEST_PROJECT_NAME}
|
|
${plan_id}= Create Plan For Project ${project_id} ${TEST_PLAN_NAME}
|
|
${change_id}= Add Change To Plan ${plan_id} new_file.py create
|
|
Should Be True ${change_id} > 0
|
|
Add Change To Plan ${plan_id} existing.py modify
|
|
${changes}= Get Changes For Plan ${plan_id}
|
|
Length Should Be ${changes} 2
|
|
Mark Change Applied ${change_id}
|
|
${updated_changes}= Get Changes For Plan ${plan_id}
|
|
${applied_count}= Count Applied Changes ${updated_changes}
|
|
Should Be Equal As Integers ${applied_count} 1
|
|
Cleanup Test Environment
|
|
|
|
Unit Of Work Transaction Commit
|
|
[Documentation] Test that UoW commits all changes together
|
|
Create Temporary Project Directory
|
|
Initialize Database
|
|
Start Transaction
|
|
${project_id}= Create Project In Transaction transaction-project
|
|
${plan_id}= Create Plan In Transaction ${project_id} transaction-plan
|
|
Commit Transaction
|
|
# Verify both were saved
|
|
${project}= Get Project By Name transaction-project
|
|
Should Not Be Equal ${project} ${None}
|
|
${plans}= Get All Plans For Project ${project_id}
|
|
Length Should Be ${plans} 1
|
|
Cleanup Test Environment
|
|
|
|
Unit Of Work Transaction Rollback
|
|
[Documentation] Test that UoW rolls back on error
|
|
Create Temporary Project Directory
|
|
Initialize Database
|
|
Test Transaction Rollback
|
|
# Verify nothing was saved
|
|
${project}= Get Project By Name rollback-project
|
|
Should Be Equal ${project} ${None}
|
|
Cleanup Test Environment
|
|
|
|
Service Layer Uses Repositories
|
|
[Documentation] Test that services properly use repositories
|
|
Create Temporary Project Directory
|
|
Initialize Project With Service service-project
|
|
${project}= Get Current Project From Service
|
|
Should Not Be Equal ${project} ${None}
|
|
Create Plan With Service Test plan
|
|
${plan}= Get Current Plan From Service
|
|
Should Not Be Equal ${plan} ${None}
|
|
Create Test File ${TEST_FILE} test content
|
|
Add Context With Service ${TEST_FILE}
|
|
${context_count}= Get Context Count From Service
|
|
Should Be True ${context_count} > 0
|
|
Cleanup Test Environment
|
|
|
|
End To End Database Workflow
|
|
[Documentation] Test complete workflow using database
|
|
Create Temporary Project Directory
|
|
|
|
# Run the complete workflow in one script
|
|
${result}= Run Python Script
|
|
... import sys
|
|
... import os
|
|
... from cleveragents.application.services.project_service import ProjectService
|
|
... from cleveragents.application.services.plan_service import PlanService
|
|
... from cleveragents.application.services.context_service import ContextService
|
|
... from cleveragents.infrastructure.database.unit_of_work import UnitOfWork
|
|
... from cleveragents.config.settings import Settings
|
|
... from features.mocks.mock_ai_provider import MockAIProvider
|
|
... from pathlib import Path
|
|
... os.environ["CLEVERAGENTS_TESTING_USE_MOCK_AI"] = "true"
|
|
... settings = Settings()
|
|
... uow = UnitOfWork('sqlite:///${TEMP_DIR}/test.db')
|
|
... mock_ai = MockAIProvider()
|
|
... project_service = ProjectService(settings, uow)
|
|
... plan_service = PlanService(settings, uow, mock_ai)
|
|
... plan_service.actor_service.ensure_default_mock_actor(force=True)
|
|
... context_service = ContextService(settings, uow)
|
|
... # Initialize project
|
|
... project = project_service.initialize_project('e2e-project', Path('${TEMP_DIR}'))
|
|
... # Create plan
|
|
... plan = plan_service.create_plan(project, 'Create a REST API')
|
|
... # Add context file
|
|
... test_file = Path('${TEMP_DIR}/${TEST_FILE}')
|
|
... test_file.write_text('# Sample Python file' + chr(10) + 'print("Hello World")')
|
|
... context_service.add_to_context(project, test_file)
|
|
... # Build plan
|
|
... changes = plan_service.build_plan(project)
|
|
... # Apply changes
|
|
... applied_count = plan_service.apply_changes(project)
|
|
... print(applied_count)
|
|
${applied_count}= Convert To Integer ${result}
|
|
Should Be True ${applied_count} > 0
|
|
|
|
Cleanup Test Environment
|
|
|
|
*** Keywords ***
|
|
Create Temporary Project Directory
|
|
[Documentation] Create a temporary directory for testing
|
|
${temp_dir}= Evaluate tempfile.mkdtemp() modules=tempfile
|
|
Set Suite Variable ${TEMP_DIR} ${temp_dir}
|
|
Set Environment Variable CLEVERAGENTS_HOME ${temp_dir}
|
|
|
|
Initialize Database
|
|
[Documentation] Initialize the database
|
|
${result}= Run Python Script
|
|
... from cleveragents.infrastructure.database.unit_of_work import UnitOfWork
|
|
... uow = UnitOfWork('sqlite:///${TEMP_DIR}/test.db')
|
|
... uow.init_database()
|
|
... print('Database initialized')
|
|
Should Contain ${result} Database initialized
|
|
|
|
Database Should Exist
|
|
[Documentation] Verify database file exists
|
|
File Should Exist ${TEMP_DIR}/test.db
|
|
|
|
Create Project In Database
|
|
[Documentation] Create a project using repository
|
|
[Arguments] ${name}
|
|
${result}= Run Python Script
|
|
... from cleveragents.infrastructure.database.unit_of_work import UnitOfWork
|
|
... from cleveragents.domain.models.core import Project, ProjectSettings
|
|
... from pathlib import Path
|
|
... from datetime import datetime
|
|
... uow = UnitOfWork('sqlite:///${TEMP_DIR}/test.db')
|
|
... with uow.transaction() as ctx:
|
|
... project = Project(name='${name}', path=Path('${TEMP_DIR}'), settings=ProjectSettings(), created_at=datetime.now(), updated_at=datetime.now())
|
|
... created = ctx.projects.create(project)
|
|
... print(created.id)
|
|
${project_id}= Convert To Integer ${result}
|
|
RETURN ${project_id}
|
|
|
|
Get Project By ID
|
|
[Documentation] Get project by ID
|
|
[Arguments] ${project_id}
|
|
${result}= Run Python Script
|
|
... from cleveragents.infrastructure.database.unit_of_work import UnitOfWork
|
|
... import json
|
|
... uow = UnitOfWork('sqlite:///${TEMP_DIR}/test.db')
|
|
... with uow.transaction() as ctx:
|
|
... project = ctx.projects.get_by_id(${project_id})
|
|
... print(json.dumps({'id': project.id, 'name': project.name}))
|
|
${project}= Evaluate json.loads('''${result}''') json
|
|
RETURN ${project}
|
|
|
|
Get Project By Name
|
|
[Documentation] Get project by name
|
|
[Arguments] ${name}
|
|
${result}= Run Python Script
|
|
... from cleveragents.infrastructure.database.unit_of_work import UnitOfWork
|
|
... import json
|
|
... uow = UnitOfWork('sqlite:///${TEMP_DIR}/test.db')
|
|
... with uow.transaction() as ctx:
|
|
... project = ctx.projects.get_by_name('${name}')
|
|
... if project is None:
|
|
... print('null')
|
|
... else:
|
|
... print(json.dumps({'id': project.id, 'name': project.name}))
|
|
${project}= Run Keyword If '${result}' == 'null' Set Variable ${None}
|
|
... ELSE Evaluate json.loads('''${result}''') json
|
|
RETURN ${project}
|
|
|
|
Update Project Name
|
|
[Documentation] Update project name
|
|
[Arguments] ${project_id} ${new_name}
|
|
${result}= Run Python Script
|
|
... from cleveragents.infrastructure.database.unit_of_work import UnitOfWork
|
|
... uow = UnitOfWork('sqlite:///${TEMP_DIR}/test.db')
|
|
... with uow.transaction() as ctx:
|
|
... project = ctx.projects.get_by_id(${project_id})
|
|
... project.name = '${new_name}'
|
|
... ctx.projects.update(project)
|
|
... print('OK')
|
|
|
|
Create Plan For Project
|
|
[Documentation] Create a plan for a project
|
|
[Arguments] ${project_id} ${plan_name}
|
|
${result}= Run Python Script
|
|
... from cleveragents.infrastructure.database.unit_of_work import UnitOfWork
|
|
... from cleveragents.domain.models.core import Plan, PlanStatus
|
|
... from datetime import datetime
|
|
... uow = UnitOfWork('sqlite:///${TEMP_DIR}/test.db')
|
|
... with uow.transaction() as ctx:
|
|
... plan = Plan(project_id=${project_id}, name='${plan_name}', prompt='Test', status=PlanStatus.PENDING, current=False, created_at=datetime.now(), updated_at=datetime.now())
|
|
... created = ctx.plans.create(plan)
|
|
... print(created.id)
|
|
${plan_id}= Convert To Integer ${result}
|
|
RETURN ${plan_id}
|
|
|
|
Set Current Plan
|
|
[Documentation] Set a plan as current
|
|
[Arguments] ${project_id} ${plan_id}
|
|
${result}= Run Python Script
|
|
... from cleveragents.infrastructure.database.unit_of_work import UnitOfWork
|
|
... uow = UnitOfWork('sqlite:///${TEMP_DIR}/test.db')
|
|
... with uow.transaction() as ctx:
|
|
... ctx.plans.set_current(${project_id}, ${plan_id})
|
|
... print('OK')
|
|
|
|
Get Current Plan For Project
|
|
[Documentation] Get current plan for project
|
|
[Arguments] ${project_id}
|
|
${result}= Run Python Script
|
|
... from cleveragents.infrastructure.database.unit_of_work import UnitOfWork
|
|
... import json
|
|
... uow = UnitOfWork('sqlite:///${TEMP_DIR}/test.db')
|
|
... with uow.transaction() as ctx:
|
|
... plan = ctx.plans.get_current_for_project(${project_id})
|
|
... print(json.dumps({'id': plan.id, 'name': plan.name}) if plan else '{}')
|
|
${plan}= Evaluate json.loads('''${result}''') json
|
|
RETURN ${plan}
|
|
|
|
Get All Plans For Project
|
|
[Documentation] Get all plans for a project
|
|
[Arguments] ${project_id}
|
|
${result}= Run Python Script
|
|
... from cleveragents.infrastructure.database.unit_of_work import UnitOfWork
|
|
... import json
|
|
... uow = UnitOfWork('sqlite:///${TEMP_DIR}/test.db')
|
|
... with uow.transaction() as ctx:
|
|
... plans = ctx.plans.get_all_for_project(${project_id})
|
|
... print(json.dumps([{'id': p.id, 'name': p.name} for p in plans]))
|
|
${plans}= Evaluate json.loads('''${result}''') json
|
|
RETURN ${plans}
|
|
|
|
Add File To Context
|
|
[Documentation] Add a file to context
|
|
[Arguments] ${plan_id} ${file_path} ${size}
|
|
${result}= Run Python Script
|
|
... from cleveragents.infrastructure.database.unit_of_work import UnitOfWork
|
|
... from cleveragents.domain.models.core import Context, ContextType
|
|
... from datetime import datetime
|
|
... uow = UnitOfWork('sqlite:///${TEMP_DIR}/test.db')
|
|
... with uow.transaction() as ctx:
|
|
... context = Context(plan_id=${plan_id}, type=ContextType.FILE, path='${file_path}', content='Test content', file_hash='abc123', size=${size}, added_at=datetime.now())
|
|
... created = ctx.contexts.add(context)
|
|
... print(created.id)
|
|
${context_id}= Convert To Integer ${result}
|
|
RETURN ${context_id}
|
|
|
|
Get Context For Plan
|
|
[Documentation] Get context for a plan
|
|
[Arguments] ${plan_id}
|
|
${result}= Run Python Script
|
|
... from cleveragents.infrastructure.database.unit_of_work import UnitOfWork
|
|
... import json
|
|
... uow = UnitOfWork('sqlite:///${TEMP_DIR}/test.db')
|
|
... with uow.transaction() as ctx:
|
|
... contexts = ctx.contexts.get_for_plan(${plan_id})
|
|
... print(json.dumps([{'id': c.id, 'path': c.path} for c in contexts]))
|
|
${contexts}= Evaluate json.loads('''${result}''') json
|
|
RETURN ${contexts}
|
|
|
|
Remove Context Item
|
|
[Documentation] Remove a context item
|
|
[Arguments] ${context_id}
|
|
${result}= Run Python Script
|
|
... from cleveragents.infrastructure.database.unit_of_work import UnitOfWork
|
|
... uow = UnitOfWork('sqlite:///${TEMP_DIR}/test.db')
|
|
... with uow.transaction() as ctx:
|
|
... ctx.contexts.remove(${context_id})
|
|
... print('OK')
|
|
|
|
Clear Context For Plan
|
|
[Documentation] Clear all context for a plan
|
|
[Arguments] ${plan_id}
|
|
${result}= Run Python Script
|
|
... from cleveragents.infrastructure.database.unit_of_work import UnitOfWork
|
|
... uow = UnitOfWork('sqlite:///${TEMP_DIR}/test.db')
|
|
... with uow.transaction() as ctx:
|
|
... ctx.contexts.clear_for_plan(${plan_id})
|
|
... print('OK')
|
|
|
|
Add Change To Plan
|
|
[Documentation] Add a change to a plan
|
|
[Arguments] ${plan_id} ${file_path} ${operation}
|
|
${result}= Run Python Script
|
|
... from cleveragents.infrastructure.database.unit_of_work import UnitOfWork
|
|
... from cleveragents.domain.models.core import Change, OperationType
|
|
... uow = UnitOfWork('sqlite:///${TEMP_DIR}/test.db')
|
|
... with uow.transaction() as ctx:
|
|
... op = OperationType.CREATE if '${operation}' == 'create' else OperationType.MODIFY
|
|
... change = Change(plan_id=${plan_id}, file_path='${file_path}', operation=op, new_content='Test content', applied=False)
|
|
... created = ctx.changes.add(change)
|
|
... print(created.id)
|
|
${change_id}= Convert To Integer ${result}
|
|
RETURN ${change_id}
|
|
|
|
Get Changes For Plan
|
|
[Documentation] Get changes for a plan
|
|
[Arguments] ${plan_id}
|
|
${result}= Run Python Script
|
|
... from cleveragents.infrastructure.database.unit_of_work import UnitOfWork
|
|
... import json
|
|
... uow = UnitOfWork('sqlite:///${TEMP_DIR}/test.db')
|
|
... with uow.transaction() as ctx:
|
|
... changes = ctx.changes.get_for_plan(${plan_id})
|
|
... print(json.dumps([{'id': c.id, 'applied': c.applied} for c in changes]))
|
|
${changes}= Evaluate json.loads('''${result}''') json
|
|
RETURN ${changes}
|
|
|
|
Mark Change Applied
|
|
[Documentation] Mark a change as applied
|
|
[Arguments] ${change_id}
|
|
${result}= Run Python Script
|
|
... from cleveragents.infrastructure.database.unit_of_work import UnitOfWork
|
|
... uow = UnitOfWork('sqlite:///${TEMP_DIR}/test.db')
|
|
... with uow.transaction() as ctx:
|
|
... ctx.changes.mark_applied(${change_id})
|
|
... print('OK')
|
|
|
|
Count Applied Changes
|
|
[Documentation] Count applied changes in a list
|
|
[Arguments] ${changes}
|
|
${count}= Set Variable 0
|
|
FOR ${change} IN @{changes}
|
|
${applied}= Get From Dictionary ${change} applied
|
|
${applied_str}= Convert To String ${applied}
|
|
IF '${applied_str}' == 'True'
|
|
${count}= Evaluate ${count} + 1
|
|
END
|
|
END
|
|
RETURN ${count}
|
|
|
|
Start Transaction
|
|
[Documentation] Start a UoW transaction (simulation)
|
|
Set Test Variable ${TRANSACTION_ACTIVE} ${True}
|
|
|
|
Create Project In Transaction
|
|
[Documentation] Create project in transaction
|
|
[Arguments] ${name}
|
|
${error_flag_exists}= Evaluate __import__('pathlib').Path('${TEMP_DIR}/error_flag').exists()
|
|
${result}= Run Python Script
|
|
... from cleveragents.infrastructure.database.unit_of_work import UnitOfWork
|
|
... from cleveragents.domain.models.core import Project, ProjectSettings
|
|
... from pathlib import Path
|
|
... from datetime import datetime
|
|
... error_flag = Path('${TEMP_DIR}/error_flag').exists()
|
|
... uow = UnitOfWork('sqlite:///${TEMP_DIR}/test.db')
|
|
... if error_flag:
|
|
... print('0')
|
|
... else:
|
|
... with uow.transaction() as ctx:
|
|
... project = Project(name='${name}', path=Path('${TEMP_DIR}'), settings=ProjectSettings(), created_at=datetime.now(), updated_at=datetime.now())
|
|
... created = ctx.projects.create(project)
|
|
... print(created.id)
|
|
${project_id}= Convert To Integer ${result}
|
|
RETURN ${project_id}
|
|
|
|
Create Plan In Transaction
|
|
[Documentation] Create plan in transaction
|
|
[Arguments] ${project_id} ${name}
|
|
${result}= Run Python Script
|
|
... from cleveragents.infrastructure.database.unit_of_work import UnitOfWork
|
|
... from cleveragents.domain.models.core import Plan, PlanStatus
|
|
... from datetime import datetime
|
|
... uow = UnitOfWork('sqlite:///${TEMP_DIR}/test.db')
|
|
... with uow.transaction() as ctx:
|
|
... plan = Plan(project_id=${project_id}, name='${name}', prompt='.', status=PlanStatus.PENDING, current=True, created_at=datetime.now(), updated_at=datetime.now())
|
|
... created = ctx.plans.create(plan)
|
|
... print(created.id)
|
|
${plan_id}= Convert To Integer ${result}
|
|
RETURN ${plan_id}
|
|
|
|
Commit Transaction
|
|
[Documentation] Commit the transaction
|
|
Set Test Variable ${TRANSACTION_ACTIVE} ${False}
|
|
|
|
Simulate Transaction Error
|
|
[Documentation] Simulate an error in transaction
|
|
Set Test Variable ${TRANSACTION_ERROR} ${True}
|
|
Create File ${TEMP_DIR}/error_flag error
|
|
|
|
Rollback Transaction
|
|
[Documentation] Rollback the transaction
|
|
Set Test Variable ${TRANSACTION_ACTIVE} ${False}
|
|
# For error simulation, delete the error flag
|
|
Run Python Script
|
|
... from pathlib import Path
|
|
... error_flag = Path('${TEMP_DIR}/error_flag')
|
|
... if error_flag.exists():
|
|
... error_flag.unlink()
|
|
# If there was an error simulated, simulate the rollback by querying (in real impl this would rollback DB changes)
|
|
# For now, we'll note that actual transaction rollback isn't supported across multiple keywords
|
|
|
|
Test Transaction Rollback
|
|
[Documentation] Test actual transaction rollback with exception
|
|
${result}= Run Python Script
|
|
... from cleveragents.infrastructure.database.unit_of_work import UnitOfWork
|
|
... from cleveragents.domain.models.core import Project, ProjectSettings
|
|
... from pathlib import Path
|
|
... from datetime import datetime
|
|
... uow = UnitOfWork('sqlite:///${TEMP_DIR}/test.db')
|
|
... try:
|
|
... with uow.transaction() as ctx:
|
|
... project = Project(name='rollback-project', path=Path('${TEMP_DIR}'), settings=ProjectSettings(), created_at=datetime.now(), updated_at=datetime.now())
|
|
... created = ctx.projects.create(project)
|
|
... # Force an error to trigger rollback
|
|
... raise Exception('Simulated error for rollback test')
|
|
... except Exception:
|
|
... pass # Expected exception
|
|
... print('Rollback test completed')
|
|
|
|
Initialize Project With Service
|
|
[Documentation] Initialize project using service
|
|
[Arguments] ${name}
|
|
${result}= Run Python Script
|
|
... from cleveragents.application.services.project_service import ProjectService
|
|
... from cleveragents.infrastructure.database.unit_of_work import UnitOfWork
|
|
... from cleveragents.config.settings import Settings
|
|
... from pathlib import Path
|
|
... settings = Settings()
|
|
... uow = UnitOfWork('sqlite:///${TEMP_DIR}/test.db')
|
|
... service = ProjectService(settings, uow)
|
|
... project = service.initialize_project('${name}', Path('${TEMP_DIR}'))
|
|
... print('Project initialized')
|
|
|
|
Initialize And Get Project With Service
|
|
[Documentation] Initialize project and return it with ID
|
|
[Arguments] ${name}
|
|
${result}= Run Python Script
|
|
... from cleveragents.application.services.project_service import ProjectService
|
|
... from cleveragents.infrastructure.database.unit_of_work import UnitOfWork
|
|
... from cleveragents.config.settings import Settings
|
|
... from pathlib import Path
|
|
... import json
|
|
... settings = Settings()
|
|
... uow = UnitOfWork('sqlite:///${TEMP_DIR}/test.db')
|
|
... service = ProjectService(settings, uow)
|
|
... project = service.initialize_project('${name}', Path('${TEMP_DIR}'))
|
|
... print(json.dumps({'id': project.id, 'name': project.name, 'path': str(project.path)}))
|
|
${project}= Evaluate json.loads('''${result}''') json
|
|
RETURN ${project}
|
|
|
|
Get Current Project From Service
|
|
[Documentation] Get current project from service
|
|
${result}= Run Python Script
|
|
... from cleveragents.application.services.project_service import ProjectService
|
|
... from cleveragents.infrastructure.database.unit_of_work import UnitOfWork
|
|
... from cleveragents.config.settings import Settings
|
|
... import os
|
|
... os.chdir('${TEMP_DIR}')
|
|
... settings = Settings()
|
|
... uow = UnitOfWork('sqlite:///${TEMP_DIR}/test.db')
|
|
... service = ProjectService(settings, uow)
|
|
... project = service.get_current_project()
|
|
... print(project.name if project else 'None')
|
|
RETURN ${result}
|
|
|
|
Get Current Project From Service With Debug
|
|
[Documentation] Get current project from service with debugging info
|
|
${result}= Run Python Script
|
|
... from cleveragents.application.services.project_service import ProjectService
|
|
... from cleveragents.infrastructure.database.unit_of_work import UnitOfWork
|
|
... from cleveragents.config.settings import Settings
|
|
... import json
|
|
... import os
|
|
... os.chdir('${TEMP_DIR}')
|
|
... settings = Settings()
|
|
... uow = UnitOfWork('sqlite:///${TEMP_DIR}/test.db')
|
|
... service = ProjectService(settings, uow)
|
|
... project = service.get_current_project()
|
|
... if project:
|
|
... print(json.dumps({'id': project.id, 'name': project.name, 'path': str(project.path)}))
|
|
... else:
|
|
... print('null')
|
|
${project}= Run Keyword If '${result}' == 'null' Set Variable ${None}
|
|
... ELSE Evaluate json.loads('''${result}''') json
|
|
RETURN ${project}
|
|
|
|
Create Plan With Service
|
|
[Documentation] Create plan using service
|
|
[Arguments] ${prompt}
|
|
${result}= Run Python Script
|
|
... from cleveragents.application.services.plan_service import PlanService
|
|
... from cleveragents.application.services.project_service import ProjectService
|
|
... from cleveragents.infrastructure.database.unit_of_work import UnitOfWork
|
|
... from cleveragents.config.settings import Settings
|
|
... from features.mocks.mock_ai_provider import MockAIProvider
|
|
... import os
|
|
... os.chdir('${TEMP_DIR}')
|
|
... settings = Settings()
|
|
... uow = UnitOfWork('sqlite:///${TEMP_DIR}/test.db')
|
|
... mock_ai = MockAIProvider()
|
|
... project_service = ProjectService(settings, uow)
|
|
... plan_service = PlanService(settings, uow, mock_ai)
|
|
... project = project_service.get_current_project()
|
|
... plan = plan_service.create_plan(project, '${prompt}')
|
|
... print('Plan created')
|
|
|
|
Create Plan With Service For Project
|
|
[Documentation] Create plan for a specific project with ID
|
|
[Arguments] ${project_id} ${prompt}
|
|
Run Python Script
|
|
... from cleveragents.application.services.plan_service import PlanService
|
|
... from cleveragents.infrastructure.database.unit_of_work import UnitOfWork
|
|
... from cleveragents.config.settings import Settings
|
|
... from cleveragents.domain.models import Project
|
|
... import os
|
|
... os.chdir('${TEMP_DIR}')
|
|
... settings = Settings()
|
|
... uow = UnitOfWork('sqlite:///${TEMP_DIR}/test.db')
|
|
... plan_service = PlanService(settings, uow)
|
|
... # Get the project from database
|
|
... with uow.transaction() as ctx:
|
|
... project = ctx.projects.get_by_id(${project_id})
|
|
... plan = plan_service.create_plan(project, '${prompt}')
|
|
... print('Plan created')
|
|
|
|
Get Current Plan From Service
|
|
[Documentation] Get current plan from service
|
|
${result}= Run Python Script
|
|
... from cleveragents.application.services.plan_service import PlanService
|
|
... from cleveragents.application.services.project_service import ProjectService
|
|
... from cleveragents.infrastructure.database.unit_of_work import UnitOfWork
|
|
... from cleveragents.config.settings import Settings
|
|
... import os
|
|
... os.chdir('${TEMP_DIR}')
|
|
... settings = Settings()
|
|
... uow = UnitOfWork('sqlite:///${TEMP_DIR}/test.db')
|
|
... project_service = ProjectService(settings, uow)
|
|
... plan_service = PlanService(settings, uow)
|
|
... project = project_service.get_current_project()
|
|
... plan = plan_service.get_current_plan(project) if project else None
|
|
... print(plan.name if plan else 'None')
|
|
RETURN ${result}
|
|
|
|
Create Test File
|
|
[Documentation] Create a test file
|
|
[Arguments] ${filename} ${content}
|
|
Create File ${TEMP_DIR}/${filename} ${content}
|
|
|
|
Add Context With Service
|
|
[Documentation] Add context using service
|
|
[Arguments] ${filename}
|
|
Run Python Script
|
|
... from cleveragents.application.services.context_service import ContextService
|
|
... from cleveragents.application.services.project_service import ProjectService
|
|
... from cleveragents.infrastructure.database.unit_of_work import UnitOfWork
|
|
... from cleveragents.config.settings import Settings
|
|
... from pathlib import Path
|
|
... import os
|
|
... os.chdir('${TEMP_DIR}')
|
|
... settings = Settings()
|
|
... uow = UnitOfWork('sqlite:///${TEMP_DIR}/test.db')
|
|
... project_service = ProjectService(settings, uow)
|
|
... context_service = ContextService(settings, uow)
|
|
... project = project_service.get_current_project()
|
|
... added = context_service.add_to_context(project, Path('${TEMP_DIR}/${filename}'))
|
|
... print(f'Added {len(added)} files')
|
|
|
|
Get Context Count From Service
|
|
[Documentation] Get context count from service
|
|
${result}= Run Python Script
|
|
... from cleveragents.application.services.context_service import ContextService
|
|
... from cleveragents.application.services.project_service import ProjectService
|
|
... from cleveragents.infrastructure.database.unit_of_work import UnitOfWork
|
|
... from cleveragents.config.settings import Settings
|
|
... import os
|
|
... os.chdir('${TEMP_DIR}')
|
|
... settings = Settings()
|
|
... uow = UnitOfWork('sqlite:///${TEMP_DIR}/test.db')
|
|
... project_service = ProjectService(settings, uow)
|
|
... context_service = ContextService(settings, uow)
|
|
... project = project_service.get_current_project()
|
|
... contexts = context_service.list_context(project) if project else []
|
|
... print(len(contexts))
|
|
${count}= Convert To Integer ${result}
|
|
RETURN ${count}
|
|
|
|
Get Context Size From Service
|
|
[Documentation] Get context size from service
|
|
${result}= Run Python Script
|
|
... from cleveragents.application.services.context_service import ContextService
|
|
... from cleveragents.application.services.project_service import ProjectService
|
|
... from cleveragents.infrastructure.database.unit_of_work import UnitOfWork
|
|
... from cleveragents.config.settings import Settings
|
|
... import os
|
|
... os.chdir('${TEMP_DIR}')
|
|
... settings = Settings()
|
|
... uow = UnitOfWork('sqlite:///${TEMP_DIR}/test.db')
|
|
... project_service = ProjectService(settings, uow)
|
|
... context_service = ContextService(settings, uow)
|
|
... project = project_service.get_current_project()
|
|
... size = context_service.get_context_size(project) if project else 0
|
|
... print(size)
|
|
${size}= Convert To Integer ${result}
|
|
RETURN ${size}
|
|
|
|
Build Plan With Service
|
|
[Documentation] Build plan using service
|
|
Run Python Script
|
|
... from cleveragents.application.services.plan_service import PlanService
|
|
... from cleveragents.application.services.project_service import ProjectService
|
|
... from cleveragents.infrastructure.database.unit_of_work import UnitOfWork
|
|
... from cleveragents.config.settings import Settings
|
|
... import os
|
|
... os.chdir('${TEMP_DIR}')
|
|
... settings = Settings()
|
|
... uow = UnitOfWork('sqlite:///${TEMP_DIR}/test.db')
|
|
... project_service = ProjectService(settings, uow)
|
|
... plan_service = PlanService(settings, uow)
|
|
... project = project_service.get_current_project()
|
|
... changes = plan_service.build_plan(project) if project else []
|
|
... print(f'Built {len(changes)} changes')
|
|
|
|
Get Pending Changes From Service
|
|
[Documentation] Get pending changes from service
|
|
${result}= Run Python Script
|
|
... from cleveragents.application.services.plan_service import PlanService
|
|
... from cleveragents.application.services.project_service import ProjectService
|
|
... from cleveragents.infrastructure.database.unit_of_work import UnitOfWork
|
|
... from cleveragents.config.settings import Settings
|
|
... import json
|
|
... import os
|
|
... os.chdir('${TEMP_DIR}')
|
|
... settings = Settings()
|
|
... uow = UnitOfWork('sqlite:///${TEMP_DIR}/test.db')
|
|
... project_service = ProjectService(settings, uow)
|
|
... plan_service = PlanService(settings, uow)
|
|
... project = project_service.get_current_project()
|
|
... changes = plan_service.get_pending_changes(project) if project else []
|
|
... print(json.dumps([{'file': c.file_path} for c in changes]))
|
|
${changes}= Evaluate json.loads('''${result}''') json
|
|
RETURN ${changes}
|
|
|
|
Apply Changes With Service
|
|
[Documentation] Apply changes using service
|
|
${result}= Run Python Script
|
|
... from cleveragents.application.services.plan_service import PlanService
|
|
... from cleveragents.application.services.project_service import ProjectService
|
|
... from cleveragents.infrastructure.database.unit_of_work import UnitOfWork
|
|
... from cleveragents.config.settings import Settings
|
|
... import os
|
|
... os.chdir('${TEMP_DIR}')
|
|
... settings = Settings()
|
|
... uow = UnitOfWork('sqlite:///${TEMP_DIR}/test.db')
|
|
... project_service = ProjectService(settings, uow)
|
|
... plan_service = PlanService(settings, uow)
|
|
... project = project_service.get_current_project()
|
|
... count = plan_service.apply_changes(project) if project else 0
|
|
... print(count)
|
|
${count}= Convert To Integer ${result}
|
|
RETURN ${count}
|
|
|
|
Run Python Script
|
|
[Documentation] Run a Python script and return output.
|
|
... Retries once on transient failure (empty output with non-zero exit)
|
|
... to handle CI resource contention when many parallel workers spawn
|
|
... Python subprocesses simultaneously.
|
|
[Arguments] @{lines}
|
|
# Join lines
|
|
${script}= Catenate SEPARATOR=\n @{lines}
|
|
# Robot Framework strips leading whitespace from continuation lines; reconstruct locally
|
|
${code}= Fix Python Indentation ${script}
|
|
# Prepare logging suppression header (also needs indentation fix)
|
|
${header_raw}= Catenate SEPARATOR=\n
|
|
... import sys
|
|
... import os
|
|
... sys.path.insert(0, '${CURDIR}/..')
|
|
... os.environ['PYTHONWARNINGS'] = 'ignore'
|
|
... os.environ['CLEVERAGENTS_TESTING'] = 'true'
|
|
... # Disable all logging
|
|
... import logging
|
|
... logging.disable(logging.CRITICAL)
|
|
... # Completely disable structlog by replacing it with a no-op logger
|
|
... import structlog
|
|
... class NoOpLogger:
|
|
... def __init__(self, *args, **kwargs): pass
|
|
... def debug(self, *args, **kwargs): pass
|
|
... def info(self, *args, **kwargs): pass
|
|
... def warning(self, *args, **kwargs): pass
|
|
... def error(self, *args, **kwargs): pass
|
|
... def critical(self, *args, **kwargs): pass
|
|
... def bind(self, **kwargs): return self
|
|
... def unbind(self, *args): return self
|
|
... def try_unbind(self, *args): return self
|
|
... def new(self, **kwargs): return self
|
|
... import warnings
|
|
... warnings.filterwarnings('ignore')
|
|
... structlog.get_logger = lambda *args, **kwargs: NoOpLogger()
|
|
# Fix indentation for the header part only
|
|
${header}= Fix Python Indentation ${header_raw}
|
|
# Combine header and code
|
|
${full_code}= Catenate SEPARATOR=\n ${header} ${code}
|
|
# Write to a temporary file — use mkstemp so the fd is closed before
|
|
# Create File writes to it (avoids leaking an open descriptor).
|
|
${temp_file}= Evaluate (lambda t: (__import__('os').close(t[0]), t[1])[-1])(__import__('tempfile').mkstemp(suffix='.py', dir='/tmp'))
|
|
Create File ${temp_file} ${full_code}
|
|
${result}= Run Process ${PYTHON} ${temp_file} timeout=180s stderr=STDOUT env:PYTHONWARNINGS=ignore env:PYTHONDONTWRITEBYTECODE=1
|
|
# Retry once for transient worker pressure (e.g. SIGTERM under heavy CI load)
|
|
IF ${result.rc} != 0
|
|
Log First Python script attempt failed with rc=${result.rc}; retrying once. Output: ${result.stdout} WARN
|
|
${retry}= Run Process ${PYTHON} ${temp_file} timeout=180s stderr=STDOUT env:PYTHONWARNINGS=ignore env:PYTHONDONTWRITEBYTECODE=1
|
|
IF ${retry.rc} == 0
|
|
${result}= Set Variable ${retry}
|
|
ELSE
|
|
Remove File ${temp_file}
|
|
Fail Python script execution failed after retry (rc=${retry.rc}): ${retry.stdout}
|
|
END
|
|
END
|
|
Remove File ${temp_file}
|
|
# Extract just the number from the output (last line)
|
|
${lines}= Split String ${result.stdout} \n
|
|
${filtered_lines}= Create List
|
|
FOR ${line} IN @{lines}
|
|
${stripped}= Strip String ${line}
|
|
# Skip debug/logging lines
|
|
IF '${stripped}' != '' and not '${stripped}'.startswith('[debug') and not '${stripped}'.startswith('[info') and not '${stripped}'.startswith('[warning')
|
|
Append To List ${filtered_lines} ${stripped}
|
|
END
|
|
END
|
|
${last_line}= Get From List ${filtered_lines} -1
|
|
RETURN ${last_line}
|
|
|
|
Cleanup Test Environment
|
|
[Documentation] Clean up test artifacts
|
|
Remove Directory ${TEMP_DIR} recursive=True
|
|
Remove Environment Variable CLEVERAGENTS_HOME
|