Migration v1 (Flask) -> v2 (FastAPI + Vue.js) complétée
✨ Changements majeurs: - Suppression complète du code Flask legacy - Migration backend FastAPI vers racine /backend - Migration frontend Vue.js vers racine /frontend - Suppression de notytex-v2/ (code monté à la racine) ✅ Validations: - Backend démarre correctement (port 8000) - API /api/v2/health répond healthy - 99/99 tests unitaires passent - Frontend configuré avec proxy Vite 📝 Documentation: - README.md réécrit pour v2 - Instructions de démarrage mises à jour - .gitignore adapté pour backend/frontend/ 🎯 Architecture finale: notytex/ ├── backend/ # FastAPI + SQLAlchemy + Pydantic ├── frontend/ # Vue 3 + Vite + TailwindCSS ├── docs/ # Documentation └── school_management.db # Base de données (inchangée) Jalon 6 complété: Application v2 prête pour utilisation!
This commit is contained in:
200
backend/tests/unit/test_email_service.py
Normal file
200
backend/tests/unit/test_email_service.py
Normal file
@@ -0,0 +1,200 @@
|
||||
"""
|
||||
Tests unitaires pour le service d'email.
|
||||
"""
|
||||
|
||||
import pytest
|
||||
from infrastructure.external.email_service import EmailService, SMTPConfig
|
||||
|
||||
|
||||
class TestSMTPConfig:
|
||||
"""Tests pour la configuration SMTP."""
|
||||
|
||||
def test_valid_localhost_config(self):
|
||||
"""Configuration locale valide sans authentification."""
|
||||
config = SMTPConfig(
|
||||
host="localhost",
|
||||
port=1025,
|
||||
username="",
|
||||
password="",
|
||||
use_tls=False,
|
||||
from_name="Test",
|
||||
from_address="test@example.com"
|
||||
)
|
||||
assert config.is_valid() is True
|
||||
|
||||
def test_valid_production_config(self):
|
||||
"""Configuration production valide avec authentification."""
|
||||
config = SMTPConfig(
|
||||
host="smtp.gmail.com",
|
||||
port=587,
|
||||
username="user@gmail.com",
|
||||
password="password123",
|
||||
use_tls=True,
|
||||
from_name="Notytex",
|
||||
from_address="notytex@school.com"
|
||||
)
|
||||
assert config.is_valid() is True
|
||||
|
||||
def test_invalid_config_missing_host(self):
|
||||
"""Configuration invalide sans host."""
|
||||
config = SMTPConfig(
|
||||
host="",
|
||||
port=587,
|
||||
username="user",
|
||||
password="pass",
|
||||
use_tls=True,
|
||||
from_name="Test",
|
||||
from_address="test@example.com"
|
||||
)
|
||||
assert config.is_valid() is False
|
||||
|
||||
def test_invalid_config_missing_from_address(self):
|
||||
"""Configuration invalide sans adresse expéditeur."""
|
||||
config = SMTPConfig(
|
||||
host="smtp.gmail.com",
|
||||
port=587,
|
||||
username="user",
|
||||
password="pass",
|
||||
use_tls=True,
|
||||
from_name="Test",
|
||||
from_address=""
|
||||
)
|
||||
assert config.is_valid() is False
|
||||
|
||||
def test_invalid_production_config_no_auth(self):
|
||||
"""Configuration production invalide sans authentification."""
|
||||
config = SMTPConfig(
|
||||
host="smtp.gmail.com",
|
||||
port=587,
|
||||
username="",
|
||||
password="",
|
||||
use_tls=True,
|
||||
from_name="Test",
|
||||
from_address="test@example.com"
|
||||
)
|
||||
assert config.is_valid() is False
|
||||
|
||||
|
||||
class TestEmailService:
|
||||
"""Tests pour le service d'email."""
|
||||
|
||||
def test_service_not_configured(self):
|
||||
"""Service non configuré."""
|
||||
service = EmailService()
|
||||
assert service.is_configured() is False
|
||||
|
||||
def test_service_with_config(self):
|
||||
"""Service avec configuration valide."""
|
||||
config = SMTPConfig(
|
||||
host="localhost",
|
||||
port=1025,
|
||||
username="",
|
||||
password="",
|
||||
use_tls=False,
|
||||
from_name="Test",
|
||||
from_address="test@example.com"
|
||||
)
|
||||
service = EmailService(config)
|
||||
assert service.is_configured() is True
|
||||
|
||||
def test_set_config(self):
|
||||
"""Définir la configuration après initialisation."""
|
||||
service = EmailService()
|
||||
assert service.is_configured() is False
|
||||
|
||||
config = SMTPConfig(
|
||||
host="localhost",
|
||||
port=1025,
|
||||
username="",
|
||||
password="",
|
||||
use_tls=False,
|
||||
from_name="Test",
|
||||
from_address="test@example.com"
|
||||
)
|
||||
service.set_config(config)
|
||||
assert service.is_configured() is True
|
||||
|
||||
def test_send_email_not_configured(self):
|
||||
"""Envoi d'email échoue si non configuré."""
|
||||
service = EmailService()
|
||||
result = service.send_email(
|
||||
to_emails=["test@example.com"],
|
||||
subject="Test",
|
||||
html_body="<p>Test</p>"
|
||||
)
|
||||
assert result['success'] is False
|
||||
assert 'incomplète' in result['error']
|
||||
|
||||
def test_from_database_config(self):
|
||||
"""Création du service depuis la configuration DB."""
|
||||
db_config = {
|
||||
'email.smtp_host': 'localhost',
|
||||
'email.smtp_port': '1025',
|
||||
'email.username': '',
|
||||
'email.password': '',
|
||||
'email.use_tls': 'false',
|
||||
'email.from_name': 'Notytex',
|
||||
'email.from_address': 'test@example.com'
|
||||
}
|
||||
|
||||
service = EmailService.from_database_config(db_config)
|
||||
assert service.is_configured() is True
|
||||
assert service.config.host == 'localhost'
|
||||
assert service.config.port == 1025
|
||||
assert service.config.from_name == 'Notytex'
|
||||
|
||||
def test_from_database_config_defaults(self):
|
||||
"""Valeurs par défaut pour la configuration DB."""
|
||||
db_config = {}
|
||||
|
||||
service = EmailService.from_database_config(db_config)
|
||||
assert service.config.port == 587
|
||||
assert service.config.use_tls is True
|
||||
assert service.config.from_name == 'Notytex'
|
||||
|
||||
|
||||
class TestEmailValidation:
|
||||
"""Tests pour la validation d'adresses email."""
|
||||
|
||||
def test_validate_valid_emails(self):
|
||||
"""Validation d'adresses valides."""
|
||||
emails = ["test@example.com", "user.name@domain.org", "a@b.co"]
|
||||
result = EmailService.validate_email_addresses(emails)
|
||||
|
||||
assert result['valid_count'] == 3
|
||||
assert result['invalid_count'] == 0
|
||||
assert len(result['valid']) == 3
|
||||
|
||||
def test_validate_invalid_emails(self):
|
||||
"""Validation d'adresses invalides."""
|
||||
emails = ["invalid", "no-at-sign", "@nodomain", "space @test.com"]
|
||||
result = EmailService.validate_email_addresses(emails)
|
||||
|
||||
assert result['valid_count'] == 0
|
||||
assert result['invalid_count'] == 4
|
||||
|
||||
def test_validate_mixed_emails(self):
|
||||
"""Validation d'un mélange d'adresses."""
|
||||
emails = ["valid@test.com", "invalid", "another@valid.org"]
|
||||
result = EmailService.validate_email_addresses(emails)
|
||||
|
||||
assert result['valid_count'] == 2
|
||||
assert result['invalid_count'] == 1
|
||||
assert "valid@test.com" in result['valid']
|
||||
assert "invalid" in result['invalid']
|
||||
|
||||
def test_validate_empty_emails(self):
|
||||
"""Validation d'une liste vide."""
|
||||
result = EmailService.validate_email_addresses([])
|
||||
|
||||
assert result['valid_count'] == 0
|
||||
assert result['invalid_count'] == 0
|
||||
|
||||
def test_validate_whitespace_emails(self):
|
||||
"""Les espaces sont supprimés lors de la validation."""
|
||||
emails = [" test@example.com ", " user@domain.org"]
|
||||
result = EmailService.validate_email_addresses(emails)
|
||||
|
||||
assert result['valid_count'] == 2
|
||||
assert "test@example.com" in result['valid']
|
||||
assert "user@domain.org" in result['valid']
|
||||
Reference in New Issue
Block a user