Files
billo-release-agent/tests/api/test_dependencies.py
Yaojia Wang f5c2733cfb feat: initial commit — Billo Release Agent (LangGraph)
LangGraph-based release automation agent with:
- PR discovery (webhook + polling)
- AI code review via Claude Code CLI (subscription-based)
- Auto-create Jira tickets for PRs without ticket ID
- Jira ticket lifecycle management (code review -> staging -> done)
- CI/CD pipeline trigger, polling, and approval gates
- Slack interactive messages with approval buttons
- Per-repo semantic versioning
- PostgreSQL persistence (threads, staging, releases)
- FastAPI API (webhooks, approvals, status, manual triggers)
- Docker Compose deployment

1069 tests, 95%+ coverage.
2026-03-24 17:38:23 +01:00

150 lines
4.3 KiB
Python

"""Tests for API FastAPI dependencies. Written FIRST (TDD RED phase)."""
from unittest.mock import MagicMock
import pytest
from fastapi import FastAPI
from fastapi.testclient import TestClient
from release_agent.api.dependencies import (
get_db_pool,
get_graphs,
get_settings,
get_staging_store,
get_tool_clients,
)
# ---------------------------------------------------------------------------
# Helpers
# ---------------------------------------------------------------------------
def _make_app_with_state(**state_kwargs) -> FastAPI:
"""Return a minimal FastAPI app with app.state attributes set."""
app = FastAPI()
for key, value in state_kwargs.items():
setattr(app.state, key, value)
return app
# ---------------------------------------------------------------------------
# get_settings
# ---------------------------------------------------------------------------
class TestGetSettings:
def test_returns_settings_from_state(self) -> None:
mock_settings = MagicMock()
app = _make_app_with_state(settings=mock_settings)
with TestClient(app) as client:
# We test the dependency directly by simulating a request
request = MagicMock()
request.app = app
result = get_settings(request)
assert result is mock_settings
def test_raises_when_settings_missing(self) -> None:
app = FastAPI() # no state.settings
request = MagicMock()
request.app = app
with pytest.raises(AttributeError):
get_settings(request)
# ---------------------------------------------------------------------------
# get_graphs
# ---------------------------------------------------------------------------
class TestGetGraphs:
def test_returns_graphs_from_state(self) -> None:
mock_graphs = {"pr_completed": MagicMock(), "release": MagicMock()}
app = _make_app_with_state(graphs=mock_graphs)
request = MagicMock()
request.app = app
result = get_graphs(request)
assert result is mock_graphs
def test_raises_when_graphs_missing(self) -> None:
app = FastAPI()
request = MagicMock()
request.app = app
with pytest.raises(AttributeError):
get_graphs(request)
# ---------------------------------------------------------------------------
# get_tool_clients
# ---------------------------------------------------------------------------
class TestGetToolClients:
def test_returns_tool_clients_from_state(self) -> None:
mock_clients = MagicMock()
app = _make_app_with_state(tool_clients=mock_clients)
request = MagicMock()
request.app = app
result = get_tool_clients(request)
assert result is mock_clients
def test_raises_when_tool_clients_missing(self) -> None:
app = FastAPI()
request = MagicMock()
request.app = app
with pytest.raises(AttributeError):
get_tool_clients(request)
# ---------------------------------------------------------------------------
# get_staging_store
# ---------------------------------------------------------------------------
class TestGetStagingStore:
def test_returns_staging_store_from_state(self) -> None:
mock_store = MagicMock()
app = _make_app_with_state(staging_store=mock_store)
request = MagicMock()
request.app = app
result = get_staging_store(request)
assert result is mock_store
def test_raises_when_staging_store_missing(self) -> None:
app = FastAPI()
request = MagicMock()
request.app = app
with pytest.raises(AttributeError):
get_staging_store(request)
# ---------------------------------------------------------------------------
# get_db_pool
# ---------------------------------------------------------------------------
class TestGetDbPool:
def test_returns_db_pool_from_state(self) -> None:
mock_pool = MagicMock()
app = _make_app_with_state(db_pool=mock_pool)
request = MagicMock()
request.app = app
result = get_db_pool(request)
assert result is mock_pool
def test_raises_when_db_pool_missing(self) -> None:
app = FastAPI()
request = MagicMock()
request.app = app
with pytest.raises(AttributeError):
get_db_pool(request)