#!/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)