- Frontend v4 accessible sur réseau local (192.168.1.40) - Ports ouverts: 3002 (frontend), 5001 (backend), 5004 (dashboard) - Ollama GPU fonctionnel - Self-healing interactif - Dashboard confiance Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
298 lines
9.9 KiB
Python
298 lines
9.9 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Test de fonctionnalité réelle pour l'authentification serveur avec variables d'environnement.
|
|
|
|
Ce test utilise les vraies implémentations:
|
|
- Chargement réel des variables d'environnement
|
|
- Serveur Flask réel avec authentification
|
|
- Vraies requêtes HTTP avec tokens
|
|
- Validation complète du pipeline d'authentification
|
|
"""
|
|
|
|
import os
|
|
import sys
|
|
import time
|
|
import subprocess
|
|
import requests
|
|
import socket
|
|
from pathlib import Path
|
|
from contextlib import contextmanager
|
|
|
|
# Ajouter le répertoire racine au path pour les imports
|
|
sys.path.insert(0, str(Path(__file__).parent))
|
|
|
|
def find_free_port():
|
|
"""Trouve un port libre pour le serveur de test."""
|
|
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
|
|
s.bind(('', 0))
|
|
s.listen(1)
|
|
port = s.getsockname()[1]
|
|
return port
|
|
|
|
def load_env_local():
|
|
"""Charge les variables d'environnement depuis .env.local"""
|
|
env_path = Path(".env.local")
|
|
if env_path.exists():
|
|
print(f"📁 Chargement de {env_path}")
|
|
with open(env_path, 'r') as f:
|
|
for line in f:
|
|
line = line.strip()
|
|
if line and not line.startswith('#') and '=' in line:
|
|
key, value = line.split('=', 1)
|
|
os.environ[key.strip()] = value.strip()
|
|
if key.strip() in ['RPA_TOKEN_ADMIN', 'RPA_TOKEN_READONLY']:
|
|
print(f" 🔑 {key.strip()}: {value.strip()[:16]}...")
|
|
return True
|
|
else:
|
|
print(f"⚠️ Fichier {env_path} non trouvé")
|
|
return False
|
|
|
|
def validate_environment():
|
|
"""Valide que l'environnement est correctement configuré."""
|
|
required_vars = ['RPA_TOKEN_ADMIN', 'RPA_TOKEN_READONLY']
|
|
missing_vars = []
|
|
|
|
for var in required_vars:
|
|
if not os.environ.get(var):
|
|
missing_vars.append(var)
|
|
|
|
if missing_vars:
|
|
print(f"❌ Variables manquantes: {', '.join(missing_vars)}")
|
|
return False
|
|
|
|
print("✅ Variables d'environnement validées")
|
|
return True
|
|
|
|
@contextmanager
|
|
def real_server_instance(port):
|
|
"""Context manager pour démarrer/arrêter un serveur réel."""
|
|
server_process = None
|
|
try:
|
|
# Configurer l'environnement pour le serveur
|
|
server_env = os.environ.copy()
|
|
server_env['FLASK_PORT'] = str(port)
|
|
server_env['FLASK_HOST'] = '127.0.0.1'
|
|
|
|
print(f"🚀 Démarrage serveur réel sur port {port}...")
|
|
|
|
# Démarrer le serveur avec les vraies implémentations
|
|
server_process = subprocess.Popen([
|
|
sys.executable, "server/api_upload.py"
|
|
],
|
|
env=server_env,
|
|
stdout=subprocess.PIPE,
|
|
stderr=subprocess.PIPE,
|
|
cwd=Path(__file__).parent
|
|
)
|
|
|
|
# Attendre que le serveur soit prêt avec vérification active
|
|
max_attempts = 20
|
|
for attempt in range(max_attempts):
|
|
try:
|
|
response = requests.get(f"http://127.0.0.1:{port}/health", timeout=1)
|
|
if response.status_code == 200:
|
|
print(f"✅ Serveur prêt après {attempt + 1} tentatives")
|
|
break
|
|
except requests.exceptions.RequestException:
|
|
pass
|
|
|
|
if attempt < max_attempts - 1:
|
|
time.sleep(0.5)
|
|
else:
|
|
# Vérifier les logs du serveur si échec
|
|
stdout, stderr = server_process.communicate(timeout=1)
|
|
print(f"❌ Serveur non prêt après {max_attempts} tentatives")
|
|
if stderr:
|
|
print(f"Erreurs serveur: {stderr.decode()}")
|
|
raise RuntimeError("Serveur non démarré")
|
|
|
|
yield port
|
|
|
|
finally:
|
|
if server_process:
|
|
print("🛑 Arrêt du serveur...")
|
|
server_process.terminate()
|
|
try:
|
|
server_process.wait(timeout=5)
|
|
except subprocess.TimeoutExpired:
|
|
server_process.kill()
|
|
server_process.wait()
|
|
|
|
def test_authentication_endpoints(port, token_admin, token_readonly):
|
|
"""Test les endpoints d'authentification avec de vrais tokens."""
|
|
base_url = f"http://127.0.0.1:{port}"
|
|
|
|
test_cases = [
|
|
{
|
|
"name": "Status avec token admin",
|
|
"url": f"{base_url}/api/traces/status",
|
|
"headers": {"Authorization": f"Bearer {token_admin}"},
|
|
"expected_status": 200,
|
|
"should_have_json": True
|
|
},
|
|
{
|
|
"name": "Status avec token readonly",
|
|
"url": f"{base_url}/api/traces/status",
|
|
"headers": {"Authorization": f"Bearer {token_readonly}"},
|
|
"expected_status": 200,
|
|
"should_have_json": True
|
|
},
|
|
{
|
|
"name": "Status sans token",
|
|
"url": f"{base_url}/api/traces/status",
|
|
"headers": {},
|
|
"expected_status": 401,
|
|
"should_have_json": False
|
|
},
|
|
{
|
|
"name": "Status avec token invalide",
|
|
"url": f"{base_url}/api/traces/status",
|
|
"headers": {"Authorization": "Bearer invalid_token_123"},
|
|
"expected_status": 401,
|
|
"should_have_json": False
|
|
}
|
|
]
|
|
|
|
results = []
|
|
|
|
for test_case in test_cases:
|
|
print(f"🧪 Test: {test_case['name']}")
|
|
|
|
try:
|
|
response = requests.get(
|
|
test_case['url'],
|
|
headers=test_case['headers'],
|
|
timeout=5
|
|
)
|
|
|
|
# Vérifier le status code
|
|
if response.status_code == test_case['expected_status']:
|
|
print(f" ✅ Status code correct: {response.status_code}")
|
|
|
|
# Vérifier le contenu JSON si attendu
|
|
if test_case['should_have_json']:
|
|
try:
|
|
json_data = response.json()
|
|
print(f" ✅ Réponse JSON valide: {json_data}")
|
|
except ValueError:
|
|
print(f" ❌ Réponse JSON invalide")
|
|
results.append(False)
|
|
continue
|
|
|
|
results.append(True)
|
|
else:
|
|
print(f" ❌ Status code incorrect: {response.status_code} (attendu: {test_case['expected_status']})")
|
|
print(f" 📄 Réponse: {response.text}")
|
|
results.append(False)
|
|
|
|
except Exception as e:
|
|
print(f" ❌ Erreur requête: {e}")
|
|
results.append(False)
|
|
|
|
return all(results)
|
|
|
|
def test_real_upload_functionality(port, token_admin):
|
|
"""Test la fonctionnalité d'upload réelle avec de vraies données."""
|
|
print("🧪 Test upload de session réelle...")
|
|
|
|
# Créer des données de test réalistes
|
|
test_session_data = {
|
|
"session_id": "test_session_real_functionality",
|
|
"user_id": "test_user",
|
|
"timestamp": "2025-01-05T10:00:00Z",
|
|
"events": [
|
|
{
|
|
"type": "mouse_click",
|
|
"timestamp": "2025-01-05T10:00:01Z",
|
|
"x": 100,
|
|
"y": 200,
|
|
"button": "left"
|
|
}
|
|
]
|
|
}
|
|
|
|
try:
|
|
response = requests.post(
|
|
f"http://127.0.0.1:{port}/api/traces/upload",
|
|
headers={
|
|
"Authorization": f"Bearer {token_admin}",
|
|
"Content-Type": "application/json"
|
|
},
|
|
json=test_session_data,
|
|
timeout=10
|
|
)
|
|
|
|
if response.status_code in [200, 201]:
|
|
print(" ✅ Upload réussi")
|
|
try:
|
|
result = response.json()
|
|
print(f" 📄 Réponse: {result}")
|
|
return True
|
|
except ValueError:
|
|
print(" ⚠️ Upload réussi mais réponse non-JSON")
|
|
return True
|
|
else:
|
|
print(f" ❌ Upload échoué: {response.status_code}")
|
|
print(f" 📄 Erreur: {response.text}")
|
|
return False
|
|
|
|
except Exception as e:
|
|
print(f" ❌ Erreur upload: {e}")
|
|
return False
|
|
|
|
def test_server_with_real_env():
|
|
"""Test principal avec fonctionnalités réelles."""
|
|
print("=" * 60)
|
|
print("🎯 Test de fonctionnalité réelle - Authentification serveur")
|
|
print("=" * 60)
|
|
|
|
# 1. Charger l'environnement réel
|
|
if not load_env_local():
|
|
print("❌ Impossible de charger .env.local")
|
|
return False
|
|
|
|
# 2. Valider l'environnement
|
|
if not validate_environment():
|
|
return False
|
|
|
|
# 3. Récupérer les tokens réels
|
|
token_admin = os.environ.get('RPA_TOKEN_ADMIN')
|
|
token_readonly = os.environ.get('RPA_TOKEN_READONLY')
|
|
|
|
print(f"🔑 Token admin: {token_admin[:16]}...")
|
|
print(f"🔑 Token readonly: {token_readonly[:16]}...")
|
|
|
|
# 4. Trouver un port libre
|
|
port = find_free_port()
|
|
print(f"🌐 Port sélectionné: {port}")
|
|
|
|
# 5. Démarrer serveur réel et tester
|
|
try:
|
|
with real_server_instance(port):
|
|
# Test authentification
|
|
auth_success = test_authentication_endpoints(port, token_admin, token_readonly)
|
|
|
|
# Test upload réel
|
|
upload_success = test_real_upload_functionality(port, token_admin)
|
|
|
|
return auth_success and upload_success
|
|
|
|
except Exception as e:
|
|
print(f"❌ Erreur serveur: {e}")
|
|
return False
|
|
|
|
if __name__ == "__main__":
|
|
success = test_server_with_real_env()
|
|
|
|
print("\n" + "=" * 60)
|
|
if success:
|
|
print("🎉 SUCCÈS - Tous les tests de fonctionnalité réelle passent!")
|
|
print("✅ Authentification serveur validée")
|
|
print("✅ Variables d'environnement correctes")
|
|
print("✅ Pipeline complet fonctionnel")
|
|
else:
|
|
print("💥 ÉCHEC - Certains tests ont échoué")
|
|
print("❌ Vérifiez la configuration et les logs ci-dessus")
|
|
|
|
print("=" * 60)
|
|
exit(0 if success else 1) |