AgentEvalTool/tests/unit/test_metrics_calculation.py
sinohqb 2e7d419f05 feat(intelligent-eval): implement monitoring and alerting (ticket 07)
- Add metrics.py with pool utilization, task backlog, stuck rate, avg processing time, eval completion rate
- Add alerts.py with alert rules (pool utilization > 90%, task backlog > 50, stuck rate > 10%)
- Implement alert history and webhook notifications
- Add metrics and alerts APIs
- Add database migration for alert history table
- Add 11 unit tests for metrics, 10 unit tests for alerts, 8 integration tests
- Update migration tests to include new alert history table

All 853 tests passing.
2026-08-12 10:41:15 +08:00

214 lines
6.0 KiB
Python

"""Unit tests for metrics calculation."""
from datetime import timedelta
import pytest
from sqlmodel import Session
from agenteval.intelligent_eval import metrics
from agenteval.intelligent_eval.models import IntelligentEvalStatus
from agenteval.storage.db import (
IntelligentEvalDB,
IntelligentEvalTaskQueueDB,
OpenClawCronPoolDB,
utc_now,
)
def test_calculate_pool_utilization_empty(db_session: Session):
"""Test pool utilization when no crons exist."""
utilization = metrics.calculate_pool_utilization(db_session)
assert utilization == 0.0
def test_calculate_pool_utilization(db_session: Session):
"""Test pool utilization calculation."""
# Create 10 crons: 6 busy, 4 idle
for i in range(6):
cron = OpenClawCronPoolDB(
openclaw_cron_id=f"busy-{i}",
status="busy",
last_active_at=utc_now(),
)
db_session.add(cron)
for i in range(4):
cron = OpenClawCronPoolDB(
openclaw_cron_id=f"idle-{i}",
status="idle",
last_active_at=utc_now(),
)
db_session.add(cron)
db_session.commit()
utilization = metrics.calculate_pool_utilization(db_session)
assert utilization == 0.6
def test_calculate_task_backlog_empty(db_session: Session):
"""Test task backlog when no tasks exist."""
backlog = metrics.calculate_task_backlog(db_session)
assert backlog == 0
def test_calculate_task_backlog(db_session: Session):
"""Test task backlog calculation."""
# Create 5 pending tasks
for i in range(5):
task = IntelligentEvalTaskQueueDB(
eval_id=f"eval-{i}",
status="pending",
priority=1,
reason="slot_due",
)
db_session.add(task)
# Create 3 assigned tasks (not counted)
for i in range(3):
task = IntelligentEvalTaskQueueDB(
eval_id=f"eval-assigned-{i}",
status="assigned",
priority=1,
reason="slot_due",
)
db_session.add(task)
db_session.commit()
backlog = metrics.calculate_task_backlog(db_session)
assert backlog == 5
def test_calculate_stuck_rate_empty(db_session: Session):
"""Test stuck rate when no crons exist."""
rate = metrics.calculate_stuck_rate(db_session)
assert rate == 0.0
def test_calculate_stuck_rate(db_session: Session):
"""Test stuck rate calculation."""
# Create 10 crons: 2 stuck, 8 active
for i in range(2):
cron = OpenClawCronPoolDB(
openclaw_cron_id=f"stuck-{i}",
status="stuck",
last_active_at=utc_now(),
)
db_session.add(cron)
for i in range(8):
cron = OpenClawCronPoolDB(
openclaw_cron_id=f"active-{i}",
status="busy",
last_active_at=utc_now(),
)
db_session.add(cron)
db_session.commit()
rate = metrics.calculate_stuck_rate(db_session)
assert rate == 0.2
def test_calculate_avg_processing_time_empty(db_session: Session):
"""Test average processing time when no completed tasks."""
avg_time = metrics.calculate_avg_processing_time(db_session)
assert avg_time is None
def test_calculate_avg_processing_time(db_session: Session):
"""Test average processing time calculation."""
now = utc_now()
# Create 3 completed tasks with different processing times
task1 = IntelligentEvalTaskQueueDB(
eval_id="eval-1",
status="completed",
priority=1,
reason="slot_due",
assigned_at=now - timedelta(minutes=10),
completed_at=now - timedelta(minutes=5),
)
task2 = IntelligentEvalTaskQueueDB(
eval_id="eval-2",
status="completed",
priority=1,
reason="slot_due",
assigned_at=now - timedelta(minutes=20),
completed_at=now - timedelta(minutes=10),
)
task3 = IntelligentEvalTaskQueueDB(
eval_id="eval-3",
status="completed",
priority=1,
reason="slot_due",
assigned_at=now - timedelta(minutes=30),
completed_at=now - timedelta(minutes=15),
)
db_session.add_all([task1, task2, task3])
db_session.commit()
avg_time = metrics.calculate_avg_processing_time(db_session)
# Average: (5 + 10 + 15) / 3 = 10 minutes = 600 seconds
assert avg_time == 600.0
def test_calculate_eval_completion_rate_empty(db_session: Session):
"""Test eval completion rate when no evals exist."""
rate = metrics.calculate_eval_completion_rate(db_session)
assert rate == 0.0
def test_calculate_eval_completion_rate(db_session: Session):
"""Test eval completion rate calculation."""
# Create 10 evals: 7 completed, 3 executing
for i in range(7):
eval_db = IntelligentEvalDB(
name=f"eval-completed-{i}",
target_id="target1",
status=IntelligentEvalStatus.COMPLETED.value,
)
db_session.add(eval_db)
for i in range(3):
eval_db = IntelligentEvalDB(
name=f"eval-executing-{i}",
target_id="target1",
status=IntelligentEvalStatus.EXECUTING.value,
)
db_session.add(eval_db)
db_session.commit()
rate = metrics.calculate_eval_completion_rate(db_session)
assert rate == 0.7
def test_get_all_metrics(db_session: Session):
"""Test getting all metrics."""
# Create some test data
for i in range(5):
cron = OpenClawCronPoolDB(
openclaw_cron_id=f"cron-{i}",
status="busy" if i < 3 else "idle",
last_active_at=utc_now(),
)
db_session.add(cron)
db_session.commit()
all_metrics = metrics.get_all_metrics(db_session)
assert "pool_utilization" in all_metrics
assert "task_backlog" in all_metrics
assert "stuck_rate" in all_metrics
assert "avg_processing_time_seconds" in all_metrics
assert "eval_completion_rate" in all_metrics
assert "timestamp" in all_metrics
assert all_metrics["pool_utilization"] == 0.6
assert all_metrics["task_backlog"] == 0
assert all_metrics["stuck_rate"] == 0.0