Files
Project_Velocity/backend/tests/test_catalyst_routes.py

160 lines
5.3 KiB
Python

from __future__ import annotations
import os
os.environ.setdefault("VELOCITY_JWT_SECRET", "test-secret")
from fastapi import FastAPI
from fastapi.testclient import TestClient
from backend.api.routes_catalyst import router
from backend.auth.dependencies import UserPrincipal, get_current_user
from backend.services.ad_network_service import BidAction, Platform
def _build_client() -> TestClient:
app = FastAPI()
async def _broadcast_live_event(*_args, **_kwargs):
return None
app.state.broadcast_live_event = _broadcast_live_event
app.include_router(router, prefix="/api/catalyst")
return TestClient(app)
def _build_authed_client() -> TestClient:
app = FastAPI()
app.state.db_pool = object()
app.dependency_overrides[get_current_user] = lambda: UserPrincipal(
user_id="sayan",
role="ADMIN",
tenant_id="tenant-root",
)
app.include_router(router, prefix="/api/catalyst")
return TestClient(app)
def test_catalyst_campaigns_and_google_budget_routes(monkeypatch) -> None:
client = _build_client()
async def fake_list_campaigns(platform=None):
return [
type(
"Campaign",
(),
{
"id": "google-camp-001",
"name": "Search Investors",
"platform": Platform.GOOGLE,
"status": type("Status", (), {"value": "active"})(),
"daily_budget": 5000,
"spent": 0,
"objective": "SEARCH",
"bid_strategy": "TARGET_ROAS",
},
)()
]
async def fake_get_insights(**_kwargs):
return [
{
"campaign_id": "google-camp-001",
"spend": 2400,
"impressions": 120000,
"clicks": 4200,
"conversions": 38,
}
]
async def fake_update_budget(_payload):
return {"status": "ok", "platform": "google", "mode": "simulated"}
async def fake_update_bid_strategy(_payload):
return BidAction(
action_id="act-1",
campaign_id="google-camp-001",
platform=Platform.GOOGLE,
old_strategy="TARGET_CPA",
new_strategy="TARGET_ROAS",
target_value=8.5,
executed_at="2026-04-12T00:00:00Z",
)
monkeypatch.setattr("backend.api.routes_catalyst.ad_network_service.list_campaigns", fake_list_campaigns)
monkeypatch.setattr("backend.api.routes_catalyst.ad_network_service.get_insights", fake_get_insights)
monkeypatch.setattr("backend.api.routes_catalyst.ad_network_service.update_budget", fake_update_budget)
monkeypatch.setattr("backend.api.routes_catalyst.ad_network_service.update_bid_strategy", fake_update_bid_strategy)
campaigns = client.get("/api/catalyst/campaigns")
assert campaigns.status_code == 200
assert campaigns.json()["data"][0]["platform"] == "google"
assert campaigns.json()["data"][0]["conversions"] == 38
budget = client.put(
"/api/catalyst/budget",
json={"campaign_id": "google-camp-001", "platform": "google", "daily_budget": 6500},
)
assert budget.status_code == 200
assert budget.json()["data"]["platform"] == "google"
bid = client.put(
"/api/catalyst/bid-strategy",
json={
"campaign_id": "google-camp-001",
"platform": "google",
"strategy": "TARGET_ROAS",
"target_value": 8.5,
},
)
assert bid.status_code == 200
assert bid.json()["data"]["new_strategy"] == "TARGET_ROAS"
def test_catalyst_social_publish_route_is_tenant_scoped(monkeypatch) -> None:
async def fake_publish_content(*, pool, tenant_id, actor_id, payload):
assert pool is not None
assert tenant_id == "tenant-root"
assert actor_id == "sayan"
assert payload.platforms[0].value == "facebook"
return {
"request_id": "req-1",
"total": 1,
"published": 1,
"scheduled": 0,
"failed": 0,
"posts": [{"post_id": "post-1", "platform": "facebook", "status": "published"}],
}
monkeypatch.setattr("backend.api.routes_catalyst.publish_content", fake_publish_content)
response = _build_authed_client().post(
"/api/catalyst/publish",
json={
"platforms": ["facebook"],
"post_type": "image",
"caption": "New waterfront inventory is ready.",
"media_url": "https://assets.example.com/post.jpg",
},
)
assert response.status_code == 201
assert response.json()["data"]["published"] == 1
def test_catalyst_scheduled_posts_route_filters_scheduled_status(monkeypatch) -> None:
async def fake_list_posts(*, pool, tenant_id, platform=None, status=None, limit=50):
assert pool is not None
assert tenant_id == "tenant-root"
assert platform is None
assert status.value == "scheduled"
assert limit == 25
return [{"post_id": "post-2", "platform": "linkedin", "status": "scheduled"}]
monkeypatch.setattr("backend.api.routes_catalyst.list_posts", fake_list_posts)
response = _build_authed_client().get("/api/catalyst/scheduled?limit=25")
assert response.status_code == 200
assert response.json()["meta"]["count"] == 1