Files
orion/tests/integration/api/v1/admin/test_email_settings.py
Samir Boulahtit d7a0ff8818 refactor: complete module-driven architecture migration
This commit completes the migration to a fully module-driven architecture:

## Models Migration
- Moved all domain models from models/database/ to their respective modules:
  - tenancy: User, Admin, Vendor, Company, Platform, VendorDomain, etc.
  - cms: MediaFile, VendorTheme
  - messaging: Email, VendorEmailSettings, VendorEmailTemplate
  - core: AdminMenuConfig
- models/database/ now only contains Base and TimestampMixin (infrastructure)

## Schemas Migration
- Moved all domain schemas from models/schema/ to their respective modules:
  - tenancy: company, vendor, admin, team, vendor_domain
  - cms: media, image, vendor_theme
  - messaging: email
- models/schema/ now only contains base.py and auth.py (infrastructure)

## Routes Migration
- Moved admin routes from app/api/v1/admin/ to modules:
  - menu_config.py -> core module
  - modules.py -> tenancy module
  - module_config.py -> tenancy module
- app/api/v1/admin/ now only aggregates auto-discovered module routes

## Menu System
- Implemented module-driven menu system with MenuDiscoveryService
- Extended FrontendType enum: PLATFORM, ADMIN, VENDOR, STOREFRONT
- Added MenuItemDefinition and MenuSectionDefinition dataclasses
- Each module now defines its own menu items in definition.py
- MenuService integrates with MenuDiscoveryService for template rendering

## Documentation
- Updated docs/architecture/models-structure.md
- Updated docs/architecture/menu-management.md
- Updated architecture validation rules for new exceptions

## Architecture Validation
- Updated MOD-019 rule to allow base.py in models/schema/
- Created core module exceptions.py and schemas/ directory
- All validation errors resolved (only warnings remain)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 21:02:56 +01:00

291 lines
9.5 KiB
Python

