WIP: Gemini Code progress on #1139
Automated salvage commit — agent session ended (exit 124). Work in progress, may need continuation.
This commit is contained in:
21
tests/dashboard/services/test_agent_metrics.py
Normal file
21
tests/dashboard/services/test_agent_metrics.py
Normal file
@@ -0,0 +1,21 @@
|
||||
|
||||
import unittest
|
||||
from src.dashboard.services.scorecard_service import (
|
||||
AgentMetrics,
|
||||
)
|
||||
|
||||
class TestAgentMetrics(unittest.TestCase):
|
||||
def test_agent_metrics_pr_merge_rate(self):
|
||||
metrics = AgentMetrics(agent_id="test_agent")
|
||||
self.assertEqual(metrics.pr_merge_rate, 0.0)
|
||||
|
||||
metrics.prs_opened = {1, 2, 3, 4}
|
||||
metrics.prs_merged = {1, 3}
|
||||
self.assertEqual(metrics.pr_merge_rate, 0.5)
|
||||
|
||||
metrics.prs_opened = {1, 2, 3, 4, 5}
|
||||
metrics.prs_merged = {1, 2, 3, 4, 5}
|
||||
self.assertEqual(metrics.pr_merge_rate, 1.0)
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
23
tests/dashboard/services/test_get_period_bounds.py
Normal file
23
tests/dashboard/services/test_get_period_bounds.py
Normal file
@@ -0,0 +1,23 @@
|
||||
|
||||
import unittest
|
||||
from datetime import datetime, UTC
|
||||
from src.dashboard.services.scorecard_service import (
|
||||
PeriodType,
|
||||
_get_period_bounds,
|
||||
)
|
||||
|
||||
class TestGetPeriodBounds(unittest.TestCase):
|
||||
def test_get_period_bounds(self):
|
||||
# Test daily period
|
||||
reference_date = datetime(2024, 1, 10, 12, 0, 0, tzinfo=UTC)
|
||||
start, end = _get_period_bounds(PeriodType.daily, reference_date)
|
||||
self.assertEqual(start, datetime(2024, 1, 9, 0, 0, 0, tzinfo=UTC))
|
||||
self.assertEqual(end, datetime(2024, 1, 10, 0, 0, 0, tzinfo=UTC))
|
||||
|
||||
# Test weekly period
|
||||
start, end = _get_period_bounds(PeriodType.weekly, reference_date)
|
||||
self.assertEqual(start, datetime(2024, 1, 3, 0, 0, 0, tzinfo=UTC))
|
||||
self.assertEqual(end, datetime(2024, 1, 10, 0, 0, 0, tzinfo=UTC))
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
287
tests/dashboard/services/test_scorecard_service.py
Normal file
287
tests/dashboard/services/test_scorecard_service.py
Normal file
@@ -0,0 +1,287 @@
|
||||
|
||||
import unittest
|
||||
from unittest.mock import MagicMock, patch
|
||||
from datetime import datetime, UTC, timedelta
|
||||
|
||||
from src.dashboard.services.scorecard_service import (
|
||||
AgentMetrics,
|
||||
PeriodType,
|
||||
ScorecardSummary,
|
||||
_get_period_bounds,
|
||||
_extract_actor_from_event,
|
||||
_is_tracked_agent,
|
||||
_aggregate_metrics,
|
||||
_generate_narrative_bullets,
|
||||
_detect_patterns,
|
||||
generate_all_scorecards,
|
||||
generate_scorecard,
|
||||
get_tracked_agents,
|
||||
)
|
||||
from infrastructure.events.bus import Event
|
||||
|
||||
|
||||
class TestScorecardService(unittest.TestCase):
|
||||
def test_get_tracked_agents(self):
|
||||
self.assertEqual(
|
||||
get_tracked_agents(), ["claude", "gemini", "hermes", "kimi", "manus"]
|
||||
)
|
||||
|
||||
def test_agent_metrics_pr_merge_rate(self):
|
||||
metrics = AgentMetrics(agent_id="test_agent")
|
||||
self.assertEqual(metrics.pr_merge_rate, 0.0)
|
||||
|
||||
metrics.prs_opened = {1, 2, 3, 4}
|
||||
metrics.prs_merged = {1, 3}
|
||||
self.assertEqual(metrics.pr_merge_rate, 0.5)
|
||||
|
||||
metrics.prs_opened = {1, 2, 3, 4, 5}
|
||||
metrics.prs_merged = {1, 2, 3, 4, 5}
|
||||
self.assertEqual(metrics.pr_merge_rate, 1.0)
|
||||
|
||||
def test_scorecard_summary_to_dict(self):
|
||||
metrics = AgentMetrics(
|
||||
agent_id="test_agent",
|
||||
issues_touched={1, 2},
|
||||
prs_opened={3, 4},
|
||||
prs_merged={3},
|
||||
tests_affected={"test1.py", "test2.py"},
|
||||
tokens_earned=100,
|
||||
tokens_spent=50,
|
||||
commits=10,
|
||||
comments=5,
|
||||
)
|
||||
summary = ScorecardSummary(
|
||||
agent_id="test_agent",
|
||||
period_type=PeriodType.daily,
|
||||
period_start=datetime(2024, 1, 1, tzinfo=UTC),
|
||||
period_end=datetime(2024, 1, 2, tzinfo=UTC),
|
||||
metrics=metrics,
|
||||
narrative_bullets=["test bullet"],
|
||||
patterns=["test pattern"],
|
||||
)
|
||||
expected_dict = {
|
||||
"agent_id": "test_agent",
|
||||
"period_type": "daily",
|
||||
"period_start": "2024-01-01T00:00:00+00:00",
|
||||
"period_end": "2024-01-02T00:00:00+00:00",
|
||||
"metrics": {
|
||||
"issues_touched": 2,
|
||||
"prs_opened": 2,
|
||||
"prs_merged": 1,
|
||||
"pr_merge_rate": 0.5,
|
||||
"tests_affected": 2,
|
||||
"commits": 10,
|
||||
"comments": 5,
|
||||
"tokens_earned": 100,
|
||||
"tokens_spent": 50,
|
||||
"token_net": 50,
|
||||
},
|
||||
"narrative_bullets": ["test bullet"],
|
||||
"patterns": ["test pattern"],
|
||||
}
|
||||
self.assertEqual(summary.to_dict(), expected_dict)
|
||||
|
||||
def test_get_period_bounds(self):
|
||||
# Test daily period
|
||||
reference_date = datetime(2024, 1, 10, 12, 0, 0, tzinfo=UTC)
|
||||
start, end = _get_period_bounds(PeriodType.daily, reference_date)
|
||||
self.assertEqual(start, datetime(2024, 1, 9, 0, 0, 0, tzinfo=UTC))
|
||||
self.assertEqual(end, datetime(2024, 1, 10, 0, 0, 0, tzinfo=UTC))
|
||||
|
||||
# Test weekly period
|
||||
start, end = _get_period_bounds(PeriodType.weekly, reference_date)
|
||||
self.assertEqual(start, datetime(2024, 1, 3, 0, 0, 0, tzinfo=UTC))
|
||||
self.assertEqual(end, datetime(2024, 1, 10, 0, 0, 0, tzinfo=UTC))
|
||||
|
||||
def test_extract_actor_from_event(self):
|
||||
event_with_actor = Event(
|
||||
id="1",
|
||||
source="test",
|
||||
timestamp="2024-01-01T00:00:00Z",
|
||||
type="test.event",
|
||||
data={"actor": "gemini"},
|
||||
)
|
||||
self.assertEqual(_extract_actor_from_event(event_with_actor), "gemini")
|
||||
|
||||
event_with_agent_id = Event(
|
||||
id="2",
|
||||
source="test",
|
||||
timestamp="2024-01-01T00:00:00Z",
|
||||
type="test.event",
|
||||
data={"agent_id": "claude"},
|
||||
)
|
||||
self.assertEqual(_extract_actor_from_event(event_with_agent_id), "claude")
|
||||
|
||||
event_with_source = Event(
|
||||
id="3",
|
||||
source="hermes",
|
||||
timestamp="2024-01-01T00:00:00Z",
|
||||
type="test.event",
|
||||
data={},
|
||||
)
|
||||
self.assertEqual(_extract_actor_from_event(event_with_source), "hermes")
|
||||
|
||||
def test_is_tracked_agent(self):
|
||||
self.assertTrue(_is_tracked_agent("gemini"))
|
||||
self.assertTrue(_is_tracked_agent("GEMINI"))
|
||||
self.assertFalse(_is_tracked_agent("untracked_agent"))
|
||||
self.assertFalse(_is_tracked_agent("test_user"))
|
||||
|
||||
def test_aggregate_metrics(self):
|
||||
events = [
|
||||
Event(
|
||||
id="1",
|
||||
source="gemini",
|
||||
timestamp="ts",
|
||||
type="gitea.push",
|
||||
data={"num_commits": 2},
|
||||
),
|
||||
Event(
|
||||
id="2",
|
||||
source="gemini",
|
||||
timestamp="ts",
|
||||
type="gitea.issue.opened",
|
||||
data={"issue_number": 101},
|
||||
),
|
||||
Event(
|
||||
id="3",
|
||||
source="gemini",
|
||||
timestamp="ts",
|
||||
type="gitea.issue.comment",
|
||||
data={"issue_number": 101},
|
||||
),
|
||||
Event(
|
||||
id="4",
|
||||
source="gemini",
|
||||
timestamp="ts",
|
||||
type="gitea.pull_request",
|
||||
data={"pr_number": 202, "action": "opened"},
|
||||
),
|
||||
Event(
|
||||
id="5",
|
||||
source="gemini",
|
||||
timestamp="ts",
|
||||
type="gitea.pull_request",
|
||||
data={"pr_number": 202, "action": "closed", "merged": True},
|
||||
),
|
||||
Event(
|
||||
id="6",
|
||||
source="gemini",
|
||||
timestamp="ts",
|
||||
type="agent.task.completed",
|
||||
data={"tests_affected": ["test_a.py"], "token_reward": 50},
|
||||
),
|
||||
Event(
|
||||
id="7",
|
||||
source="claude",
|
||||
timestamp="ts",
|
||||
type="test.execution",
|
||||
data={"test_files": ["test_b.py"]},
|
||||
),
|
||||
]
|
||||
|
||||
metrics_by_agent = _aggregate_metrics(events)
|
||||
self.assertIn("gemini", metrics_by_agent)
|
||||
self.assertIn("claude", metrics_by_agent)
|
||||
|
||||
gemini_metrics = metrics_by_agent["gemini"]
|
||||
self.assertEqual(gemini_metrics.commits, 2)
|
||||
self.assertEqual(gemini_metrics.issues_touched, {101, 202})
|
||||
self.assertEqual(gemini_metrics.prs_opened, {202})
|
||||
self.assertEqual(gemini_metrics.prs_merged, {202})
|
||||
self.assertEqual(gemini_metrics.tests_affected, {"test_a.py"})
|
||||
self.assertEqual(gemini_metrics.tokens_earned, 50)
|
||||
self.assertEqual(gemini_metrics.comments, 1)
|
||||
|
||||
claude_metrics = metrics_by_agent["claude"]
|
||||
self.assertEqual(claude_metrics.tests_affected, {"test_b.py"})
|
||||
|
||||
def test_generate_narrative_bullets(self):
|
||||
metrics = AgentMetrics("gemini", commits=5, prs_opened={1}, prs_merged={1})
|
||||
bullets = _generate_narrative_bullets(metrics, PeriodType.daily)
|
||||
self.assertIn("Active across 5 commits, 1 PR opened, 1 PR merged this day.", bullets)
|
||||
|
||||
metrics = AgentMetrics("gemini", tokens_earned=100, tokens_spent=20)
|
||||
bullets = _generate_narrative_bullets(metrics, PeriodType.weekly)
|
||||
self.assertIn("Net earned 80 tokens (100 earned, 20 spent).", bullets)
|
||||
|
||||
metrics = AgentMetrics("gemini")
|
||||
bullets = _generate_narrative_bullets(metrics, PeriodType.daily)
|
||||
self.assertEqual(bullets, ["No recorded activity this day."])
|
||||
|
||||
def test_detect_patterns(self):
|
||||
# High merge rate
|
||||
metrics = AgentMetrics("gemini", prs_opened={1, 2, 3}, prs_merged={1, 2, 3})
|
||||
patterns = _detect_patterns(metrics)
|
||||
self.assertIn("High merge rate with few failures — code quality focus.", patterns)
|
||||
|
||||
# High commit volume without PRs
|
||||
metrics = AgentMetrics("gemini", commits=11)
|
||||
patterns = _detect_patterns(metrics)
|
||||
self.assertIn("High commit volume without PRs — working directly on main?", patterns)
|
||||
|
||||
# Strong token accumulation
|
||||
metrics = AgentMetrics("gemini", tokens_earned=150, tokens_spent=20)
|
||||
patterns = _detect_patterns(metrics)
|
||||
self.assertIn("Strong token accumulation — high value delivery.", patterns)
|
||||
|
||||
@patch("src.dashboard.services.scorecard_service._collect_events_for_period")
|
||||
@patch("src.dashboard.services.scorecard_service._query_token_transactions")
|
||||
def test_generate_scorecard(
|
||||
self, mock_query_tokens, mock_collect_events
|
||||
):
|
||||
mock_collect_events.return_value = [
|
||||
Event(
|
||||
id="1",
|
||||
source="gemini",
|
||||
timestamp="ts",
|
||||
type="gitea.push",
|
||||
data={"num_commits": 2},
|
||||
)
|
||||
]
|
||||
mock_query_tokens.return_value = (100, 50)
|
||||
|
||||
scorecard = generate_scorecard("gemini", PeriodType.daily)
|
||||
self.assertIsNotNone(scorecard)
|
||||
self.assertEqual(scorecard.agent_id, "gemini")
|
||||
self.assertEqual(scorecard.metrics.commits, 2)
|
||||
self.assertEqual(scorecard.metrics.tokens_earned, 100)
|
||||
self.assertEqual(scorecard.metrics.tokens_spent, 50)
|
||||
|
||||
@patch("src.dashboard.services.scorecard_service._collect_events_for_period")
|
||||
@patch("src.dashboard.services.scorecard_service._query_token_transactions")
|
||||
def test_generate_all_scorecards(
|
||||
self, mock_query_tokens, mock_collect_events
|
||||
):
|
||||
mock_collect_events.return_value = [
|
||||
Event(
|
||||
id="1",
|
||||
source="gemini",
|
||||
timestamp="ts",
|
||||
type="gitea.push",
|
||||
data={"num_commits": 2},
|
||||
),
|
||||
Event(
|
||||
id="2",
|
||||
source="claude",
|
||||
timestamp="ts",
|
||||
type="gitea.issue.comment",
|
||||
data={"issue_number": 101},
|
||||
),
|
||||
]
|
||||
mock_query_tokens.side_effect = [(100, 50), (200, 75), (0, 0), (0, 0), (0,0)]
|
||||
|
||||
scorecards = generate_all_scorecards(PeriodType.daily)
|
||||
self.assertEqual(len(scorecards), 5)
|
||||
|
||||
gemini_scorecard = next(s for s in scorecards if s.agent_id == "gemini")
|
||||
self.assertEqual(gemini_scorecard.metrics.commits, 2)
|
||||
self.assertEqual(gemini_scorecard.metrics.tokens_earned, 100)
|
||||
|
||||
claude_scorecard = next(s for s in scorecards if s.agent_id == "claude")
|
||||
self.assertEqual(claude_scorecard.metrics.comments, 1)
|
||||
self.assertEqual(claude_scorecard.metrics.tokens_earned, 200)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
55
tests/dashboard/services/test_scorecard_summary.py
Normal file
55
tests/dashboard/services/test_scorecard_summary.py
Normal file
@@ -0,0 +1,55 @@
|
||||
|
||||
import unittest
|
||||
from datetime import datetime, UTC
|
||||
from src.dashboard.services.scorecard_service import (
|
||||
AgentMetrics,
|
||||
PeriodType,
|
||||
ScorecardSummary,
|
||||
)
|
||||
|
||||
class TestScorecardSummary(unittest.TestCase):
|
||||
def test_scorecard_summary_to_dict(self):
|
||||
metrics = AgentMetrics(
|
||||
agent_id="test_agent",
|
||||
issues_touched={1, 2},
|
||||
prs_opened={3, 4},
|
||||
prs_merged={3},
|
||||
tests_affected={"test1.py", "test2.py"},
|
||||
tokens_earned=100,
|
||||
tokens_spent=50,
|
||||
commits=10,
|
||||
comments=5,
|
||||
)
|
||||
summary = ScorecardSummary(
|
||||
agent_id="test_agent",
|
||||
period_type=PeriodType.daily,
|
||||
period_start=datetime(2024, 1, 1, tzinfo=UTC),
|
||||
period_end=datetime(2024, 1, 2, tzinfo=UTC),
|
||||
metrics=metrics,
|
||||
narrative_bullets=["test bullet"],
|
||||
patterns=["test pattern"],
|
||||
)
|
||||
expected_dict = {
|
||||
"agent_id": "test_agent",
|
||||
"period_type": "daily",
|
||||
"period_start": "2024-01-01T00:00:00+00:00",
|
||||
"period_end": "2024-01-02T00:00:00+00:00",
|
||||
"metrics": {
|
||||
"issues_touched": 2,
|
||||
"prs_opened": 2,
|
||||
"prs_merged": 1,
|
||||
"pr_merge_rate": 0.5,
|
||||
"tests_affected": 2,
|
||||
"commits": 10,
|
||||
"comments": 5,
|
||||
"tokens_earned": 100,
|
||||
"tokens_spent": 50,
|
||||
"token_net": 50,
|
||||
},
|
||||
"narrative_bullets": ["test bullet"],
|
||||
"patterns": ["test pattern"],
|
||||
}
|
||||
self.assertEqual(summary.to_dict(), expected_dict)
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user