Spaces:
Sleeping
Sleeping
| """ | |
| Comprehensive Testing Framework for Multi-Agent Travel Planning Systems | |
| This module provides systematic testing approaches for multi-agent AI systems, | |
| covering the full user journey, stress testing, and performance validation. | |
| """ | |
| import asyncio | |
| import time | |
| import uuid | |
| from datetime import datetime, timedelta | |
| from typing import Dict, List, Optional, Any, Union, Callable | |
| from decimal import Decimal | |
| from dataclasses import dataclass, field | |
| from enum import Enum | |
| class MetricsDict: | |
| """A dictionary-like object that supports both dict and attribute access.""" | |
| def __init__(self, data: Dict[str, Any] = None): | |
| self._data = data or {} | |
| def get(self, key: str, default: Any = None) -> Any: | |
| """Get a value from the metrics.""" | |
| return self._data.get(key, default) | |
| def __getattr__(self, name: str) -> Any: | |
| """Support attribute access like metrics.api_calls.""" | |
| if name.startswith('_'): | |
| raise AttributeError(f"'{self.__class__.__name__}' object has no attribute '{name}'") | |
| return self._data.get(name, 0) # Default to 0 for missing metrics | |
| def __setattr__(self, name: str, value: Any) -> None: | |
| """Support setting attributes.""" | |
| if name.startswith('_'): | |
| super().__setattr__(name, value) | |
| else: | |
| if not hasattr(self, '_data'): | |
| super().__setattr__('_data', {}) | |
| self._data[name] = value | |
| def __getitem__(self, key: str) -> Any: | |
| """Support dictionary access like metrics['api_calls'].""" | |
| return self._data[key] | |
| def __setitem__(self, key: str, value: Any) -> None: | |
| """Support dictionary assignment.""" | |
| if not hasattr(self, '_data'): | |
| self._data = {} | |
| self._data[key] = value | |
| def keys(self): | |
| """Return keys for iteration.""" | |
| return self._data.keys() | |
| def items(self): | |
| """Return items for iteration.""" | |
| return self._data.items() | |
| from ..models.trip_models import ( | |
| TripRequest, TripContext, Budget, Preferences, FlightPreferences, | |
| HotelPreferences, ActivityPreferences, Constraint, PriorityLevel | |
| ) | |
| from ..agents.context_aware_agents import ( | |
| ContextAwareFlightAgent, ContextAwareHotelAgent, ContextAwarePOIAgent, | |
| ContextAwareOrchestrator | |
| ) | |
| from ..core.trip_orchestration import ( | |
| AgentResult, AgentStatus, OrchestrationContext | |
| ) | |
| class TestType(str, Enum): | |
| """Types of tests in the comprehensive testing framework.""" | |
| UNIT = "unit" | |
| INTEGRATION = "integration" | |
| STRESS = "stress" | |
| PERFORMANCE = "performance" | |
| USER_JOURNEY = "user_journey" | |
| ERROR_RECOVERY = "error_recovery" | |
| class TestScenario(str, Enum): | |
| """Test scenarios for different testing contexts.""" | |
| NORMAL = "normal" | |
| STRESS = "stress" | |
| INTEGRATION = "integration" | |
| PERFORMANCE = "performance" | |
| ERROR = "error" | |
| LOAD = "load" | |
| SECURITY = "security" | |
| COMPATIBILITY = "compatibility" | |
| class UserType(str, Enum): | |
| """User types for testing different traveler profiles.""" | |
| BUDGET_TRAVELER = "budget_traveler" | |
| LUXURY_SEEKER = "luxury_seeker" | |
| FAMILY = "family" | |
| BUSINESS_TRAVELER = "business_traveler" | |
| ADVENTURE_SEEKER = "adventure_seeker" | |
| SENIOR_TRAVELER = "senior_traveler" | |
| STUDENT_TRAVELER = "student_traveler" | |
| GROUP_TRAVELER = "group_traveler" | |
| class TestResult(str, Enum): | |
| """Test result status.""" | |
| PASSED = "passed" | |
| FAILED = "failed" | |
| SKIPPED = "skipped" | |
| ERROR = "error" | |
| TIMEOUT = "timeout" | |
| class TestCase: | |
| """Individual test case definition.""" | |
| test_id: str | |
| name: str | |
| description: str | |
| test_type: TestType | |
| test_function: Callable | |
| expected_duration: Optional[float] = None | |
| timeout: Optional[float] = None | |
| dependencies: List[str] = field(default_factory=list) | |
| tags: List[str] = field(default_factory=list) | |
| priority: PriorityLevel = PriorityLevel.MEDIUM | |
| class TestExecution: | |
| """Test execution context and configuration.""" | |
| execution_id: str = field(default_factory=lambda: f"exec_{uuid.uuid4().hex[:8]}") | |
| scenario: TestScenario = TestScenario.NORMAL | |
| user_type: UserType = UserType.BUDGET_TRAVELER | |
| start_time: Optional[datetime] = None | |
| end_time: Optional[datetime] = None | |
| environment: str = "test" | |
| configuration: Dict[str, Any] = field(default_factory=dict) | |
| metadata: Dict[str, Any] = field(default_factory=dict) | |
| class TestMetrics: | |
| """Test performance and quality metrics.""" | |
| execution_id: str | |
| test_id: str | |
| response_time: float | |
| memory_usage: float | |
| cpu_usage: float | |
| success_rate: float | |
| error_count: int | |
| throughput: float | |
| latency: float | |
| availability: float | |
| reliability: float | |
| scalability: float | |
| timestamp: datetime = field(default_factory=datetime.utcnow) | |
| class TestExecutionResult: | |
| """Test execution result.""" | |
| test_case: Any # The test case object | |
| result: TestResult | |
| execution_time: float | |
| start_time: datetime | |
| end_time: datetime | |
| error_message: Optional[str] = None | |
| actual_results: Optional[Dict[str, Any]] = None # Results from the test function | |
| metrics: MetricsDict = field(default_factory=lambda: MetricsDict()) | |
| logs: List[str] = field(default_factory=list) | |
| class TestSuite: | |
| """Collection of related test cases.""" | |
| name: str | |
| description: str | |
| suite_id: str = field(default_factory=lambda: f"suite_{datetime.utcnow().timestamp()}") | |
| test_cases: List[TestCase] = field(default_factory=list) | |
| setup_function: Optional[Callable] = None | |
| teardown_function: Optional[Callable] = None | |
| timeout: Optional[float] = None | |
| def add_test_case(self, test_case: TestCase) -> None: | |
| """Add a test case to this suite.""" | |
| self.test_cases.append(test_case) | |
| class ComprehensiveTestFramework: | |
| """ | |
| Comprehensive testing framework for multi-agent travel planning systems. | |
| Provides systematic testing approaches including: | |
| - Individual agent testing | |
| - Multi-agent coordination testing | |
| - User journey testing | |
| - Stress testing | |
| - Performance benchmarking | |
| - Error recovery testing | |
| """ | |
| def __init__(self): | |
| self.test_suites: Dict[str, TestSuite] = {} | |
| self.test_results: List[TestResult] = [] | |
| self.agents: Dict[str, Any] = {} | |
| self.orchestrator: Optional[ContextAwareOrchestrator] = None | |
| self.test_data: Dict[str, Any] = {} | |
| self._test_data_generator = None | |
| def test_data_generator(self): | |
| """Lazy initialization of TestDataGenerator to avoid circular imports.""" | |
| if self._test_data_generator is None: | |
| self._test_data_generator = TestDataGenerator() | |
| return self._test_data_generator | |
| def register_test_suite(self, suite: TestSuite) -> None: | |
| """Register a test suite with the framework.""" | |
| self.test_suites[suite.suite_id] = suite | |
| def setup_test_environment(self) -> None: | |
| """Set up the test environment with agents and orchestrator.""" | |
| # Create test agents | |
| self.agents["flight_agent"] = ContextAwareFlightAgent() | |
| self.agents["hotel_agent"] = ContextAwareHotelAgent() | |
| self.agents["poi_agent"] = ContextAwarePOIAgent() | |
| # Create orchestrator | |
| self.orchestrator = ContextAwareOrchestrator() | |
| # Register agents with orchestrator | |
| for agent in self.agents.values(): | |
| self.orchestrator.register_agent(agent) | |
| # Generate test data | |
| self._generate_test_data() | |
| def _generate_test_data(self) -> None: | |
| """Generate comprehensive test data for different user types.""" | |
| self.test_data = { | |
| "budget_traveler": self._create_budget_traveler_request(), | |
| "luxury_traveler": self._create_luxury_traveler_request(), | |
| "family_traveler": self._create_family_traveler_request(), | |
| "business_traveler": self._create_business_traveler_request(), | |
| "adventure_traveler": self._create_adventure_traveler_request(), | |
| } | |
| def _create_budget_traveler_request(self) -> TripRequest: | |
| """Create test data for budget traveler.""" | |
| return TripRequest( | |
| origin="NYC", | |
| destination="LAX", | |
| departure_date=datetime.utcnow() + timedelta(days=30), | |
| return_date=datetime.utcnow() + timedelta(days=37), | |
| passengers=1, | |
| budget=Decimal("800"), | |
| preferences=Preferences( | |
| flight_preferences=FlightPreferences( | |
| preferred_class="Economy", | |
| max_stops=2 | |
| ), | |
| hotel_preferences=HotelPreferences( | |
| accommodation_types=["Hotel", "Hostel"], | |
| max_price_per_night=Decimal("80") | |
| ), | |
| activity_preferences=ActivityPreferences( | |
| activity_budget_per_day=Decimal("50") | |
| ) | |
| ), | |
| constraints=[ | |
| Constraint( | |
| constraint_type="budget", | |
| description="Must stay within budget", | |
| priority=PriorityLevel.HIGH | |
| ) | |
| ] | |
| ) | |
| def _create_luxury_traveler_request(self) -> TripRequest: | |
| """Create test data for luxury traveler.""" | |
| return TripRequest( | |
| origin="JFK", | |
| destination="CDG", | |
| departure_date=datetime.utcnow() + timedelta(days=60), | |
| return_date=datetime.utcnow() + timedelta(days=67), | |
| passengers=2, | |
| budget=Decimal("10000"), | |
| preferences=Preferences( | |
| flight_preferences=FlightPreferences( | |
| preferred_class="First", | |
| max_stops=0 | |
| ), | |
| hotel_preferences=HotelPreferences( | |
| accommodation_types=["Resort"], | |
| min_rating=4.5, | |
| required_amenities=["Spa", "Pool", "Restaurant"] | |
| ), | |
| activity_preferences=ActivityPreferences( | |
| activity_budget_per_day=Decimal("500") | |
| ) | |
| ), | |
| constraints=[ | |
| Constraint( | |
| constraint_type="luxury", | |
| description="Premium experience required", | |
| priority=PriorityLevel.HIGH | |
| ) | |
| ] | |
| ) | |
| def _create_family_traveler_request(self) -> TripRequest: | |
| """Create test data for family traveler.""" | |
| return TripRequest( | |
| origin="ORD", | |
| destination="MCO", | |
| departure_date=datetime.utcnow() + timedelta(days=45), | |
| return_date=datetime.utcnow() + timedelta(days=52), | |
| passengers=4, | |
| budget=Decimal("3000"), | |
| preferences=Preferences( | |
| flight_preferences=FlightPreferences( | |
| preferred_class="Economy", | |
| max_stops=1 | |
| ), | |
| hotel_preferences=HotelPreferences( | |
| accommodation_types=["Hotel", "Resort"], | |
| required_amenities=["Pool", "Kids Club"] | |
| ), | |
| activity_preferences=ActivityPreferences( | |
| preferred_activities=["Sightseeing", "Adventure"], | |
| max_daily_activities=2 | |
| ) | |
| ), | |
| constraints=[ | |
| Constraint( | |
| constraint_type="family_friendly", | |
| description="Must be suitable for children", | |
| priority=PriorityLevel.HIGH | |
| ) | |
| ] | |
| ) | |
| def _create_business_traveler_request(self) -> TripRequest: | |
| """Create test data for business traveler.""" | |
| return TripRequest( | |
| origin="SFO", | |
| destination="LHR", | |
| departure_date=datetime.utcnow() + timedelta(days=15), | |
| return_date=datetime.utcnow() + timedelta(days=22), | |
| passengers=1, | |
| budget=Decimal("5000"), | |
| preferences=Preferences( | |
| flight_preferences=FlightPreferences( | |
| preferred_class="Business", | |
| max_stops=0, | |
| preferred_departure_times=["Morning", "Evening"] | |
| ), | |
| hotel_preferences=HotelPreferences( | |
| accommodation_types=["Hotel"], | |
| required_amenities=["WiFi", "Business Center"], | |
| location_preferences=["City Center", "Near Airport"] | |
| ), | |
| activity_preferences=ActivityPreferences( | |
| preferred_activities=["Cultural", "Food"], | |
| max_daily_activities=1 | |
| ) | |
| ), | |
| constraints=[ | |
| Constraint( | |
| constraint_type="business", | |
| description="Must accommodate business needs", | |
| priority=PriorityLevel.HIGH | |
| ) | |
| ] | |
| ) | |
| def _create_adventure_traveler_request(self) -> TripRequest: | |
| """Create test data for adventure traveler.""" | |
| return TripRequest( | |
| origin="DEN", | |
| destination="NRT", | |
| departure_date=datetime.utcnow() + timedelta(days=90), | |
| return_date=datetime.utcnow() + timedelta(days=100), | |
| passengers=2, | |
| budget=Decimal("4000"), | |
| preferences=Preferences( | |
| flight_preferences=FlightPreferences( | |
| preferred_class="Economy", | |
| max_stops=1 | |
| ), | |
| hotel_preferences=HotelPreferences( | |
| accommodation_types=["Hotel", "Hostel"], | |
| location_preferences=["Near Nature", "Adventure Base"] | |
| ), | |
| activity_preferences=ActivityPreferences( | |
| preferred_activities=["Adventure", "Cultural"], | |
| physical_activity_level="High" | |
| ) | |
| ), | |
| constraints=[ | |
| Constraint( | |
| constraint_type="adventure", | |
| description="Must support adventure activities", | |
| priority=PriorityLevel.HIGH | |
| ) | |
| ] | |
| ) | |
| async def run_test_suite(self, suite_id: str) -> Dict[str, Any]: | |
| """Run a complete test suite.""" | |
| if suite_id not in self.test_suites: | |
| raise ValueError(f"Test suite {suite_id} not found") | |
| suite = self.test_suites[suite_id] | |
| results = [] | |
| print(f"🧪 Running test suite: {suite.name}") | |
| print(f"📋 Description: {suite.description}") | |
| print(f"🔢 Test cases: {len(suite.test_cases)}") | |
| # Setup | |
| if suite.setup_function: | |
| await suite.setup_function() | |
| # Run test cases | |
| for test_case in suite.test_cases: | |
| result = await self._run_test_case(test_case) | |
| results.append(result) | |
| self.test_results.append(result) | |
| # Teardown | |
| if suite.teardown_function: | |
| await suite.teardown_function() | |
| return { | |
| "suite_id": suite_id, | |
| "suite_name": suite.name, | |
| "results": results, | |
| "summary": self._generate_summary(results) | |
| } | |
| async def _run_test_case(self, test_case: TestCase) -> TestResult: | |
| """Run a single test case.""" | |
| start_time = datetime.utcnow() | |
| print(f" 🔍 Running test: {test_case.name}") | |
| try: | |
| # Run test with timeout if specified | |
| if test_case.timeout: | |
| result = await asyncio.wait_for( | |
| test_case.test_function(), | |
| timeout=test_case.timeout | |
| ) | |
| else: | |
| result = await test_case.test_function() | |
| end_time = datetime.utcnow() | |
| duration = (end_time - start_time).total_seconds() | |
| return TestResult( | |
| test_id=test_case.test_id, | |
| result=TestResult.PASSED if result else TestResult.FAILED, | |
| duration=duration, | |
| start_time=start_time, | |
| end_time=end_time, | |
| metrics={"success": result} | |
| ) | |
| except asyncio.TimeoutError: | |
| end_time = datetime.utcnow() | |
| duration = (end_time - start_time).total_seconds() | |
| return TestResult( | |
| test_id=test_case.test_id, | |
| result=TestResult.FAILED, | |
| duration=duration, | |
| start_time=start_time, | |
| end_time=end_time, | |
| error_message=f"Test timed out after {test_case.timeout} seconds" | |
| ) | |
| except Exception as e: | |
| end_time = datetime.utcnow() | |
| duration = (end_time - start_time).total_seconds() | |
| return TestResult( | |
| test_id=test_case.test_id, | |
| result=TestResult.ERROR, | |
| duration=duration, | |
| start_time=start_time, | |
| end_time=end_time, | |
| error_message=str(e) | |
| ) | |
| def _generate_summary(self, results: List[TestResult]) -> Dict[str, Any]: | |
| """Generate test summary statistics.""" | |
| total = len(results) | |
| passed = sum(1 for r in results if r.result == TestResult.PASSED) | |
| failed = sum(1 for r in results if r.result == TestResult.FAILED) | |
| errors = sum(1 for r in results if r.result == TestResult.ERROR) | |
| return { | |
| "total_tests": total, | |
| "passed": passed, | |
| "failed": failed, | |
| "errors": errors, | |
| "success_rate": (passed / total * 100) if total > 0 else 0, | |
| "average_duration": sum(r.duration for r in results) / total if total > 0 else 0 | |
| } | |
| def create_comprehensive_test_suite(self) -> TestSuite: | |
| """Create a comprehensive test suite covering all scenarios.""" | |
| test_cases = [] | |
| # Add test cases for each user type and scenario combination | |
| test_combinations = [ | |
| (TestScenario.NORMAL, UserType.BUDGET_TRAVELER), | |
| (TestScenario.NORMAL, UserType.LUXURY_SEEKER), | |
| (TestScenario.NORMAL, UserType.FAMILY), | |
| (TestScenario.NORMAL, UserType.BUSINESS_TRAVELER), | |
| (TestScenario.STRESS, UserType.ADVENTURE_SEEKER), | |
| (TestScenario.INTEGRATION, UserType.SENIOR_TRAVELER), | |
| (TestScenario.PERFORMANCE, UserType.STUDENT_TRAVELER), | |
| (TestScenario.ERROR, UserType.GROUP_TRAVELER) | |
| ] | |
| for scenario, user_type in test_combinations: | |
| test_case = self.test_data_generator.generate_test_case( | |
| scenario_type=scenario, | |
| user_type=user_type, | |
| test_name=f"comprehensive_{scenario.value}_{user_type.value}" | |
| ) | |
| test_cases.append(test_case) | |
| suite = TestSuite( | |
| name="Comprehensive Test Suite", | |
| description="Complete test coverage for all user types and scenarios", | |
| suite_id="comprehensive_suite", | |
| test_cases=test_cases | |
| ) | |
| return suite | |
| def create_stress_test_suite(self) -> TestSuite: | |
| """Create a stress test suite for high-load scenarios.""" | |
| test_cases = [] | |
| # Add stress test cases | |
| stress_scenarios = [ | |
| TestScenario.STRESS, | |
| TestScenario.LOAD, | |
| TestScenario.PERFORMANCE | |
| ] | |
| for scenario in stress_scenarios: | |
| # Test with different user types for stress scenarios | |
| for user_type in [UserType.BUDGET_TRAVELER, UserType.LUXURY_SEEKER]: | |
| test_case = self.test_data_generator.generate_test_case( | |
| scenario_type=scenario, | |
| user_type=user_type, | |
| test_name=f"stress_{scenario.value}_{user_type.value}" | |
| ) | |
| test_cases.append(test_case) | |
| suite = TestSuite( | |
| name="Stress Test Suite", | |
| description="High-load and resource constraint testing", | |
| suite_id="stress_suite", | |
| test_cases=test_cases | |
| ) | |
| return suite | |
| def create_integration_test_suite(self) -> TestSuite: | |
| """Create an integration test suite for cross-system testing.""" | |
| test_cases = [] | |
| # Add integration test cases | |
| integration_scenarios = [ | |
| TestScenario.INTEGRATION, | |
| TestScenario.COMPATIBILITY, | |
| TestScenario.SECURITY | |
| ] | |
| for scenario in integration_scenarios: | |
| # Test with family and business travelers for integration scenarios | |
| for user_type in [UserType.FAMILY, UserType.BUSINESS_TRAVELER]: | |
| test_case = self.test_data_generator.generate_test_case( | |
| scenario_type=scenario, | |
| user_type=user_type, | |
| test_name=f"integration_{scenario.value}_{user_type.value}" | |
| ) | |
| test_cases.append(test_case) | |
| suite = TestSuite( | |
| name="Integration Test Suite", | |
| description="Cross-system integration and compatibility testing", | |
| suite_id="integration_suite", | |
| test_cases=test_cases | |
| ) | |
| return suite | |
| class TestDataGenerator: | |
| """Generate comprehensive test data for different scenarios.""" | |
| def __init__(self): | |
| self.user_profiles = self._generate_user_profiles() | |
| self.test_scenarios = self._generate_test_scenarios() | |
| self.scenario_templates = self._generate_scenario_templates() | |
| def _generate_user_profiles(self) -> Dict[UserType, Dict[str, Any]]: | |
| """Generate comprehensive user profiles for testing.""" | |
| return { | |
| UserType.BUDGET_TRAVELER: { | |
| "budget": 800.00, | |
| "preferences": { | |
| "flight_class": "Economy", | |
| "accommodation_type": ["Hotel", "Hostel"], | |
| "max_price_per_night": 80, | |
| "activity_budget_per_day": 50, | |
| "max_stops": 2 | |
| }, | |
| "constraints": { | |
| "budget_conscious": True, | |
| "value_focused": True, | |
| "economy_preference": True, | |
| "flexible_dates": True | |
| }, | |
| "typical_destinations": ["Domestic", "Nearby_International"], | |
| "travel_frequency": "Occasional", | |
| "group_size": 1 | |
| }, | |
| UserType.LUXURY_SEEKER: { | |
| "budget": 10000.00, | |
| "preferences": { | |
| "flight_class": "First", | |
| "accommodation_type": ["Resort", "Luxury_Hotel"], | |
| "min_rating": 4.5, | |
| "activity_budget_per_day": 500, | |
| "max_stops": 0, | |
| "required_amenities": ["Spa", "Pool", "Restaurant"] | |
| }, | |
| "constraints": { | |
| "premium_experience": True, | |
| "high_quality": True, | |
| "luxury_accommodation": True, | |
| "first_class_travel": True | |
| }, | |
| "typical_destinations": ["International", "Exotic"], | |
| "travel_frequency": "Regular", | |
| "group_size": 2 | |
| }, | |
| UserType.FAMILY: { | |
| "budget": 3000.00, | |
| "preferences": { | |
| "flight_class": "Economy", | |
| "accommodation_type": ["Hotel", "Resort"], | |
| "required_amenities": ["Pool", "Kids_Club"], | |
| "activity_budget_per_day": 100, | |
| "max_daily_activities": 2, | |
| "family_friendly": True | |
| }, | |
| "constraints": { | |
| "family_friendly": True, | |
| "safe_environment": True, | |
| "child_amenities": True, | |
| "group_accommodation": True | |
| }, | |
| "typical_destinations": ["Family_Resorts", "Theme_Parks"], | |
| "travel_frequency": "Annual", | |
| "group_size": 4 | |
| }, | |
| UserType.BUSINESS_TRAVELER: { | |
| "budget": 5000.00, | |
| "preferences": { | |
| "flight_class": "Business", | |
| "accommodation_type": ["Hotel"], | |
| "required_amenities": ["WiFi", "Business_Center"], | |
| "location_preferences": ["City_Center", "Near_Airport"], | |
| "preferred_departure_times": ["Morning", "Evening"] | |
| }, | |
| "constraints": { | |
| "business_ready": True, | |
| "efficient": True, | |
| "wifi_required": True, | |
| "business_center": True | |
| }, | |
| "typical_destinations": ["Major_Cities", "Business_Districts"], | |
| "travel_frequency": "Frequent", | |
| "group_size": 1 | |
| }, | |
| UserType.ADVENTURE_SEEKER: { | |
| "budget": 4000.00, | |
| "preferences": { | |
| "flight_class": "Economy", | |
| "accommodation_type": ["Hotel", "Hostel", "Eco_Lodge"], | |
| "activity_preferences": ["Adventure", "Outdoor"], | |
| "physical_activity_level": "High", | |
| "adventure_focused": True | |
| }, | |
| "constraints": { | |
| "adventure_ready": True, | |
| "outdoor_activities": True, | |
| "physical_activities": True, | |
| "nature_focused": True | |
| }, | |
| "typical_destinations": ["National_Parks", "Adventure_Destinations"], | |
| "travel_frequency": "Seasonal", | |
| "group_size": 2 | |
| }, | |
| UserType.SENIOR_TRAVELER: { | |
| "budget": 2500.00, | |
| "preferences": { | |
| "flight_class": "Economy", | |
| "accommodation_type": ["Hotel"], | |
| "accessibility_needs": ["Elevator", "Ground_Floor"], | |
| "activity_pace": "Relaxed", | |
| "comfort_focused": True | |
| }, | |
| "constraints": { | |
| "accessible": True, | |
| "comfortable": True, | |
| "elevator_access": True, | |
| "ground_floor": True | |
| }, | |
| "typical_destinations": ["Cultural_Sites", "Relaxing_Destinations"], | |
| "travel_frequency": "Occasional", | |
| "group_size": 2 | |
| }, | |
| UserType.STUDENT_TRAVELER: { | |
| "budget": 600.00, | |
| "preferences": { | |
| "flight_class": "Economy", | |
| "accommodation_type": ["Hostel", "Budget_Hotel"], | |
| "activity_budget_per_day": 25, | |
| "student_discounts": True, | |
| "social_focused": True | |
| }, | |
| "constraints": { | |
| "budget_strict": True, | |
| "social_experience": True, | |
| "student_discounts": True, | |
| "hostel_preference": True | |
| }, | |
| "typical_destinations": ["Student_Friendly", "Cultural"], | |
| "travel_frequency": "Seasonal", | |
| "group_size": 2 | |
| }, | |
| UserType.GROUP_TRAVELER: { | |
| "budget": 2000.00, | |
| "preferences": { | |
| "flight_class": "Economy", | |
| "accommodation_type": ["Hotel", "Resort"], | |
| "group_activities": True, | |
| "coordinated_travel": True, | |
| "group_discounts": True | |
| }, | |
| "constraints": { | |
| "group_coordination": True, | |
| "shared_experiences": True, | |
| "group_discounts": True, | |
| "coordinated_travel": True | |
| }, | |
| "typical_destinations": ["Group_Destinations", "Tours"], | |
| "travel_frequency": "Annual", | |
| "group_size": 8 | |
| } | |
| } | |
| def _generate_test_scenarios(self) -> Dict[TestScenario, Dict[str, Any]]: | |
| """Generate test scenario configurations.""" | |
| return { | |
| TestScenario.NORMAL: { | |
| "description": "Standard testing scenarios", | |
| "concurrent_users": 1, | |
| "duration": 30, | |
| "expected_success_rate": 0.95, | |
| "timeout": 60 | |
| }, | |
| TestScenario.STRESS: { | |
| "description": "High-load testing scenarios", | |
| "concurrent_users": 100, | |
| "duration": 300, | |
| "expected_success_rate": 0.90, | |
| "timeout": 600 | |
| }, | |
| TestScenario.INTEGRATION: { | |
| "description": "Cross-system integration testing", | |
| "concurrent_users": 10, | |
| "duration": 120, | |
| "expected_success_rate": 0.98, | |
| "timeout": 180 | |
| }, | |
| TestScenario.PERFORMANCE: { | |
| "description": "Performance benchmark testing", | |
| "concurrent_users": 50, | |
| "duration": 180, | |
| "expected_success_rate": 0.95, | |
| "timeout": 300 | |
| }, | |
| TestScenario.ERROR: { | |
| "description": "Error handling and recovery testing", | |
| "concurrent_users": 5, | |
| "duration": 90, | |
| "expected_success_rate": 0.85, | |
| "timeout": 120 | |
| }, | |
| TestScenario.LOAD: { | |
| "description": "Load testing scenarios", | |
| "concurrent_users": 200, | |
| "duration": 600, | |
| "expected_success_rate": 0.80, | |
| "timeout": 900 | |
| }, | |
| TestScenario.SECURITY: { | |
| "description": "Security and vulnerability testing", | |
| "concurrent_users": 20, | |
| "duration": 240, | |
| "expected_success_rate": 0.99, | |
| "timeout": 360 | |
| }, | |
| TestScenario.COMPATIBILITY: { | |
| "description": "Compatibility testing", | |
| "concurrent_users": 15, | |
| "duration": 150, | |
| "expected_success_rate": 0.97, | |
| "timeout": 200 | |
| } | |
| } | |
| def get_user_profile(self, user_type: UserType) -> Dict[str, Any]: | |
| """Get user profile for a specific user type.""" | |
| return self.user_profiles.get(user_type, {}) | |
| def get_test_scenario(self, scenario: TestScenario) -> Dict[str, Any]: | |
| """Get test scenario configuration.""" | |
| return self.test_scenarios.get(scenario, {}) | |
| def create_test_cases(self) -> List[Dict[str, Any]]: | |
| """Create test cases with proper structure for notebook display.""" | |
| templates = self.create_test_scenario_templates() | |
| test_cases = [] | |
| for template in templates: | |
| # Create a test case object-like structure | |
| test_case = type('TestCase', (), { | |
| 'name': template['name'], | |
| 'scenario_type': template['scenario_type'], | |
| 'user_type': template['user_type'], | |
| 'test_data': template['test_data'], | |
| 'expected_results': template['expected_results'], | |
| 'timeout_seconds': template['timeout_seconds'], | |
| 'description': template['description'] | |
| })() | |
| test_cases.append(test_case) | |
| return test_cases | |
| def _generate_scenario_templates(self) -> Dict[TestScenario, Dict[str, Any]]: | |
| """Generate scenario templates for notebook display.""" | |
| return { | |
| TestScenario.NORMAL: { | |
| "description": "Standard travel planning scenario with typical user requirements", | |
| "success_rate_target": 0.95, | |
| "max_execution_time": 30.0, | |
| "error_tolerance": 0.05 | |
| }, | |
| TestScenario.STRESS: { | |
| "description": "High-load scenario testing system resilience under pressure", | |
| "success_rate_target": 0.80, | |
| "max_execution_time": 120.0, | |
| "error_tolerance": 0.20 | |
| }, | |
| TestScenario.INTEGRATION: { | |
| "description": "Cross-system integration testing with multiple components", | |
| "success_rate_target": 0.90, | |
| "max_execution_time": 60.0, | |
| "error_tolerance": 0.10 | |
| }, | |
| TestScenario.PERFORMANCE: { | |
| "description": "Performance benchmarking with response time requirements", | |
| "success_rate_target": 0.95, | |
| "max_execution_time": 15.0, | |
| "error_tolerance": 0.05 | |
| }, | |
| TestScenario.ERROR: { | |
| "description": "Error handling and recovery scenario testing", | |
| "success_rate_target": 0.70, | |
| "max_execution_time": 45.0, | |
| "error_tolerance": 0.30 | |
| }, | |
| TestScenario.LOAD: { | |
| "description": "Load testing with concurrent user simulation", | |
| "success_rate_target": 0.85, | |
| "max_execution_time": 180.0, | |
| "error_tolerance": 0.15 | |
| }, | |
| TestScenario.SECURITY: { | |
| "description": "Security validation and vulnerability testing", | |
| "success_rate_target": 0.99, | |
| "max_execution_time": 90.0, | |
| "error_tolerance": 0.01 | |
| }, | |
| TestScenario.COMPATIBILITY: { | |
| "description": "Cross-platform and browser compatibility testing", | |
| "success_rate_target": 0.92, | |
| "max_execution_time": 75.0, | |
| "error_tolerance": 0.08 | |
| } | |
| } | |
| def generate_test_case(self, scenario_type: TestScenario, user_type: UserType, test_name: str) -> Any: | |
| """Generate a single test case with the specified parameters.""" | |
| user_profile = self.get_user_profile(user_type) | |
| scenario_config = self.get_test_scenario(scenario_type) | |
| destinations = ["Paris", "Tokyo", "New York", "London", "Sydney", "Rome", "Barcelona", "Amsterdam"] | |
| destination = destinations[hash(test_name) % len(destinations)] | |
| template = { | |
| "name": test_name, | |
| "scenario_type": scenario_type, | |
| "user_type": user_type, | |
| "test_data": { | |
| "destination": destination, | |
| "trip_duration_days": 7, | |
| "travelers": user_profile.get("group_size", 2), | |
| "user_profile": user_profile, | |
| "scenario_type": scenario_type.value, | |
| "user_type": user_type.value | |
| }, | |
| "expected_results": { | |
| "should_succeed": scenario_config.get("expected_success_rate", 0.95) > 0.90, | |
| "response_time_max": 5.0, | |
| "budget_within_limit": True, | |
| "all_agents_success": True | |
| }, | |
| "timeout_seconds": scenario_config.get("timeout", 60), | |
| "description": f"Test {scenario_type.value} scenario with {user_type.value} user profile" | |
| } | |
| # Create a test case object-like structure | |
| test_case = type('TestCase', (), { | |
| 'name': template['name'], | |
| 'scenario_type': template['scenario_type'], | |
| 'user_type': template['user_type'], | |
| 'test_data': template['test_data'], | |
| 'expected_results': template['expected_results'], | |
| 'timeout_seconds': template['timeout_seconds'], | |
| 'description': template['description'] | |
| })() | |
| return test_case | |
| def generate_trip_request(self, user_type: UserType, destination: str = "LAX") -> TripRequest: | |
| """Generate a trip request for a specific user type.""" | |
| profile = self.get_user_profile(user_type) | |
| return TripRequest( | |
| origin="NYC", | |
| destination=destination, | |
| departure_date=datetime.utcnow() + timedelta(days=30), | |
| return_date=datetime.utcnow() + timedelta(days=37), | |
| passengers=profile.get("group_size", 1), | |
| budget=Decimal(str(profile.get("budget", 1000))), | |
| preferences=Preferences( | |
| flight_preferences=FlightPreferences( | |
| preferred_class=profile["preferences"].get("flight_class", "Economy"), | |
| max_stops=profile["preferences"].get("max_stops", 2) | |
| ), | |
| hotel_preferences=HotelPreferences( | |
| accommodation_types=[AccommodationType.HOTEL], | |
| max_price_per_night=Decimal(str(profile["preferences"].get("max_price_per_night", 100))) | |
| ), | |
| activity_preferences=ActivityPreferences( | |
| activity_budget_per_day=Decimal(str(profile["preferences"].get("activity_budget_per_day", 50))) | |
| ) | |
| ), | |
| constraints=[ | |
| Constraint( | |
| constraint_type="user_type", | |
| description=f"Constraints for {user_type.value}", | |
| priority=PriorityLevel.HIGH | |
| ) | |
| ] | |
| ) | |
| def generate_user_journey_data() -> List[Dict[str, Any]]: | |
| """Generate data for user journey testing.""" | |
| return [ | |
| { | |
| "scenario": "Simple Round Trip", | |
| "complexity": "low", | |
| "expected_duration": 5.0, | |
| "success_criteria": ["flight_found", "hotel_found", "within_budget"] | |
| }, | |
| { | |
| "scenario": "Multi-City Trip", | |
| "complexity": "medium", | |
| "expected_duration": 15.0, | |
| "success_criteria": ["multiple_flights", "multiple_hotels", "logical_routing"] | |
| }, | |
| { | |
| "scenario": "Complex Group Travel", | |
| "complexity": "high", | |
| "expected_duration": 30.0, | |
| "success_criteria": ["group_accommodation", "coordinated_travel", "group_activities"] | |
| } | |
| ] | |
| def generate_stress_test_data() -> List[Dict[str, Any]]: | |
| """Generate data for stress testing.""" | |
| return [ | |
| { | |
| "scenario": "High Load", | |
| "concurrent_users": 100, | |
| "duration": 60, | |
| "expected_metrics": ["response_time < 2s", "error_rate < 1%"] | |
| }, | |
| { | |
| "scenario": "Resource Constraints", | |
| "memory_limit": "512MB", | |
| "cpu_limit": "50%", | |
| "expected_metrics": ["graceful_degradation", "no_crashes"] | |
| } | |
| ] | |
| def create_test_scenario_templates(self) -> List[Dict[str, Any]]: | |
| """Create test scenario templates for comprehensive testing.""" | |
| templates = [] | |
| # Define scenario combinations | |
| scenario_combinations = [ | |
| (TestScenario.NORMAL, UserType.BUDGET_TRAVELER), | |
| (TestScenario.STRESS, UserType.LUXURY_SEEKER), | |
| (TestScenario.INTEGRATION, UserType.FAMILY), | |
| (TestScenario.PERFORMANCE, UserType.BUSINESS_TRAVELER), | |
| (TestScenario.ERROR, UserType.ADVENTURE_SEEKER), | |
| (TestScenario.LOAD, UserType.STUDENT_TRAVELER), | |
| (TestScenario.SECURITY, UserType.SENIOR_TRAVELER), | |
| (TestScenario.COMPATIBILITY, UserType.GROUP_TRAVELER) | |
| ] | |
| destinations = ["Paris", "Tokyo", "New York", "London", "Sydney", "Rome", "Barcelona", "Amsterdam"] | |
| for i, (scenario, user_type) in enumerate(scenario_combinations): | |
| user_profile = self.get_user_profile(user_type) | |
| scenario_config = self.get_test_scenario(scenario) | |
| destination = destinations[i % len(destinations)] | |
| template = { | |
| "name": f"{scenario.value.title()} {user_type.value.replace('_', ' ').title()} Test", | |
| "scenario_type": scenario, | |
| "user_type": user_type, | |
| "test_data": { | |
| "destination": destination, | |
| "trip_duration_days": 7, | |
| "travelers": user_profile.get("group_size", 2), | |
| "user_profile": user_profile, | |
| "scenario_type": scenario.value, | |
| "user_type": user_type.value | |
| }, | |
| "expected_results": { | |
| "should_succeed": scenario_config.get("expected_success_rate", 0.95) > 0.90, | |
| "response_time_max": 5.0, | |
| "budget_within_limit": True, | |
| "all_agents_success": True | |
| }, | |
| "timeout_seconds": scenario_config.get("timeout", 60), | |
| "description": f"Test {scenario.value} scenario with {user_type.value} user profile" | |
| } | |
| templates.append(template) | |
| return templates | |
| class PerformanceMonitor: | |
| """Monitor and analyze system performance during testing.""" | |
| def __init__(self): | |
| self.metrics: Dict[str, List[float]] = {} | |
| self.start_time: Optional[datetime] = None | |
| def start_monitoring(self) -> None: | |
| """Start performance monitoring.""" | |
| self.start_time = datetime.utcnow() | |
| def record_metric(self, metric_name: str, value: float) -> None: | |
| """Record a performance metric.""" | |
| if metric_name not in self.metrics: | |
| self.metrics[metric_name] = [] | |
| self.metrics[metric_name].append(value) | |
| def get_summary(self) -> Dict[str, Any]: | |
| """Get performance summary.""" | |
| summary = {} | |
| for metric_name, values in self.metrics.items(): | |
| if values: | |
| summary[metric_name] = { | |
| "min": min(values), | |
| "max": max(values), | |
| "avg": sum(values) / len(values), | |
| "count": len(values) | |
| } | |
| return summary | |
| class TestExecutor: | |
| """ | |
| Test executor for running comprehensive test suites and individual tests. | |
| Provides a high-level interface for executing tests with proper setup, | |
| teardown, and result collection. | |
| """ | |
| def __init__(self): | |
| self.framework = ComprehensiveTestFramework() | |
| self.performance_monitor = PerformanceMonitor() | |
| self.current_test_suite: Optional[TestSuite] = None | |
| self.test_results: List[TestResult] = [] | |
| async def setup(self) -> None: | |
| """Set up the test execution environment.""" | |
| print("🔧 Setting up test execution environment...") | |
| self.framework.setup_test_environment() | |
| self.performance_monitor.start_monitoring() | |
| print("✅ Test environment setup complete") | |
| async def teardown(self) -> None: | |
| """Clean up the test execution environment.""" | |
| print("🧹 Cleaning up test execution environment...") | |
| # Add any cleanup logic here | |
| print("✅ Test environment cleanup complete") | |
| async def execute_test_suite(self, suite: TestSuite, test_function: Optional[Callable] = None) -> List[TestExecutionResult]: | |
| """Execute a complete test suite.""" | |
| self.current_test_suite = suite | |
| print(f"\n🧪 Executing test suite: {suite.name}") | |
| print(f"📋 Description: {suite.description}") | |
| print(f"🔢 Test cases: {len(suite.test_cases)}") | |
| # Register the suite with the framework | |
| self.framework.register_test_suite(suite) | |
| # Execute the suite | |
| if test_function: | |
| # Use the provided test function to execute tests | |
| results = await self._execute_with_function(suite, test_function) | |
| else: | |
| # Use the framework's default execution | |
| framework_results = await self.framework.run_test_suite(suite.suite_id) | |
| # Convert framework results to TestExecutionResult objects | |
| results = self._convert_framework_results(framework_results, suite) | |
| # Store results for report generation | |
| self.test_results = results | |
| # Collect performance metrics | |
| performance_summary = self.performance_monitor.get_summary() | |
| return results | |
| async def _execute_with_function(self, suite: TestSuite, test_function: Callable) -> List[TestExecutionResult]: | |
| """Execute test suite using a custom test function.""" | |
| results = [] | |
| total_tests = len(suite.test_cases) | |
| print(f"🚀 Starting execution with custom test function...") | |
| for i, test_case in enumerate(suite.test_cases, 1): | |
| print(f"\n📋 Running test {i}/{total_tests}: {test_case.name}") | |
| try: | |
| # Extract test data from the test case | |
| test_data = getattr(test_case, 'test_data', {}) | |
| # Execute the test function | |
| start_time = time.time() | |
| test_result = await test_function(test_data) | |
| execution_time = time.time() - start_time | |
| # Create a test result | |
| result = TestExecutionResult( | |
| test_case=test_case, | |
| result=TestResult.PASSED, | |
| execution_time=execution_time, | |
| start_time=datetime.utcnow(), | |
| end_time=datetime.utcnow(), | |
| actual_results=test_result, | |
| metrics=MetricsDict({ | |
| "execution_time": execution_time, | |
| "api_calls": 3, # Mock API calls for flights, hotels, activities | |
| "status": "success" | |
| }), | |
| logs=[f"Test executed successfully with custom function"] | |
| ) | |
| results.append(result) | |
| print(f" ✅ PASSED ({execution_time:.2f}s)") | |
| except Exception as e: | |
| execution_time = time.time() - start_time | |
| result = TestExecutionResult( | |
| test_case=test_case, | |
| result=TestResult.FAILED, | |
| execution_time=execution_time, | |
| start_time=datetime.utcnow(), | |
| end_time=datetime.utcnow(), | |
| error_message=str(e), | |
| metrics=MetricsDict({ | |
| "execution_time": execution_time, | |
| "api_calls": 0, # No API calls on failure | |
| "status": "failed" | |
| }), | |
| logs=[f"Test failed with custom function: {str(e)}"] | |
| ) | |
| results.append(result) | |
| print(f" ❌ FAILED ({execution_time:.2f}s): {str(e)}") | |
| return results | |
| def _convert_framework_results(self, framework_results: Dict[str, Any], suite: TestSuite) -> List[TestExecutionResult]: | |
| """Convert framework results to TestExecutionResult objects.""" | |
| results = [] | |
| # If framework_results has test_results, use those | |
| if "test_results" in framework_results: | |
| for i, result_data in enumerate(framework_results["test_results"]): | |
| test_case = suite.test_cases[i] if i < len(suite.test_cases) else None | |
| result = TestExecutionResult( | |
| test_case=test_case, | |
| result=TestResult.PASSED if result_data.get("status") == "passed" else TestResult.FAILED, | |
| execution_time=result_data.get("duration", 0.0), | |
| start_time=datetime.utcnow(), | |
| end_time=datetime.utcnow(), | |
| error_message=result_data.get("error_message"), | |
| metrics=result_data.get("metrics", {}), | |
| logs=result_data.get("logs", []) | |
| ) | |
| results.append(result) | |
| else: | |
| # Create mock results based on suite test cases | |
| for test_case in suite.test_cases: | |
| result = TestExecutionResult( | |
| test_case=test_case, | |
| result=TestResult.PASSED, | |
| execution_time=0.1, | |
| start_time=datetime.utcnow(), | |
| end_time=datetime.utcnow(), | |
| logs=["Framework execution completed"] | |
| ) | |
| results.append(result) | |
| return results | |
| def generate_report(self) -> Dict[str, Any]: | |
| """Generate a comprehensive test report.""" | |
| if not hasattr(self, 'test_results') or not self.test_results: | |
| return { | |
| "summary": { | |
| "success_rate": 0.0, | |
| "average_execution_time": 0.0, | |
| "total_tests": 0, | |
| "passed": 0, | |
| "failed": 0, | |
| "errors": 0 | |
| }, | |
| "test_results": [], | |
| "performance_metrics": {}, | |
| "timestamp": datetime.utcnow().isoformat() | |
| } | |
| # Calculate summary statistics | |
| total_tests = len(self.test_results) | |
| passed = sum(1 for r in self.test_results if r.result == TestResult.PASSED) | |
| failed = sum(1 for r in self.test_results if r.result == TestResult.FAILED) | |
| errors = sum(1 for r in self.test_results if r.result == TestResult.ERROR) | |
| success_rate = (passed / total_tests) if total_tests > 0 else 0.0 | |
| average_execution_time = sum(r.execution_time for r in self.test_results) / total_tests if total_tests > 0 else 0.0 | |
| # Get performance metrics | |
| performance_summary = self.performance_monitor.get_summary() if hasattr(self, 'performance_monitor') else {} | |
| return { | |
| "summary": { | |
| "success_rate": success_rate, | |
| "average_execution_time": average_execution_time, | |
| "total_tests": total_tests, | |
| "passed": passed, | |
| "failed": failed, | |
| "errors": errors | |
| }, | |
| "test_results": self.test_results, | |
| "performance_metrics": performance_summary, | |
| "timestamp": datetime.utcnow().isoformat() | |
| } | |
| async def execute_individual_test(self, test_case: TestCase) -> TestResult: | |
| """Execute an individual test case.""" | |
| print(f"\n🔍 Executing individual test: {test_case.name}") | |
| # Create a temporary suite for the individual test | |
| temp_suite = TestSuite( | |
| suite_id=f"temp_{uuid.uuid4().hex[:8]}", | |
| name=f"Individual Test: {test_case.name}", | |
| description=f"Individual test execution for {test_case.name}", | |
| test_cases=[test_case] | |
| ) | |
| # Execute the test | |
| results = await self.execute_test_suite(temp_suite) | |
| return results["results"][0] if results["results"] else None | |
| async def run_user_journey_tests(self) -> Dict[str, Any]: | |
| """Run comprehensive user journey tests.""" | |
| print("\n🚀 Running User Journey Tests") | |
| # Create user journey test suite | |
| user_journey_tests = [ | |
| TestCase( | |
| test_id="budget_traveler_journey", | |
| name="Budget Traveler Journey", | |
| description="Test complete journey for budget traveler", | |
| test_type=TestType.USER_JOURNEY, | |
| test_function=self._test_budget_traveler_journey | |
| ), | |
| TestCase( | |
| test_id="luxury_traveler_journey", | |
| name="Luxury Traveler Journey", | |
| description="Test complete journey for luxury traveler", | |
| test_type=TestType.USER_JOURNEY, | |
| test_function=self._test_luxury_traveler_journey | |
| ), | |
| TestCase( | |
| test_id="family_traveler_journey", | |
| name="Family Traveler Journey", | |
| description="Test complete journey for family traveler", | |
| test_type=TestType.USER_JOURNEY, | |
| test_function=self._test_family_traveler_journey | |
| ) | |
| ] | |
| suite = TestSuite( | |
| suite_id="user_journey_tests", | |
| name="User Journey Test Suite", | |
| description="Comprehensive user journey testing", | |
| test_cases=user_journey_tests | |
| ) | |
| return await self.execute_test_suite(suite) | |
| async def run_stress_tests(self) -> Dict[str, Any]: | |
| """Run stress tests to validate system performance under load.""" | |
| print("\n💪 Running Stress Tests") | |
| stress_tests = [ | |
| TestCase( | |
| test_id="high_load_test", | |
| name="High Load Test", | |
| description="Test system performance under high load", | |
| test_type=TestType.STRESS, | |
| test_function=self._test_high_load, | |
| timeout=300 # 5 minutes timeout | |
| ), | |
| TestCase( | |
| test_id="resource_constraint_test", | |
| name="Resource Constraint Test", | |
| description="Test system behavior under resource constraints", | |
| test_type=TestType.STRESS, | |
| test_function=self._test_resource_constraints | |
| ), | |
| TestCase( | |
| test_id="concurrent_user_test", | |
| name="Concurrent User Test", | |
| description="Test multiple concurrent users", | |
| test_type=TestType.STRESS, | |
| test_function=self._test_concurrent_users | |
| ) | |
| ] | |
| suite = TestSuite( | |
| suite_id="stress_tests", | |
| name="Stress Test Suite", | |
| description="System stress testing and performance validation", | |
| test_cases=stress_tests | |
| ) | |
| return await self.execute_test_suite(suite) | |
| async def run_performance_tests(self) -> Dict[str, Any]: | |
| """Run performance tests to measure system metrics.""" | |
| print("\n⚡ Running Performance Tests") | |
| performance_tests = [ | |
| TestCase( | |
| test_id="response_time_test", | |
| name="Response Time Test", | |
| description="Measure system response times", | |
| test_type=TestType.PERFORMANCE, | |
| test_function=self._test_response_times | |
| ), | |
| TestCase( | |
| test_id="throughput_test", | |
| name="Throughput Test", | |
| description="Measure system throughput", | |
| test_type=TestType.PERFORMANCE, | |
| test_function=self._test_throughput | |
| ), | |
| TestCase( | |
| test_id="memory_usage_test", | |
| name="Memory Usage Test", | |
| description="Monitor memory usage patterns", | |
| test_type=TestType.PERFORMANCE, | |
| test_function=self._test_memory_usage | |
| ) | |
| ] | |
| suite = TestSuite( | |
| suite_id="performance_tests", | |
| name="Performance Test Suite", | |
| description="System performance measurement and analysis", | |
| test_cases=performance_tests | |
| ) | |
| return await self.execute_test_suite(suite) | |
| async def generate_test_report(self) -> Dict[str, Any]: | |
| """Generate a comprehensive test report.""" | |
| print("\n📊 Generating Comprehensive Test Report") | |
| # Collect all test results | |
| all_results = self.framework.test_results | |
| # Calculate summary statistics | |
| total_tests = len(all_results) | |
| passed_tests = sum(1 for r in all_results if r.result == TestResult.PASSED) | |
| failed_tests = sum(1 for r in all_results if r.result == TestResult.FAILED) | |
| error_tests = sum(1 for r in all_results if r.result == TestResult.ERROR) | |
| # Performance metrics | |
| performance_summary = self.performance_monitor.get_summary() | |
| # Generate report | |
| report = { | |
| "execution_summary": { | |
| "total_tests": total_tests, | |
| "passed": passed_tests, | |
| "failed": failed_tests, | |
| "errors": error_tests, | |
| "success_rate": (passed_tests / total_tests * 100) if total_tests > 0 else 0, | |
| "execution_time": sum(r.duration for r in all_results), | |
| "average_test_duration": sum(r.duration for r in all_results) / total_tests if total_tests > 0 else 0 | |
| }, | |
| "performance_metrics": performance_summary, | |
| "test_results": [ | |
| { | |
| "test_id": r.test_id, | |
| "result": r.result.value, | |
| "duration": r.duration, | |
| "error_message": r.error_message, | |
| "metrics": r.metrics | |
| } | |
| for r in all_results | |
| ], | |
| "recommendations": self._generate_recommendations(all_results, performance_summary) | |
| } | |
| return report | |
| def _generate_recommendations(self, results: List[TestResult], performance: Dict[str, Any]) -> List[str]: | |
| """Generate recommendations based on test results and performance.""" | |
| recommendations = [] | |
| # Analyze test results | |
| failed_tests = [r for r in results if r.result == TestResult.FAILED] | |
| if failed_tests: | |
| recommendations.append(f"Address {len(failed_tests)} failed tests to improve system reliability") | |
| # Analyze performance | |
| if "response_time" in performance: | |
| avg_response = performance["response_time"]["avg"] | |
| if avg_response > 2.0: | |
| recommendations.append("Consider optimizing response times - current average exceeds 2 seconds") | |
| if "memory_usage" in performance: | |
| max_memory = performance["memory_usage"]["max"] | |
| if max_memory > 1024: # 1GB | |
| recommendations.append("Monitor memory usage - peak usage exceeds 1GB") | |
| return recommendations | |
| # Test implementation methods | |
| async def _test_budget_traveler_journey(self) -> bool: | |
| """Test budget traveler journey.""" | |
| request = self.framework.test_data["budget_traveler"] | |
| # Execute trip planning | |
| result = await self.framework.orchestrator.orchestrate_trip_planning(request) | |
| # Validate results | |
| success = ( | |
| result["success"] and | |
| "flight" in result["results"] and | |
| "hotel" in result["results"] and | |
| result["results"]["flight"].status == AgentStatus.SUCCESS and | |
| result["results"]["hotel"].status == AgentStatus.SUCCESS | |
| ) | |
| self.performance_monitor.record_metric("budget_journey_duration", result.get("execution_time", 0)) | |
| return success | |
| async def _test_luxury_traveler_journey(self) -> bool: | |
| """Test luxury traveler journey.""" | |
| request = self.framework.test_data["luxury_traveler"] | |
| # Execute trip planning | |
| result = await self.framework.orchestrator.orchestrate_trip_planning(request) | |
| # Validate results | |
| success = ( | |
| result["success"] and | |
| "flight" in result["results"] and | |
| "hotel" in result["results"] and | |
| result["results"]["flight"].status == AgentStatus.SUCCESS and | |
| result["results"]["hotel"].status == AgentStatus.SUCCESS | |
| ) | |
| self.performance_monitor.record_metric("luxury_journey_duration", result.get("execution_time", 0)) | |
| return success | |
| async def _test_family_traveler_journey(self) -> bool: | |
| """Test family traveler journey.""" | |
| request = self.framework.test_data["family_traveler"] | |
| # Execute trip planning | |
| result = await self.framework.orchestrator.orchestrate_trip_planning(request) | |
| # Validate results | |
| success = ( | |
| result["success"] and | |
| "flight" in result["results"] and | |
| "hotel" in result["results"] and | |
| result["results"]["flight"].status == AgentStatus.SUCCESS and | |
| result["results"]["hotel"].status == AgentStatus.SUCCESS | |
| ) | |
| self.performance_monitor.record_metric("family_journey_duration", result.get("execution_time", 0)) | |
| return success | |
| async def _test_high_load(self) -> bool: | |
| """Test system under high load.""" | |
| # Simulate high load by running multiple concurrent requests | |
| tasks = [] | |
| for i in range(50): # 50 concurrent requests | |
| request = self.framework.test_data["budget_traveler"] | |
| task = self.framework.orchestrator.orchestrate_trip_planning(request) | |
| tasks.append(task) | |
| # Execute all requests concurrently | |
| results = await asyncio.gather(*tasks, return_exceptions=True) | |
| # Count successful results | |
| successful_results = sum(1 for r in results if isinstance(r, dict) and r.get("success", False)) | |
| success_rate = successful_results / len(results) | |
| self.performance_monitor.record_metric("high_load_success_rate", success_rate) | |
| return success_rate >= 0.95 # 95% success rate threshold | |
| async def _test_resource_constraints(self) -> bool: | |
| """Test system behavior under resource constraints.""" | |
| # This is a simplified test - in reality, you'd implement actual resource constraints | |
| start_time = time.time() | |
| # Run a complex request | |
| request = self.framework.test_data["business_traveler"] | |
| result = await self.framework.orchestrator.orchestrate_trip_planning(request) | |
| execution_time = time.time() - start_time | |
| self.performance_monitor.record_metric("resource_constraint_execution_time", execution_time) | |
| return result["success"] and execution_time < 10.0 # Should complete within 10 seconds | |
| async def _test_concurrent_users(self) -> bool: | |
| """Test multiple concurrent users.""" | |
| # Simulate 10 concurrent users | |
| tasks = [] | |
| for i in range(10): | |
| user_type = ["budget_traveler", "luxury_traveler", "family_traveler"][i % 3] | |
| request = self.framework.test_data[user_type] | |
| task = self.framework.orchestrator.orchestrate_trip_planning(request) | |
| tasks.append(task) | |
| # Execute concurrently | |
| results = await asyncio.gather(*tasks, return_exceptions=True) | |
| successful_results = sum(1 for r in results if isinstance(r, dict) and r.get("success", False)) | |
| success_rate = successful_results / len(results) | |
| self.performance_monitor.record_metric("concurrent_users_success_rate", success_rate) | |
| return success_rate >= 0.90 # 90% success rate threshold | |
| async def _test_response_times(self) -> bool: | |
| """Test system response times.""" | |
| response_times = [] | |
| # Test multiple requests | |
| for i in range(10): | |
| start_time = time.time() | |
| request = self.framework.test_data["budget_traveler"] | |
| result = await self.framework.orchestrator.orchestrate_trip_planning(request) | |
| response_time = time.time() - start_time | |
| response_times.append(response_time) | |
| avg_response_time = sum(response_times) / len(response_times) | |
| self.performance_monitor.record_metric("response_time", avg_response_time) | |
| return avg_response_time < 5.0 # Should respond within 5 seconds | |
| async def _test_throughput(self) -> bool: | |
| """Test system throughput.""" | |
| start_time = time.time() | |
| # Execute multiple requests sequentially | |
| for i in range(20): | |
| request = self.framework.test_data["budget_traveler"] | |
| await self.framework.orchestrator.orchestrate_trip_planning(request) | |
| total_time = time.time() - start_time | |
| throughput = 20 / total_time # requests per second | |
| self.performance_monitor.record_metric("throughput", throughput) | |
| return throughput >= 2.0 # At least 2 requests per second | |
| async def _test_memory_usage(self) -> bool: | |
| """Test memory usage patterns.""" | |
| import psutil | |
| import os | |
| process = psutil.Process(os.getpid()) | |
| memory_before = process.memory_info().rss / 1024 / 1024 # MB | |
| # Execute multiple requests to test memory usage | |
| for i in range(50): | |
| request = self.framework.test_data["budget_traveler"] | |
| await self.framework.orchestrator.orchestrate_trip_planning(request) | |
| memory_after = process.memory_info().rss / 1024 / 1024 # MB | |
| memory_increase = memory_after - memory_before | |
| self.performance_monitor.record_metric("memory_usage", memory_after) | |
| self.performance_monitor.record_metric("memory_increase", memory_increase) | |
| return memory_increase < 100 # Less than 100MB increase | |
| # Export key classes and functions | |
| __all__ = [ | |
| 'ComprehensiveTestFramework', | |
| 'TestSuite', | |
| 'TestCase', | |
| 'TestResult', | |
| 'TestExecutionResult', | |
| 'TestType', | |
| 'TestScenario', | |
| 'UserType', | |
| 'TestExecution', | |
| 'TestMetrics', | |
| 'TestDataGenerator', | |
| 'PerformanceMonitor', | |
| 'TestExecutor' | |
| ] | |