mirror of
http://88.130.71.182:3000/BlitTech/contexta_be.git
synced 2026-06-12 23:23:21 +00:00
feat: add appointments, campaigns, admin, storage, tests and various updates
- Add new routers: admin, appointments, campaigns - Add storage service and logging config - Add migrations directory and test suite with pytest config - Add supabase_migration_features.sql - Update models, dependencies, config, and existing routers - Remove whatsapp_service (deleted) - Update pyproject.toml and uv.lock dependencies Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
107
tests/test_models.py
Normal file
107
tests/test_models.py
Normal file
@@ -0,0 +1,107 @@
|
||||
"""Tests for models router — plan-based model availability."""
|
||||
import pytest
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
AUTH = {"Authorization": "Bearer test-token"}
|
||||
|
||||
|
||||
def _make_sb_with_plan(plan: str):
|
||||
sb = MagicMock()
|
||||
m = MagicMock()
|
||||
m.select.return_value = m
|
||||
m.eq.return_value = m
|
||||
m.execute.return_value = MagicMock(data=[{"plan": plan}])
|
||||
sb.table.return_value = m
|
||||
sb.auth = MagicMock()
|
||||
return sb
|
||||
|
||||
|
||||
class TestModelsAuth:
|
||||
def test_available_requires_auth(self, client):
|
||||
resp = client.get("/api/v1/models/available")
|
||||
assert resp.status_code == 401
|
||||
|
||||
|
||||
class TestModelsAvailable:
|
||||
@pytest.mark.parametrize("plan", ["free", "starter", "pro", "enterprise"])
|
||||
def test_returns_200_for_all_plans(self, client, plan):
|
||||
with patch("app.routers.models.get_supabase") as mock_sb:
|
||||
mock_sb.return_value = _make_sb_with_plan(plan)
|
||||
resp = client.get("/api/v1/models/available", headers=AUTH)
|
||||
assert resp.status_code == 200
|
||||
|
||||
def test_response_shape(self, client):
|
||||
with patch("app.routers.models.get_supabase") as mock_sb:
|
||||
mock_sb.return_value = _make_sb_with_plan("starter")
|
||||
resp = client.get("/api/v1/models/available", headers=AUTH)
|
||||
body = resp.json()
|
||||
assert "models" in body
|
||||
assert "plan" in body
|
||||
assert "has_premium_access" in body
|
||||
assert isinstance(body["models"], list)
|
||||
|
||||
def test_free_plan_has_no_premium_access(self, client):
|
||||
with patch("app.routers.models.get_supabase") as mock_sb:
|
||||
mock_sb.return_value = _make_sb_with_plan("free")
|
||||
resp = client.get("/api/v1/models/available", headers=AUTH)
|
||||
body = resp.json()
|
||||
assert body["has_premium_access"] is False
|
||||
assert body["upgrade_label"] is not None
|
||||
|
||||
def test_enterprise_has_premium_access(self, client):
|
||||
with patch("app.routers.models.get_supabase") as mock_sb:
|
||||
mock_sb.return_value = _make_sb_with_plan("enterprise")
|
||||
resp = client.get("/api/v1/models/available", headers=AUTH)
|
||||
body = resp.json()
|
||||
assert body["has_premium_access"] is True
|
||||
assert body["upgrade_label"] is None
|
||||
|
||||
def test_model_fields_present(self, client):
|
||||
with patch("app.routers.models.get_supabase") as mock_sb:
|
||||
mock_sb.return_value = _make_sb_with_plan("starter")
|
||||
resp = client.get("/api/v1/models/available", headers=AUTH)
|
||||
body = resp.json()
|
||||
if body["models"]:
|
||||
model = body["models"][0]
|
||||
assert "id" in model
|
||||
assert "name" in model
|
||||
assert "provider" in model
|
||||
assert "badge" in model
|
||||
assert "is_default" in model
|
||||
|
||||
def test_exactly_one_default_model_per_plan(self, client):
|
||||
for plan in ["starter", "pro"]:
|
||||
with patch("app.routers.models.get_supabase") as mock_sb:
|
||||
mock_sb.return_value = _make_sb_with_plan(plan)
|
||||
resp = client.get("/api/v1/models/available", headers=AUTH)
|
||||
body = resp.json()
|
||||
defaults = [m for m in body["models"] if m["is_default"]]
|
||||
assert len(defaults) <= 1, f"Plan {plan} has {len(defaults)} default models"
|
||||
|
||||
def test_starter_upgrade_label_mentions_business(self, client):
|
||||
with patch("app.routers.models.get_supabase") as mock_sb:
|
||||
mock_sb.return_value = _make_sb_with_plan("starter")
|
||||
resp = client.get("/api/v1/models/available", headers=AUTH)
|
||||
body = resp.json()
|
||||
assert body["upgrade_label"] is not None
|
||||
|
||||
def test_unknown_plan_falls_back_to_free(self, client):
|
||||
"""An unknown plan should fall back to free-tier behavior without crashing."""
|
||||
with patch("app.routers.models.get_supabase") as mock_sb:
|
||||
mock_sb.return_value = _make_sb_with_plan("banana")
|
||||
resp = client.get("/api/v1/models/available", headers=AUTH)
|
||||
assert resp.status_code == 200
|
||||
|
||||
def test_no_active_subscription_defaults_to_free(self, client):
|
||||
with patch("app.routers.models.get_supabase") as mock_sb:
|
||||
sb = MagicMock()
|
||||
m = MagicMock()
|
||||
m.select.return_value = m
|
||||
m.eq.return_value = m
|
||||
m.execute.return_value = MagicMock(data=[])
|
||||
sb.table.return_value = m
|
||||
sb.auth = MagicMock()
|
||||
mock_sb.return_value = sb
|
||||
resp = client.get("/api/v1/models/available", headers=AUTH)
|
||||
assert resp.status_code == 200
|
||||
assert resp.json()["plan"] == "free"
|
||||
Reference in New Issue
Block a user