Files
cleveragents-core/robot/database_integration.robot
brent.edwards 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
fix: add missing validations/unit-tests.yaml example
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
2026-05-30 00:09:20 -04:00

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