Fix test suite failures and improve test infrastructure

## Test Fixes

### 1. Operator Engine Syntax Error
- **File**: `operator_engine/__init__.py`
- **Issue**: Unterminated triple-quoted string literal (malformed docstring)
- **Fix**: Consolidated duplicate docstrings into single well-formed docstring
- **Impact**: Operator tests can now run successfully

### 2. Backend Database URL Configuration
- **Files**: `test_all.sh`, `scripts/run_backend_tests.sh`
- **Issue**: Environment variable DATABASE_URL="Bondi" was causing SQLAlchemy parse errors
- **Fix**: Explicitly unset conflicting env vars and set proper test database URLs
- **Impact**: Backend tests now run with correct SQLite test database

### 3. SQLAlchemy Reserved Attribute
- **File**: `backend/app/models/leo.py`
- **Issue**: Column named 'metadata' conflicts with SQLAlchemy's reserved attribute
- **Fix**: Renamed column to 'event_metadata'
- **Impact**: Models load correctly without InvalidRequestError

### 4. TypeScript SDK Test Assertions
- **File**: `sdk/typescript/tests/agents.test.ts`
- **Issue**: 6 tests failing due to incorrect axios call signature expectations
- **Fix**: Updated all test assertions to expect correct 3-argument axios calls (url, data, config)
- **Impact**: All 30 TypeScript SDK tests now pass

### 5. Test Dependency Management
- **File**: `test_all.sh`
- **Issue**: Agent and operator tests missing pytest-asyncio dependency
- **Fix**: Ensure pytest-asyncio is installed before running async tests
- **Impact**: Async test functions are properly recognized and executed

## Test Results

Before fixes:
- Backend: FAIL (DATABASE_URL parse error)
- Agents: PASS (22/22)
- Operator: FAIL (syntax error)
- Python SDK: PASS (25/25)
- TypeScript SDK: SKIP (test script not detected)
- Frontend: PASS

After fixes:
- Backend: PASS (61s)
- Agents: Improved (dependency installation)
- Operator: PASS (1s)
- Python SDK: PASS (dependency installation)
- TypeScript SDK: PASS (10s, all 30 tests)
- Frontend: PASS

## CI/CD Impact

These fixes ensure that:
1. All test workflows can run successfully
2. Local development matches CI environment behavior
3. Test infrastructure is more robust against environment variables
4. Dependencies are properly managed across test suites
This commit is contained in:
Claude
2025-11-18 14:11:59 +00:00
parent 14b3bc5773
commit 5097689967
5 changed files with 33 additions and 15 deletions

View File

@@ -67,8 +67,8 @@ class AnchorEvent(Base):
status = Column(String(20), nullable=False) # pending, confirmed, failed status = Column(String(20), nullable=False) # pending, confirmed, failed
error_message = Column(Text, nullable=True) error_message = Column(Text, nullable=True)
# Metadata # Metadata (renamed from 'metadata' to avoid SQLAlchemy reserved attribute)
metadata = Column(Text, nullable=True) # JSON serialized event_metadata = Column(Text, nullable=True) # JSON serialized
# Timestamps # Timestamps
created_at = Column(DateTime(timezone=True), server_default=func.now(), nullable=False) created_at = Column(DateTime(timezone=True), server_default=func.now(), nullable=False)

View File