# tests/integration/api/v1/admin/test_email_settings.py
"""Integration tests for admin email settings API."""
import pytest
from app.modules.tenancy.models import AdminSetting
# =============================================================================
# GET EMAIL STATUS TESTS
# =============================================================================
@pytest.mark.integration
@pytest.mark.email
class TestGetAdminEmailStatus:
"""Test suite for GET /admin/settings/email/status endpoint."""
def test_get_status_unauthenticated(self, client):
"""Test getting status without auth fails."""
response = client.get("/api/v1/admin/settings/email/status")
assert response.status_code == 401
def test_get_status_non_admin(self, client, auth_headers):
"""Test getting status as non-admin fails."""
response = client.get(
"/api/v1/admin/settings/email/status",
headers=auth_headers,
)
assert response.status_code == 403
def test_get_status_admin(self, client, admin_headers):
"""Test getting status as admin succeeds."""
response = client.get(
"/api/v1/admin/settings/email/status",
headers=admin_headers,
)
assert response.status_code == 200
data = response.json()
assert "provider" in data
assert "from_email" in data
assert "enabled" in data
assert "is_configured" in data
def test_get_status_has_db_overrides_flag(self, client, admin_headers):
"""Test status includes has_db_overrides flag."""
response = client.get(
"/api/v1/admin/settings/email/status",
headers=admin_headers,
)
assert response.status_code == 200
data = response.json()
assert "has_db_overrides" in data
# Initially should be False (no DB settings)
assert data["has_db_overrides"] is False
# =============================================================================
# UPDATE EMAIL SETTINGS TESTS
# =============================================================================
@pytest.mark.integration
@pytest.mark.email
class TestUpdateAdminEmailSettings:
"""Test suite for PUT /admin/settings/email/settings endpoint."""
def test_update_unauthenticated(self, client):
"""Test updating settings without auth fails."""
response = client.put(
"/api/v1/admin/settings/email/settings",
json={"from_email": "test@example.com"},
)
assert response.status_code == 401
def test_update_non_admin(self, client, auth_headers):
"""Test updating settings as non-admin fails."""
response = client.put(
"/api/v1/admin/settings/email/settings",
headers=auth_headers,
json={"from_email": "test@example.com"},
)
assert response.status_code == 403
def test_update_settings_admin(self, client, admin_headers, db):
"""Test updating settings as admin succeeds."""
response = client.put(
"/api/v1/admin/settings/email/settings",
headers=admin_headers,
json={
"from_email": "platform@example.com",
"from_name": "Test Platform",
"provider": "smtp",
"smtp_host": "smtp.test.com",
"smtp_port": 587,
},
)
assert response.status_code == 200
data = response.json()
assert data["success"] is True
assert "updated_keys" in data
assert "from_email" in data["updated_keys"]
# Verify settings were stored in DB
setting = (
db.query(AdminSetting)
.filter(AdminSetting.key == "email_from_address")
.first()
)
assert setting is not None
assert setting.value == "platform@example.com"
def test_update_partial_settings(self, client, admin_headers):
"""Test updating only some settings."""
response = client.put(
"/api/v1/admin/settings/email/settings",
headers=admin_headers,
json={
"enabled": False,
"debug": True,
},
)
assert response.status_code == 200
data = response.json()
assert data["success"] is True
assert "enabled" in data["updated_keys"]
assert "debug" in data["updated_keys"]
def test_status_shows_db_overrides(self, client, admin_headers):
"""Test that status shows DB overrides after update."""
# First, set a DB override
client.put(
"/api/v1/admin/settings/email/settings",
headers=admin_headers,
json={"from_email": "override@example.com"},
)
# Check status
response = client.get(
"/api/v1/admin/settings/email/status",
headers=admin_headers,
)
assert response.status_code == 200
data = response.json()
assert data["has_db_overrides"] is True
assert data["from_email"] == "override@example.com"
# =============================================================================
# RESET EMAIL SETTINGS TESTS
# =============================================================================
@pytest.mark.integration
@pytest.mark.email
class TestResetAdminEmailSettings:
"""Test suite for DELETE /admin/settings/email/settings endpoint."""
def test_reset_unauthenticated(self, client):
"""Test resetting settings without auth fails."""
response = client.delete("/api/v1/admin/settings/email/settings")
assert response.status_code == 401
def test_reset_non_admin(self, client, auth_headers):
"""Test resetting settings as non-admin fails."""
response = client.delete(
"/api/v1/admin/settings/email/settings",
headers=auth_headers,
)
assert response.status_code == 403
def test_reset_settings_admin(self, client, admin_headers, db):
"""Test resetting settings as admin."""
# First, create some DB overrides
client.put(
"/api/v1/admin/settings/email/settings",
headers=admin_headers,
json={
"from_email": "tobereset@example.com",
"provider": "sendgrid",
},
)
# Verify they exist
setting = (
db.query(AdminSetting)
.filter(AdminSetting.key == "email_from_address")
.first()
)
assert setting is not None
# Reset
response = client.delete(
"/api/v1/admin/settings/email/settings",
headers=admin_headers,
)
assert response.status_code == 200
data = response.json()
assert data["success"] is True
# Verify they're gone
db.expire_all()
setting = (
db.query(AdminSetting)
.filter(AdminSetting.key == "email_from_address")
.first()
)
assert setting is None
def test_status_after_reset(self, client, admin_headers):
"""Test status after reset shows no DB overrides."""
# Set an override
client.put(
"/api/v1/admin/settings/email/settings",
headers=admin_headers,
json={"from_email": "override@example.com"},
)
# Reset
client.delete(
"/api/v1/admin/settings/email/settings",
headers=admin_headers,
)
# Check status
response = client.get(
"/api/v1/admin/settings/email/status",
headers=admin_headers,
)
assert response.status_code == 200
data = response.json()
assert data["has_db_overrides"] is False
# =============================================================================
# TEST EMAIL TESTS
# =============================================================================
@pytest.mark.integration
@pytest.mark.email
class TestSendAdminTestEmail:
"""Test suite for POST /admin/settings/email/test endpoint."""
def test_send_test_unauthenticated(self, client):
"""Test sending test email without auth fails."""
response = client.post(
"/api/v1/admin/settings/email/test",
json={"to_email": "test@example.com"},
)
assert response.status_code == 401
def test_send_test_non_admin(self, client, auth_headers):
"""Test sending test email as non-admin fails."""
response = client.post(
"/api/v1/admin/settings/email/test",
headers=auth_headers,
json={"to_email": "test@example.com"},
)
assert response.status_code == 403
def test_send_test_invalid_email(self, client, admin_headers):
"""Test sending to invalid email format fails."""
response = client.post(
"/api/v1/admin/settings/email/test",
headers=admin_headers,
json={"to_email": "not-an-email"},
)
assert response.status_code == 422 # Validation error
def test_send_test_admin(self, client, admin_headers):
"""Test sending test email as admin."""
response = client.post(
"/api/v1/admin/settings/email/test",
headers=admin_headers,
json={"to_email": "test@example.com"},
)
# May fail if email not configured, but should not be 401/403
assert response.status_code in (200, 500)
data = response.json()
assert "success" in data
assert "message" in data