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>
This commit is contained in:
@@ -0,0 +1,319 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Script de Validation Finale - Intégration Propriétés VWB
|
||||
Auteur : Dom, Alice, Kiro - 10 janvier 2026
|
||||
|
||||
Ce script valide l'intégration complète des propriétés d'étapes VWB
|
||||
dans le Visual Workflow Builder sans dépendances pytest.
|
||||
"""
|
||||
|
||||
import json
|
||||
import time
|
||||
import requests
|
||||
import subprocess
|
||||
import os
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from typing import Dict, Any, List, Optional
|
||||
|
||||
# Configuration des chemins
|
||||
PROJECT_ROOT = Path(__file__).parent.parent
|
||||
VWB_FRONTEND_PATH = PROJECT_ROOT / "visual_workflow_builder" / "frontend"
|
||||
VWB_BACKEND_PATH = PROJECT_ROOT / "visual_workflow_builder" / "backend"
|
||||
|
||||
class ValidationFinaleProprietesVWB:
|
||||
"""Validation finale de l'intégration des propriétés VWB"""
|
||||
|
||||
def __init__(self):
|
||||
self.backend_url = "http://localhost:5004"
|
||||
self.backend_process = None
|
||||
self.tests_passed = 0
|
||||
self.tests_failed = 0
|
||||
self.errors = []
|
||||
|
||||
def run_all_validations(self):
|
||||
"""Exécuter toutes les validations"""
|
||||
print("🚀 VALIDATION FINALE - INTÉGRATION PROPRIÉTÉS VWB")
|
||||
print("=" * 60)
|
||||
|
||||
try:
|
||||
# Étape 1: Vérifier l'environnement
|
||||
self.validate_environment()
|
||||
|
||||
# Étape 2: Démarrer le backend
|
||||
self.start_backend()
|
||||
|
||||
# Étape 3: Valider les fichiers frontend
|
||||
self.validate_frontend_files()
|
||||
|
||||
# Étape 4: Valider l'API backend
|
||||
self.validate_backend_api()
|
||||
|
||||
# Étape 5: Valider l'intégration complète
|
||||
self.validate_integration()
|
||||
|
||||
except Exception as e:
|
||||
self.log_error(f"Erreur critique: {e}")
|
||||
|
||||
finally:
|
||||
# Nettoyage
|
||||
self.cleanup()
|
||||
|
||||
# Rapport final
|
||||
self.print_final_report()
|
||||
|
||||
def validate_environment(self):
|
||||
"""Valider l'environnement de développement"""
|
||||
print("\n🔍 ÉTAPE 1: Validation de l'environnement")
|
||||
|
||||
# Vérifier l'environnement virtuel
|
||||
if "venv_v3" not in sys.executable:
|
||||
self.log_error("Environnement virtuel venv_v3 non activé")
|
||||
return
|
||||
|
||||
self.log_success("Environnement virtuel venv_v3 activé")
|
||||
|
||||
# Vérifier les dépendances Python
|
||||
try:
|
||||
import flask
|
||||
import requests
|
||||
self.log_success("Dépendances Python disponibles")
|
||||
except ImportError as e:
|
||||
self.log_error(f"Dépendances manquantes: {e}")
|
||||
|
||||
def start_backend(self):
|
||||
"""Démarrer le backend VWB"""
|
||||
print("\n🔍 ÉTAPE 2: Démarrage du backend VWB")
|
||||
|
||||
try:
|
||||
# Vérifier si le backend est déjà en cours d'exécution
|
||||
try:
|
||||
response = requests.get(f"{self.backend_url}/api/health", timeout=2)
|
||||
if response.status_code == 200:
|
||||
self.log_success("Backend VWB déjà en cours d'exécution")
|
||||
return
|
||||
except requests.exceptions.RequestException:
|
||||
pass
|
||||
|
||||
# Démarrer le backend
|
||||
script_path = PROJECT_ROOT / "scripts" / "start_vwb_backend_catalogue_complet_10jan2026.py"
|
||||
if script_path.exists():
|
||||
self.backend_process = subprocess.Popen([
|
||||
sys.executable, str(script_path)
|
||||
], cwd=str(PROJECT_ROOT))
|
||||
else:
|
||||
# Fallback
|
||||
self.backend_process = subprocess.Popen([
|
||||
sys.executable, "-m", "visual_workflow_builder.backend.app_catalogue_simple"
|
||||
], cwd=str(PROJECT_ROOT))
|
||||
|
||||
# Attendre que le backend soit prêt
|
||||
max_attempts = 30
|
||||
for attempt in range(max_attempts):
|
||||
try:
|
||||
response = requests.get(f"{self.backend_url}/api/health", timeout=2)
|
||||
if response.status_code == 200:
|
||||
self.log_success(f"Backend VWB démarré (PID: {self.backend_process.pid})")
|
||||
return
|
||||
except requests.exceptions.RequestException:
|
||||
pass
|
||||
|
||||
time.sleep(1)
|
||||
|
||||
self.log_error("Backend VWB non accessible après 30 secondes")
|
||||
|
||||
except Exception as e:
|
||||
self.log_error(f"Impossible de démarrer le backend VWB: {e}")
|
||||
|
||||
def validate_frontend_files(self):
|
||||
"""Valider les fichiers frontend"""
|
||||
print("\n🔍 ÉTAPE 3: Validation des fichiers frontend")
|
||||
|
||||
# Fichiers essentiels à vérifier
|
||||
essential_files = [
|
||||
# Types
|
||||
VWB_FRONTEND_PATH / "src" / "types" / "catalog.ts",
|
||||
VWB_FRONTEND_PATH / "src" / "types" / "index.ts",
|
||||
|
||||
# Services
|
||||
VWB_FRONTEND_PATH / "src" / "services" / "catalogService.ts",
|
||||
|
||||
# Hooks
|
||||
VWB_FRONTEND_PATH / "src" / "hooks" / "useVWBStepIntegration.ts",
|
||||
|
||||
# Composants
|
||||
VWB_FRONTEND_PATH / "src" / "components" / "PropertiesPanel" / "VWBActionProperties.tsx",
|
||||
VWB_FRONTEND_PATH / "src" / "components" / "PropertiesPanel" / "index.tsx",
|
||||
VWB_FRONTEND_PATH / "src" / "components" / "Canvas" / "StepNode.tsx",
|
||||
VWB_FRONTEND_PATH / "src" / "components" / "Palette" / "index.tsx",
|
||||
]
|
||||
|
||||
for file_path in essential_files:
|
||||
if file_path.exists():
|
||||
self.log_success(f"Fichier présent: {file_path.name}")
|
||||
else:
|
||||
self.log_error(f"Fichier manquant: {file_path}")
|
||||
|
||||
# Vérifier le contenu des fichiers clés
|
||||
self.validate_file_content()
|
||||
|
||||
def validate_file_content(self):
|
||||
"""Valider le contenu des fichiers clés"""
|
||||
print("\n🔍 Validation du contenu des fichiers")
|
||||
|
||||
# Vérifier catalog.ts
|
||||
catalog_types_file = VWB_FRONTEND_PATH / "src" / "types" / "catalog.ts"
|
||||
if catalog_types_file.exists():
|
||||
content = catalog_types_file.read_text()
|
||||
required_types = ["VWBCatalogAction", "VWBActionParameter", "VWBVisualAnchor"]
|
||||
|
||||
for type_name in required_types:
|
||||
if type_name in content:
|
||||
self.log_success(f"Type {type_name} présent")
|
||||
else:
|
||||
self.log_error(f"Type {type_name} manquant")
|
||||
|
||||
# Vérifier VWBActionProperties.tsx
|
||||
vwb_props_file = VWB_FRONTEND_PATH / "src" / "components" / "PropertiesPanel" / "VWBActionProperties.tsx"
|
||||
if vwb_props_file.exists():
|
||||
content = vwb_props_file.read_text()
|
||||
required_elements = ["VWBActionProperties", "VisualAnchorEditor", "onParameterChange"]
|
||||
|
||||
for element in required_elements:
|
||||
if element in content:
|
||||
self.log_success(f"Élément {element} présent dans VWBActionProperties")
|
||||
else:
|
||||
self.log_error(f"Élément {element} manquant dans VWBActionProperties")
|
||||
|
||||
# Vérifier l'intégration dans PropertiesPanel/index.tsx
|
||||
main_props_file = VWB_FRONTEND_PATH / "src" / "components" / "PropertiesPanel" / "index.tsx"
|
||||
if main_props_file.exists():
|
||||
content = main_props_file.read_text()
|
||||
integration_elements = ["import VWBActionProperties", "useVWBStepIntegration", "isVWBCatalogAction"]
|
||||
|
||||
for element in integration_elements:
|
||||
if element in content:
|
||||
self.log_success(f"Intégration {element} présente")
|
||||
else:
|
||||
self.log_error(f"Intégration {element} manquante")
|
||||
|
||||
def validate_backend_api(self):
|
||||
"""Valider l'API backend"""
|
||||
print("\n🔍 ÉTAPE 4: Validation de l'API backend")
|
||||
|
||||
try:
|
||||
# Test de l'endpoint catalogue
|
||||
response = requests.get(f"{self.backend_url}/api/vwb/catalog/actions", timeout=5)
|
||||
if response.status_code == 200:
|
||||
self.log_success("Endpoint catalogue accessible")
|
||||
|
||||
catalog_data = response.json()
|
||||
if "actions" in catalog_data:
|
||||
actions = catalog_data["actions"]
|
||||
self.log_success(f"Catalogue contient {len(actions)} actions")
|
||||
|
||||
# Vérifier les actions essentielles
|
||||
action_ids = [action["id"] for action in actions]
|
||||
required_actions = ["click_anchor", "type_text", "wait_for_anchor"]
|
||||
|
||||
for action_id in required_actions:
|
||||
if action_id in action_ids:
|
||||
self.log_success(f"Action {action_id} disponible")
|
||||
else:
|
||||
self.log_error(f"Action {action_id} manquante")
|
||||
else:
|
||||
self.log_error("Structure de catalogue invalide")
|
||||
else:
|
||||
self.log_error(f"Endpoint catalogue non accessible: {response.status_code}")
|
||||
|
||||
except requests.exceptions.RequestException as e:
|
||||
self.log_error(f"Erreur de connexion API: {e}")
|
||||
|
||||
def validate_integration(self):
|
||||
"""Valider l'intégration complète"""
|
||||
print("\n🔍 ÉTAPE 5: Validation de l'intégration complète")
|
||||
|
||||
try:
|
||||
# Test de validation d'action
|
||||
validation_request = {
|
||||
"type": "click_anchor",
|
||||
"parameters": {
|
||||
"visual_anchor": {
|
||||
"anchor_type": "screenshot",
|
||||
"screenshot_base64": "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8/5+hHgAHggJ/PchI7wAAAABJRU5ErkJggg==",
|
||||
"confidence_threshold": 0.8
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
response = requests.post(
|
||||
f"{self.backend_url}/api/vwb/catalog/validate",
|
||||
json=validation_request,
|
||||
timeout=5
|
||||
)
|
||||
|
||||
if response.status_code == 200:
|
||||
validation_result = response.json()
|
||||
if validation_result.get("is_valid"):
|
||||
self.log_success("Validation d'action fonctionnelle")
|
||||
else:
|
||||
self.log_error("Validation d'action échouée")
|
||||
else:
|
||||
self.log_error(f"Endpoint de validation non accessible: {response.status_code}")
|
||||
|
||||
except requests.exceptions.RequestException as e:
|
||||
self.log_error(f"Erreur de validation: {e}")
|
||||
|
||||
def cleanup(self):
|
||||
"""Nettoyage des ressources"""
|
||||
if self.backend_process:
|
||||
try:
|
||||
self.backend_process.terminate()
|
||||
self.backend_process.wait(timeout=5)
|
||||
except subprocess.TimeoutExpired:
|
||||
self.backend_process.kill()
|
||||
|
||||
def log_success(self, message: str):
|
||||
"""Enregistrer un succès"""
|
||||
print(f"✅ {message}")
|
||||
self.tests_passed += 1
|
||||
|
||||
def log_error(self, message: str):
|
||||
"""Enregistrer une erreur"""
|
||||
print(f"❌ {message}")
|
||||
self.tests_failed += 1
|
||||
self.errors.append(message)
|
||||
|
||||
def print_final_report(self):
|
||||
"""Imprimer le rapport final"""
|
||||
print("\n" + "=" * 60)
|
||||
print("📊 RAPPORT FINAL DE VALIDATION")
|
||||
print("=" * 60)
|
||||
|
||||
print(f"✅ Tests réussis: {self.tests_passed}")
|
||||
print(f"❌ Tests échoués: {self.tests_failed}")
|
||||
print(f"📈 Taux de réussite: {(self.tests_passed / (self.tests_passed + self.tests_failed) * 100):.1f}%")
|
||||
|
||||
if self.errors:
|
||||
print("\n🔧 ERREURS À CORRIGER:")
|
||||
for i, error in enumerate(self.errors, 1):
|
||||
print(f" {i}. {error}")
|
||||
|
||||
if self.tests_failed == 0:
|
||||
print("\n🎉 VALIDATION COMPLÈTE RÉUSSIE!")
|
||||
print("✨ L'intégration des propriétés d'étapes VWB est fonctionnelle")
|
||||
return True
|
||||
else:
|
||||
print("\n⚠️ VALIDATION INCOMPLÈTE")
|
||||
print("🔧 Veuillez corriger les erreurs identifiées")
|
||||
return False
|
||||
|
||||
def main():
|
||||
"""Fonction principale"""
|
||||
validator = ValidationFinaleProprietesVWB()
|
||||
success = validator.run_all_validations()
|
||||
|
||||
return 0 if success else 1
|
||||
|
||||
if __name__ == "__main__":
|
||||
exit(main())
|
||||
Reference in New Issue
Block a user