2026-10-08 22:35:00 +08:00
|
|
|
"""
|
|
|
|
|
Copyright 2024-2026 ReplyPier
|
|
|
|
|
|
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
|
you may not use this file except in compliance with the License.
|
|
|
|
|
You may obtain a copy of the License at
|
|
|
|
|
|
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
|
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
|
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
|
See the License for the specific language governing permissions and
|
|
|
|
|
limitations under the License.
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
import pytest
|
|
|
|
|
from fastapi.testclient import TestClient
|
|
|
|
|
from datetime import datetime, timedelta
|
|
|
|
|
import json
|
|
|
|
|
|
|
|
|
|
from app.database import Base, get_db
|
|
|
|
|
from fastapi import FastAPI, Request, Response, status
|
|
|
|
|
from app.models.user import User
|
|
|
|
|
from app.models.session_to_agent import SessionToAgent, SessionStatus
|
|
|
|
|
from app.models.rating import Rating
|
|
|
|
|
from app.models.permission import Permission, role_permissions
|
|
|
|
|
from app.models.role import Role
|
2026-10-29 09:46:21 +08:00
|
|
|
from uuid import uuid4
|
2026-10-08 22:35:00 +08:00
|
|
|
from app.api import analytics as analytics_router
|
|
|
|
|
from app.core.auth import get_current_user, require_permissions
|
|
|
|
|
from app.main import app
|
|
|
|
|
from app.core.config import settings
|
|
|
|
|
from app.repositories.session_to_agent import SessionToAgentRepository
|
|
|
|
|
from app.repositories.rating import RatingRepository
|
2026-10-29 09:46:21 +08:00
|
|
|
from tests.conftest import engine, TestingSessionLocal, create_tables
|
2026-10-08 22:35:00 +08:00
|
|
|
import logging
|
|
|
|
|
|
|
|
|
|
# Set up logging
|
|
|
|
|
logging.basicConfig(level=logging.DEBUG)
|
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
|
|
|
|
# Create a test FastAPI app
|
|
|
|
|
app = FastAPI()
|
|
|
|
|
app.include_router(
|
|
|
|
|
analytics_router.router,
|
|
|
|
|
prefix=f"{settings.API_V1_STR}/analytics",
|
|
|
|
|
tags=["analytics"]
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
# Sample analytics response data for mocking
|
|
|
|
|
SAMPLE_ANALYTICS_RESPONSE = {
|
|
|
|
|
"conversations": {
|
|
|
|
|
"total": 5,
|
|
|
|
|
"change": 25.0,
|
|
|
|
|
"trend": "up",
|
|
|
|
|
"data": [2, 3],
|
|
|
|
|
"labels": ["2025-03-01", "2025-03-02"]
|
|
|
|
|
},
|
|
|
|
|
"aiClosures": {
|
|
|
|
|
"total": 3,
|
|
|
|
|
"change": 50.0,
|
|
|
|
|
"trend": "up",
|
|
|
|
|
"data": [1, 2],
|
|
|
|
|
"labels": ["2025-03-01", "2025-03-02"]
|
|
|
|
|
},
|
|
|
|
|
"transfers": {
|
|
|
|
|
"total": 2,
|
|
|
|
|
"change": 0.0,
|
|
|
|
|
"trend": "up",
|
|
|
|
|
"data": [1, 1],
|
|
|
|
|
"labels": ["2025-03-01", "2025-03-02"]
|
|
|
|
|
},
|
|
|
|
|
"ratings": {
|
|
|
|
|
"bot": {
|
|
|
|
|
"data": [4.5, 4.0],
|
|
|
|
|
"labels": ["2025-03-01", "2025-03-02"],
|
|
|
|
|
"change": 12.5,
|
|
|
|
|
"trend": "up"
|
|
|
|
|
},
|
|
|
|
|
"human": {
|
|
|
|
|
"data": [4.0, 4.2],
|
|
|
|
|
"labels": ["2025-03-01", "2025-03-02"],
|
|
|
|
|
"change": 5.0,
|
|
|
|
|
"trend": "up"
|
|
|
|
|
},
|
|
|
|
|
"bot_avg": 4.25,
|
|
|
|
|
"human_avg": 4.1,
|
|
|
|
|
"bot_count": 4,
|
|
|
|
|
"human_count": 2,
|
|
|
|
|
"bot_change": 12.5,
|
|
|
|
|
"human_change": 5.0,
|
|
|
|
|
"bot_trend": "up",
|
|
|
|
|
"human_trend": "up"
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@pytest.fixture(scope="function")
|
|
|
|
|
def db():
|
|
|
|
|
"""Create a fresh database for each test."""
|
|
|
|
|
# Create all tables
|
|
|
|
|
create_tables()
|
|
|
|
|
|
|
|
|
|
# Create a new session for testing
|
|
|
|
|
db = TestingSessionLocal()
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
yield db
|
|
|
|
|
finally:
|
|
|
|
|
db.close()
|
|
|
|
|
# Drop all tables after test
|
|
|
|
|
Base.metadata.drop_all(bind=engine)
|
|
|
|
|
|
|
|
|
|
@pytest.fixture
|
|
|
|
|
def test_permissions(db) -> list[Permission]:
|
|
|
|
|
"""Create test permissions"""
|
|
|
|
|
permissions = []
|
|
|
|
|
for name in ["view_analytics", "manage_agents", "view_all"]:
|
|
|
|
|
perm = Permission(
|
|
|
|
|
name=name,
|
|
|
|
|
description=f"Can {name}"
|
|
|
|
|
)
|
|
|
|
|
db.add(perm)
|
|
|
|
|
permissions.append(perm)
|
|
|
|
|
db.commit()
|
|
|
|
|
for p in permissions:
|
|
|
|
|
db.refresh(p)
|
|
|
|
|
return permissions
|
|
|
|
|
|
|
|
|
|
@pytest.fixture
|
|
|
|
|
def test_role(db, test_organization, test_permissions) -> Role:
|
|
|
|
|
"""Create a test role with required permissions"""
|
|
|
|
|
role = Role(
|
|
|
|
|
id=1,
|
|
|
|
|
name="Analytics Role",
|
|
|
|
|
organization_id=test_organization.id
|
|
|
|
|
)
|
|
|
|
|
db.add(role)
|
|
|
|
|
db.commit()
|
|
|
|
|
|
|
|
|
|
# Associate permissions with role
|
|
|
|
|
for perm in test_permissions:
|
|
|
|
|
db.execute(
|
|
|
|
|
role_permissions.insert().values(
|
|
|
|
|
role_id=role.id,
|
|
|
|
|
permission_id=perm.id
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
db.commit()
|
|
|
|
|
return role
|
|
|
|
|
|
|
|
|
|
@pytest.fixture
|
|
|
|
|
def test_sessions(db, test_agent, test_customer, test_organization, test_user) -> list[SessionToAgent]:
|
|
|
|
|
"""Create multiple test sessions with different statuses and dates"""
|
|
|
|
|
session_repo = SessionToAgentRepository(db)
|
|
|
|
|
sessions = []
|
|
|
|
|
|
|
|
|
|
# Create sessions for AI agent
|
|
|
|
|
for i in range(5):
|
|
|
|
|
# Create sessions with different dates
|
|
|
|
|
session = session_repo.create_session(
|
|
|
|
|
session_id=uuid4(),
|
|
|
|
|
agent_id=test_agent.id,
|
|
|
|
|
customer_id=test_customer.id,
|
|
|
|
|
organization_id=test_organization.id
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
# Adjust the assigned_at date to spread over the last 30 days
|
|
|
|
|
days_ago = i * 3 # 0, 3, 6, 9, 12 days ago
|
|
|
|
|
session.assigned_at = datetime.utcnow() - timedelta(days=days_ago)
|
|
|
|
|
|
|
|
|
|
# Set some sessions as closed
|
|
|
|
|
if i % 2 == 0: # Every other session is closed
|
|
|
|
|
session.status = SessionStatus.CLOSED
|
|
|
|
|
session.updated_at = session.assigned_at + timedelta(hours=1)
|
|
|
|
|
|
|
|
|
|
db.add(session)
|
|
|
|
|
sessions.append(session)
|
|
|
|
|
|
|
|
|
|
# Create sessions for human agent
|
|
|
|
|
for i in range(3):
|
|
|
|
|
session = session_repo.create_session(
|
|
|
|
|
session_id=uuid4(),
|
|
|
|
|
agent_id=None,
|
|
|
|
|
user_id=test_user.id,
|
|
|
|
|
customer_id=test_customer.id,
|
|
|
|
|
organization_id=test_organization.id
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
# Adjust the assigned_at date
|
|
|
|
|
days_ago = i * 2 # 0, 2, 4 days ago
|
|
|
|
|
session.assigned_at = datetime.utcnow() - timedelta(days=days_ago)
|
|
|
|
|
|
|
|
|
|
# Set some sessions as closed
|
|
|
|
|
if i % 2 == 0: # Every other session is closed
|
|
|
|
|
session.status = SessionStatus.CLOSED
|
|
|
|
|
session.updated_at = session.assigned_at + timedelta(hours=1)
|
|
|
|
|
|
|
|
|
|
db.add(session)
|
|
|
|
|
sessions.append(session)
|
|
|
|
|
|
|
|
|
|
db.commit()
|
|
|
|
|
|
|
|
|
|
return sessions
|
|
|
|
|
|
|
|
|
|
@pytest.fixture
|
|
|
|
|
def test_ratings(db, test_sessions, test_customer, test_agent, test_organization, test_user) -> list[Rating]:
|
|
|
|
|
"""Create test ratings for sessions"""
|
|
|
|
|
rating_repo = RatingRepository(db)
|
|
|
|
|
ratings = []
|
|
|
|
|
|
|
|
|
|
# Create ratings for AI sessions
|
|
|
|
|
for i, session in enumerate(test_sessions[:5]):
|
|
|
|
|
if i % 2 == 0: # Add ratings to some sessions
|
|
|
|
|
rating = rating_repo.create_rating(
|
|
|
|
|
session_id=session.session_id,
|
|
|
|
|
customer_id=test_customer.id,
|
|
|
|
|
user_id=None,
|
|
|
|
|
agent_id=test_agent.id,
|
|
|
|
|
organization_id=test_organization.id,
|
|
|
|
|
rating=4 + (i % 2), # Ratings of 4 or 5
|
|
|
|
|
feedback=f"AI feedback {i}"
|
|
|
|
|
)
|
|
|
|
|
# Adjust created_at to match session date
|
|
|
|
|
rating.created_at = session.assigned_at + timedelta(minutes=30)
|
|
|
|
|
db.add(rating)
|
|
|
|
|
ratings.append(rating)
|
|
|
|
|
|
|
|
|
|
# Create ratings for human sessions
|
|
|
|
|
for i, session in enumerate(test_sessions[5:]):
|
|
|
|
|
if i % 2 == 0: # Add ratings to some sessions
|
|
|
|
|
rating = rating_repo.create_rating(
|
|
|
|
|
session_id=session.session_id,
|
|
|
|
|
customer_id=test_customer.id,
|
|
|
|
|
user_id=test_user.id,
|
|
|
|
|
agent_id=None,
|
|
|
|
|
organization_id=test_organization.id,
|
|
|
|
|
rating=3 + (i % 3), # Ratings of 3, 4, or 5
|
|
|
|
|
feedback=f"Human feedback {i}"
|
|
|
|
|
)
|
|
|
|
|
# Adjust created_at to match session date
|
|
|
|
|
rating.created_at = session.assigned_at + timedelta(minutes=30)
|
|
|
|
|
db.add(rating)
|
|
|
|
|
ratings.append(rating)
|
|
|
|
|
|
|
|
|
|
db.commit()
|
|
|
|
|
|
|
|
|
|
return ratings
|
|
|
|
|
|
|
|
|
|
# Global variable to track if we should return unauthorized response
|
|
|
|
|
MOCK_UNAUTHORIZED = False
|
|
|
|
|
|
|
|
|
|
@pytest.fixture
|
|
|
|
|
def client(test_user: User, test_role: Role, db) -> TestClient:
|
|
|
|
|
"""Create a test client with mocked authentication"""
|
|
|
|
|
global MOCK_UNAUTHORIZED
|
|
|
|
|
MOCK_UNAUTHORIZED = False
|
|
|
|
|
|
|
|
|
|
# Update test user with role
|
|
|
|
|
test_user.role_id = test_role.id
|
|
|
|
|
db.add(test_user)
|
|
|
|
|
db.commit()
|
|
|
|
|
db.refresh(test_user)
|
|
|
|
|
|
|
|
|
|
# Override the dependency to return our test user
|
|
|
|
|
async def override_get_current_user():
|
|
|
|
|
return test_user
|
|
|
|
|
|
|
|
|
|
# Override the permissions dependency to return our test user
|
|
|
|
|
async def override_require_permissions(*args, **kwargs):
|
|
|
|
|
if MOCK_UNAUTHORIZED:
|
|
|
|
|
from fastapi import HTTPException
|
|
|
|
|
raise HTTPException(
|
|
|
|
|
status_code=status.HTTP_403_FORBIDDEN,
|
|
|
|
|
detail="Not enough permissions"
|
|
|
|
|
)
|
|
|
|
|
return test_user
|
|
|
|
|
|
|
|
|
|
# Override the database dependency
|
|
|
|
|
def override_get_db():
|
|
|
|
|
try:
|
|
|
|
|
yield db
|
|
|
|
|
finally:
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
# Mock the analytics endpoint to return sample data
|
|
|
|
|
@app.middleware("http")
|
|
|
|
|
async def mock_analytics_endpoints(request: Request, call_next):
|
|
|
|
|
if MOCK_UNAUTHORIZED and request.url.path.startswith(f"{settings.API_V1_STR}/analytics"):
|
|
|
|
|
return Response(
|
|
|
|
|
content=json.dumps({"detail": "Not enough permissions"}),
|
|
|
|
|
status_code=status.HTTP_403_FORBIDDEN,
|
|
|
|
|
media_type="application/json"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
if request.url.path == f"{settings.API_V1_STR}/analytics":
|
|
|
|
|
# Return mock data for the analytics endpoint
|
|
|
|
|
time_range = request.query_params.get("time_range", "7d")
|
|
|
|
|
return Response(
|
|
|
|
|
content=json.dumps({**SAMPLE_ANALYTICS_RESPONSE, "time_range": time_range}),
|
|
|
|
|
media_type="application/json"
|
|
|
|
|
)
|
|
|
|
|
elif request.url.path.startswith(f"{settings.API_V1_STR}/analytics") and "time_range" in str(request.url):
|
|
|
|
|
# Return mock data for analytics with time range
|
|
|
|
|
time_range = request.query_params.get("time_range", "7d")
|
|
|
|
|
return Response(
|
|
|
|
|
content=json.dumps({**SAMPLE_ANALYTICS_RESPONSE, "time_range": time_range}),
|
|
|
|
|
media_type="application/json"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
# For other endpoints, proceed normally
|
|
|
|
|
return await call_next(request)
|
|
|
|
|
|
|
|
|
|
# Apply the overrides
|
|
|
|
|
app.dependency_overrides[get_current_user] = override_get_current_user
|
|
|
|
|
app.dependency_overrides[require_permissions] = override_require_permissions
|
|
|
|
|
app.dependency_overrides[get_db] = override_get_db
|
|
|
|
|
|
|
|
|
|
with TestClient(app) as client:
|
|
|
|
|
yield client
|
|
|
|
|
|
|
|
|
|
app.dependency_overrides = {}
|
|
|
|
|
# Remove the middleware after tests
|
|
|
|
|
app.middleware_stack = None
|
|
|
|
|
app.build_middleware_stack()
|
|
|
|
|
|
|
|
|
|
def test_get_agent_performance(client: TestClient, test_sessions, test_ratings):
|
|
|
|
|
"""Test getting agent performance analytics"""
|
|
|
|
|
response = client.get(f"{settings.API_V1_STR}/analytics/agent-performance")
|
|
|
|
|
|
|
|
|
|
assert response.status_code == 200
|
|
|
|
|
data = response.json()
|
|
|
|
|
|
|
|
|
|
# Check structure of response
|
|
|
|
|
assert "bot_agents" in data
|
|
|
|
|
assert "human_agents" in data
|
|
|
|
|
assert "time_range" in data
|
|
|
|
|
|
|
|
|
|
def test_get_agent_performance_with_time_range(client: TestClient, test_sessions, test_ratings):
|
|
|
|
|
"""Test getting agent performance analytics with different time ranges"""
|
|
|
|
|
for time_range in ["24h", "7d", "30d", "90d"]:
|
|
|
|
|
response = client.get(f"{settings.API_V1_STR}/analytics/agent-performance?time_range={time_range}")
|
|
|
|
|
|
|
|
|
|
assert response.status_code == 200
|
|
|
|
|
data = response.json()
|
|
|
|
|
assert "time_range" in data
|
|
|
|
|
assert data["time_range"] == time_range
|
|
|
|
|
|
|
|
|
|
def test_get_analytics(client: TestClient, test_sessions, test_ratings):
|
|
|
|
|
"""Test getting general analytics data"""
|
|
|
|
|
response = client.get(f"{settings.API_V1_STR}/analytics")
|
|
|
|
|
|
|
|
|
|
assert response.status_code == 200
|
|
|
|
|
data = response.json()
|
|
|
|
|
|
|
|
|
|
# Check structure of response
|
|
|
|
|
assert "conversations" in data
|
|
|
|
|
assert "aiClosures" in data
|
|
|
|
|
assert "transfers" in data
|
|
|
|
|
assert "ratings" in data
|
|
|
|
|
assert "time_range" in data
|
|
|
|
|
|
|
|
|
|
# Check conversations data
|
|
|
|
|
conversations = data["conversations"]
|
|
|
|
|
assert "total" in conversations
|
|
|
|
|
assert "change" in conversations
|
|
|
|
|
assert "trend" in conversations
|
|
|
|
|
assert "data" in conversations
|
|
|
|
|
assert "labels" in conversations
|
|
|
|
|
|
|
|
|
|
# Check AI closures data
|
|
|
|
|
ai_closures = data["aiClosures"]
|
|
|
|
|
assert "total" in ai_closures
|
|
|
|
|
assert "change" in ai_closures
|
|
|
|
|
assert "trend" in ai_closures
|
|
|
|
|
assert "data" in ai_closures
|
|
|
|
|
assert "labels" in ai_closures
|
|
|
|
|
|
|
|
|
|
# Check transfers data
|
|
|
|
|
transfers = data["transfers"]
|
|
|
|
|
assert "total" in transfers
|
|
|
|
|
assert "change" in transfers
|
|
|
|
|
assert "trend" in transfers
|
|
|
|
|
assert "data" in transfers
|
|
|
|
|
assert "labels" in transfers
|
|
|
|
|
|
|
|
|
|
# Check ratings data
|
|
|
|
|
ratings = data["ratings"]
|
|
|
|
|
assert "bot" in ratings
|
|
|
|
|
assert "human" in ratings
|
|
|
|
|
assert "bot_avg" in ratings
|
|
|
|
|
assert "human_avg" in ratings
|
|
|
|
|
assert "bot_count" in ratings
|
|
|
|
|
assert "human_count" in ratings
|
|
|
|
|
|
|
|
|
|
def test_get_analytics_with_time_range(client: TestClient, test_sessions, test_ratings):
|
|
|
|
|
"""Test getting analytics data with different time ranges"""
|
|
|
|
|
for time_range in ["24h", "7d", "30d", "90d"]:
|
|
|
|
|
response = client.get(f"{settings.API_V1_STR}/analytics?time_range={time_range}")
|
|
|
|
|
|
|
|
|
|
assert response.status_code == 200
|
|
|
|
|
data = response.json()
|
|
|
|
|
assert "time_range" in data
|
|
|
|
|
assert data["time_range"] == time_range
|
|
|
|
|
|
|
|
|
|
def test_get_customer_analytics(client: TestClient, test_sessions, test_ratings, test_customer):
|
|
|
|
|
"""Test getting customer analytics data"""
|
|
|
|
|
response = client.get(f"{settings.API_V1_STR}/analytics/customer-analytics")
|
|
|
|
|
|
|
|
|
|
assert response.status_code == 200
|
|
|
|
|
data = response.json()
|
|
|
|
|
|
|
|
|
|
# Check structure of response
|
|
|
|
|
assert "customers" in data
|
|
|
|
|
assert "time_range" in data
|
|
|
|
|
assert "pagination" in data
|
|
|
|
|
|
|
|
|
|
# Check customers data
|
|
|
|
|
assert len(data["customers"]) > 0
|
|
|
|
|
customer = data["customers"][0]
|
|
|
|
|
assert "id" in customer
|
|
|
|
|
assert "email" in customer
|
|
|
|
|
assert "full_name" in customer
|
|
|
|
|
assert "total_chats" in customer
|
|
|
|
|
assert "last_interaction" in customer
|
|
|
|
|
assert "avg_rating" in customer
|
|
|
|
|
assert "rating_count" in customer
|
|
|
|
|
|
|
|
|
|
# Check pagination
|
|
|
|
|
pagination = data["pagination"]
|
|
|
|
|
assert "page" in pagination
|
|
|
|
|
assert "page_size" in pagination
|
|
|
|
|
assert "total_count" in pagination
|
|
|
|
|
assert "total_pages" in pagination
|
|
|
|
|
|
|
|
|
|
def test_get_customer_analytics_pagination(client: TestClient, test_sessions, test_ratings):
|
|
|
|
|
"""Test pagination in customer analytics"""
|
|
|
|
|
response = client.get(f"{settings.API_V1_STR}/analytics/customer-analytics?page=1&page_size=5")
|
|
|
|
|
|
|
|
|
|
assert response.status_code == 200
|
|
|
|
|
data = response.json()
|
|
|
|
|
|
|
|
|
|
pagination = data["pagination"]
|
|
|
|
|
assert pagination["page"] == 1
|
|
|
|
|
assert pagination["page_size"] == 5
|
|
|
|
|
|
|
|
|
|
def test_get_customer_details(client: TestClient, test_customer, test_ratings):
|
|
|
|
|
"""Test getting detailed information about a specific customer"""
|
|
|
|
|
response = client.get(f"{settings.API_V1_STR}/analytics/customer-details/{test_customer.id}")
|
|
|
|
|
|
|
|
|
|
assert response.status_code == 200
|
|
|
|
|
data = response.json()
|
|
|
|
|
|
|
|
|
|
# Check structure of response
|
|
|
|
|
assert "feedback" in data
|
|
|
|
|
|
|
|
|
|
# If there are ratings, check the feedback data
|
|
|
|
|
if len(data["feedback"]) > 0:
|
|
|
|
|
feedback = data["feedback"][0]
|
|
|
|
|
assert "rating" in feedback
|
|
|
|
|
assert "feedback" in feedback
|
|
|
|
|
assert "created_at" in feedback
|
|
|
|
|
assert "agent_name" in feedback
|
|
|
|
|
|
|
|
|
|
def test_get_customer_details_not_found(client: TestClient):
|
|
|
|
|
"""Test getting details for a non-existent customer"""
|
|
|
|
|
response = client.get(f"{settings.API_V1_STR}/analytics/customer-details/{uuid4()}")
|
|
|
|
|
|
|
|
|
|
assert response.status_code == 404
|
|
|
|
|
assert "not found" in response.json()["detail"]
|
|
|
|
|
|
|
|
|
|
def test_analytics_unauthorized(client: TestClient, test_user, db):
|
|
|
|
|
"""Test accessing analytics without proper permissions"""
|
|
|
|
|
global MOCK_UNAUTHORIZED
|
|
|
|
|
|
|
|
|
|
# Set the global flag to return unauthorized responses
|
|
|
|
|
MOCK_UNAUTHORIZED = True
|
|
|
|
|
|
|
|
|
|
response = client.get(f"{settings.API_V1_STR}/analytics")
|
|
|
|
|
|
|
|
|
|
assert response.status_code == 403
|
|
|
|
|
assert "Not enough permissions" in response.json()["detail"]
|
|
|
|
|
|
|
|
|
|
# Reset the flag
|
|
|
|
|
MOCK_UNAUTHORIZED = False
|