Files
rpa_vision_v3/test_server_with_env.py
Dom a27b74cf22 v1.0 - Version stable: multi-PC, détection UI-DETR-1, 3 modes exécution
- 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>
2026-01-29 11:23:51 +01:00

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)