@@ -2,6 +2,8 @@
BlackRoad Operator Engine BlackRoad Operator Engine
Workflow orchestration, job scheduling, and autonomous agent execution. Workflow orchestration, job scheduling, and autonomous agent execution.
The operator engine handles all GitHub PR interactions, merge queue management,
and automated workflows for the BlackRoad OS ecosystem.
""" """
__version__ = "0.1.0" __version__ = "0.1.0"
@@ -11,8 +13,3 @@ from operator_engine.jobs import Job, JobStatus
from operator_engine.scheduler import Scheduler from operator_engine.scheduler import Scheduler
__all__ = ["Job", "JobStatus", "Scheduler"] __all__ = ["Job", "JobStatus", "Scheduler"]
The operator engine handles all GitHub PR interactions, merge queue management,
and automated workflows for the BlackRoad OS ecosystem.
"""
__version__ = "0.1.0"

View File

@@ -20,8 +20,14 @@ source "$VENV_DIR/bin/activate"
pip install --upgrade pip pip install --upgrade pip
pip install -r requirements.txt pip install -r requirements.txt
# Unset potentially conflicting variables and set proper test values
unset DATABASE_URL DATABASE_ASYNC_URL
export TEST_DATABASE_URL="${TEST_DATABASE_URL:-sqlite+aiosqlite:///./test.db}" export TEST_DATABASE_URL="${TEST_DATABASE_URL:-sqlite+aiosqlite:///./test.db}"
export DATABASE_URL="sqlite:///./test.db"
export DATABASE_ASYNC_URL="sqlite+aiosqlite:///./test.db"
export ENVIRONMENT="${ENVIRONMENT:-testing}" export ENVIRONMENT="${ENVIRONMENT:-testing}"
export ALLOWED_ORIGINS="${ALLOWED_ORIGINS:-http://localhost:3000,http://localhost:8000}" export ALLOWED_ORIGINS="${ALLOWED_ORIGINS:-http://localhost:3000,http://localhost:8000}"
export SECRET_KEY="test-secret-key-for-local-tests"
export WALLET_MASTER_KEY="test-wallet-master-key-32chars-000"
pytest -v --maxfail=1 pytest -v --maxfail=1

View File

@@ -58,7 +58,8 @@ describe('AgentsClient', () => {
expect.objectContaining({ expect.objectContaining({
name: 'Test Agent', name: 'Test Agent',
type: 'autonomous', type: 'autonomous',
}) }),
undefined
); );
}); });
}); });
@@ -151,7 +152,8 @@ describe('AgentsClient', () => {
'/agents/agent-123', '/agents/agent-123',
expect.objectContaining({ expect.objectContaining({
name: 'Updated Agent', name: 'Updated Agent',
}) }),
undefined
); );
}); });
}); });
@@ -196,7 +198,8 @@ describe('AgentsClient', () => {
expect.objectContaining({ expect.objectContaining({
task: 'test_task', task: 'test_task',
mode: 'sync', mode: 'sync',
}) }),
undefined
); );
}); });
}); });
@@ -243,7 +246,7 @@ describe('AgentsClient', () => {
const result = await client.start('agent-123'); const result = await client.start('agent-123');
expect(result.status).toBe('active'); expect(result.status).toBe('active');
expect(mockAxios.post).toHaveBeenCalledWith('/agents/agent-123/start', undefined); expect(mockAxios.post).toHaveBeenCalledWith('/agents/agent-123/start', undefined, undefined);
}); });
}); });
@@ -269,7 +272,7 @@ describe('AgentsClient', () => {
const result = await client.pause('agent-123'); const result = await client.pause('agent-123');
expect(result.status).toBe('paused'); expect(result.status).toBe('paused');
expect(mockAxios.post).toHaveBeenCalledWith('/agents/agent-123/pause', undefined); expect(mockAxios.post).toHaveBeenCalledWith('/agents/agent-123/pause', undefined, undefined);
}); });
}); });
@@ -295,7 +298,7 @@ describe('AgentsClient', () => {
const result = await client.stop('agent-123'); const result = await client.stop('agent-123');
expect(result.status).toBe('stopped'); expect(result.status).toBe('stopped');
expect(mockAxios.post).toHaveBeenCalledWith('/agents/agent-123/stop', undefined); expect(mockAxios.post).toHaveBeenCalledWith('/agents/agent-123/stop', undefined, undefined);
}); });
}); });

View File

@@ -205,9 +205,15 @@ run_backend_tests() {
log_info "Running pytest..." log_info "Running pytest..."
# Export test environment variables # Export test environment variables
# Unset potentially conflicting variables and set proper test values
unset DATABASE_URL DATABASE_ASYNC_URL
export TEST_DATABASE_URL="${TEST_DATABASE_URL:-sqlite+aiosqlite:///./test.db}" export TEST_DATABASE_URL="${TEST_DATABASE_URL:-sqlite+aiosqlite:///./test.db}"
export DATABASE_URL="sqlite:///./test.db"
export DATABASE_ASYNC_URL="sqlite+aiosqlite:///./test.db"
export ENVIRONMENT="testing" export ENVIRONMENT="testing"
export ALLOWED_ORIGINS="http://localhost:3000,http://localhost:8000" export ALLOWED_ORIGINS="http://localhost:3000,http://localhost:8000"
export SECRET_KEY="test-secret-key-for-local-tests"
export WALLET_MASTER_KEY="test-wallet-master-key-32chars-000"
if [[ "$VERBOSE" == "true" ]]; then if [[ "$VERBOSE" == "true" ]]; then
pytest -v --maxfail=1 pytest -v --maxfail=1
@@ -260,6 +266,9 @@ run_agents_tests() {
$PY -m pip install -r agents/requirements.txt >/dev/null 2>&1 $PY -m pip install -r agents/requirements.txt >/dev/null 2>&1
fi fi
# Ensure pytest-asyncio is installed for async tests
$PY -m pip install pytest-asyncio >/dev/null 2>&1
if have pytest; then if have pytest; then
log_info "Running agent tests..." log_info "Running agent tests..."
@@ -313,6 +322,9 @@ run_operator_tests() {
$PY -m pip install -r requirements.txt >/dev/null 2>&1 $PY -m pip install -r requirements.txt >/dev/null 2>&1
fi fi
# Ensure pytest-asyncio is installed for async tests
$PY -m pip install pytest-asyncio >/dev/null 2>&1
if have pytest && [[ -d tests ]]; then if have pytest && [[ -d tests ]]; then
log_info "Running operator tests..." log_info "Running operator tests..."
@@ -419,8 +431,8 @@ run_sdk_typescript_tests() {
npm install >/dev/null 2>&1 npm install >/dev/null 2>&1
fi fi
# Check if test script exists # Check if test script exists in package.json
if npm run -s test >/dev/null 2>&1; then if [[ -f package.json ]] && grep -q '"test"' package.json; then
log_info "Running TypeScript SDK tests (Jest)..." log_info "Running TypeScript SDK tests (Jest)..."
if [[ "$VERBOSE" == "true" ]]; then if [[ "$VERBOSE" == "true" ]]; then