Files
cleveragents-core/robot/database_integration.robot
T
brent.edwards 2c838dedee
CI / lint (pull_request) Failing after 17s
CI / typecheck (pull_request) Successful in 46s
CI / quality (pull_request) Successful in 32s
CI / coverage (pull_request) Has been skipped
CI / security (pull_request) Successful in 53s
CI / benchmark-publish (pull_request) Has been skipped
CI / benchmark-regression (pull_request) Has been skipped
CI / build (pull_request) Successful in 31s
CI / e2e_tests (pull_request) Successful in 4m19s
CI / unit_tests (pull_request) Successful in 5m18s
CI / docker (pull_request) Has been skipped
CI / integration_tests (pull_request) Successful in 5m46s
feat(cli): repo indexing CLI functional
Add agents repo index and agents repo status CLI commands. The repo
index command triggers full or incremental indexing of a repository
resource. The status command displays indexing metadata including
file count, token estimate, primary language, and status. Both
commands support text and JSON output formats. Wires the existing
RepoIndexingService backend to the CLI layer.

Also fixes pre-existing test failures discovered during full nox
suite verification.

ISSUES CLOSED: #856
2026-03-19 22:20:14 +00:00

786 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=60s stderr=STDOUT env:PYTHONWARNINGS=ignore env:PYTHONDONTWRITEBYTECODE=1
Remove File ${temp_file}
# Check if process failed and log stderr if present
IF ${result.rc} != 0
Log Process failed with rc=${result.rc} stdout: ${result.stdout} WARN
Fail Python script execution failed (rc=${result.rc}): ${result.stdout}
END
# 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