#!/usr/bin/env python3 """ End-to-end tests for PyGuardian system. """ import unittest import tempfile import os import sys import json import time import subprocess import requests from datetime import datetime # Add src directory to path sys.path.insert(0, os.path.join(os.path.dirname(__file__), '../../src')) class TestE2EWorkflow(unittest.TestCase): """End-to-end workflow tests.""" def setUp(self): """Set up test fixtures.""" self.temp_dir = tempfile.mkdtemp() self.test_config = { 'api_host': 'localhost', 'api_port': 8080, 'agent_port': 8081 } def tearDown(self): """Clean up test fixtures.""" os.rmdir(self.temp_dir) def test_agent_registration_workflow(self): """Test complete agent registration workflow.""" # Step 1: Agent requests registration registration_data = { 'agent_name': 'test-agent-e2e', 'hostname': 'test-host.local', 'ip_address': '192.168.1.100', 'host_info': { 'os': 'Linux', 'arch': 'x86_64', 'kernel': '5.4.0-74-generic' } } # Simulate registration request self.assertIsNotNone(registration_data['agent_name']) self.assertIsNotNone(registration_data['hostname']) # Step 2: Controller generates credentials agent_id = f"agent_{registration_data['agent_name']}_123456" credentials = { 'agent_id': agent_id, 'secret_key': 'generated_secret_key_here', 'api_endpoint': f"https://{self.test_config['api_host']}:{self.test_config['api_port']}" } self.assertEqual(credentials['agent_id'], agent_id) self.assertIsNotNone(credentials['secret_key']) # Step 3: Agent receives credentials and authenticates auth_request = { 'agent_id': credentials['agent_id'], 'secret_key': credentials['secret_key'] } # Simulate authentication jwt_token = "mocked.jwt.token.here" self.assertIsNotNone(jwt_token) # Step 4: Agent makes authenticated API requests api_request_headers = { 'Authorization': f'Bearer {jwt_token}', 'Content-Type': 'application/json' } self.assertTrue(api_request_headers['Authorization'].startswith('Bearer ')) # Step 5: Verify agent appears in cluster cluster_status = { 'total_agents': 1, 'active_agents': 1, 'agents': [ { 'agent_id': agent_id, 'status': 'active', 'last_seen': datetime.now().isoformat(), 'hostname': registration_data['hostname'] } ] } self.assertEqual(cluster_status['total_agents'], 1) self.assertEqual(cluster_status['active_agents'], 1) self.assertEqual(cluster_status['agents'][0]['agent_id'], agent_id) def test_security_incident_workflow(self): """Test security incident detection and response workflow.""" # Step 1: Simulate security event detection security_event = { 'event_type': 'brute_force_attack', 'source_ip': '203.0.113.100', 'target_service': 'ssh', 'attempts': 10, 'timestamp': datetime.now().isoformat(), 'severity': 'high' } self.assertEqual(security_event['event_type'], 'brute_force_attack') self.assertGreaterEqual(security_event['attempts'], 5) # Threshold # Step 2: Automatic threat analysis threat_analysis = { 'threat_level': 'high', 'recommended_action': 'block_ip', 'confidence': 0.95, 'similar_events': 3 } self.assertEqual(threat_analysis['threat_level'], 'high') self.assertGreater(threat_analysis['confidence'], 0.8) # Step 3: Automatic response execution response_action = { 'action': 'ip_block', 'target': security_event['source_ip'], 'duration': 3600, # 1 hour 'executed_at': datetime.now().isoformat(), 'success': True } self.assertEqual(response_action['action'], 'ip_block') self.assertEqual(response_action['target'], security_event['source_ip']) self.assertTrue(response_action['success']) # Step 4: Notification sent via Telegram notification = { 'type': 'security_alert', 'message': f"🚨 Blocked {security_event['source_ip']} due to {security_event['event_type']}", 'sent_at': datetime.now().isoformat(), 'delivered': True } self.assertEqual(notification['type'], 'security_alert') self.assertIn(security_event['source_ip'], notification['message']) self.assertTrue(notification['delivered']) # Step 5: Event logged for analysis log_entry = { 'event_id': 'evt_12345', 'original_event': security_event, 'analysis': threat_analysis, 'response': response_action, 'notification': notification, 'logged_at': datetime.now().isoformat() } self.assertIsNotNone(log_entry['event_id']) self.assertIsNotNone(log_entry['original_event']) self.assertIsNotNone(log_entry['response']) def test_cluster_health_monitoring(self): """Test cluster health monitoring workflow.""" # Step 1: Collect agent health data agent_health_data = [ { 'agent_id': 'agent_web01_123456', 'status': 'healthy', 'cpu_usage': 45.2, 'memory_usage': 62.8, 'disk_usage': 78.1, 'network_rx': 1024000, 'network_tx': 2048000, 'last_heartbeat': datetime.now().isoformat() }, { 'agent_id': 'agent_db01_789012', 'status': 'warning', 'cpu_usage': 85.7, 'memory_usage': 91.3, 'disk_usage': 45.6, 'network_rx': 512000, 'network_tx': 1024000, 'last_heartbeat': datetime.now().isoformat() } ] # Validate health data for agent in agent_health_data: self.assertIn('agent_id', agent) self.assertIn('status', agent) self.assertLessEqual(agent['cpu_usage'], 100) self.assertLessEqual(agent['memory_usage'], 100) self.assertLessEqual(agent['disk_usage'], 100) # Step 2: Analyze cluster health cluster_health = { 'total_agents': len(agent_health_data), 'healthy_agents': len([a for a in agent_health_data if a['status'] == 'healthy']), 'warning_agents': len([a for a in agent_health_data if a['status'] == 'warning']), 'critical_agents': len([a for a in agent_health_data if a['status'] == 'critical']), 'overall_status': 'warning', 'average_cpu': sum(a['cpu_usage'] for a in agent_health_data) / len(agent_health_data), 'average_memory': sum(a['memory_usage'] for a in agent_health_data) / len(agent_health_data) } self.assertEqual(cluster_health['total_agents'], 2) self.assertEqual(cluster_health['healthy_agents'], 1) self.assertEqual(cluster_health['warning_agents'], 1) self.assertLessEqual(cluster_health['average_cpu'], 100) # Step 3: Generate alerts for concerning metrics alerts = [] for agent in agent_health_data: if agent['cpu_usage'] > 80: alerts.append({ 'type': 'high_cpu', 'agent_id': agent['agent_id'], 'value': agent['cpu_usage'], 'threshold': 80 }) if agent['memory_usage'] > 90: alerts.append({ 'type': 'high_memory', 'agent_id': agent['agent_id'], 'value': agent['memory_usage'], 'threshold': 90 }) # Verify alerts were generated self.assertGreater(len(alerts), 0) cpu_alerts = [a for a in alerts if a['type'] == 'high_cpu'] memory_alerts = [a for a in alerts if a['type'] == 'high_memory'] self.assertEqual(len(cpu_alerts), 1) self.assertEqual(len(memory_alerts), 1) def test_backup_and_recovery(self): """Test backup and recovery workflow.""" # Step 1: Create backup backup_data = { 'backup_id': 'backup_20241125_123456', 'created_at': datetime.now().isoformat(), 'backup_type': 'full', 'components': [ 'configuration', 'agent_credentials', 'security_logs', 'cluster_state' ], 'size_bytes': 1024000, 'compressed': True } self.assertIsNotNone(backup_data['backup_id']) self.assertEqual(backup_data['backup_type'], 'full') self.assertIn('agent_credentials', backup_data['components']) # Step 2: Verify backup integrity integrity_check = { 'backup_id': backup_data['backup_id'], 'checksum': 'sha256_checksum_here', 'verification_passed': True, 'verified_at': datetime.now().isoformat() } self.assertTrue(integrity_check['verification_passed']) self.assertIsNotNone(integrity_check['checksum']) # Step 3: Simulate recovery scenario recovery_scenario = { 'scenario': 'controller_failure', 'recovery_method': 'restore_from_backup', 'backup_used': backup_data['backup_id'], 'recovery_time': 300, # seconds 'success': True } self.assertEqual(recovery_scenario['recovery_method'], 'restore_from_backup') self.assertTrue(recovery_scenario['success']) self.assertLess(recovery_scenario['recovery_time'], 600) # Under 10 minutes class TestPerformance(unittest.TestCase): """Performance and load tests.""" def setUp(self): """Set up test fixtures.""" self.temp_dir = tempfile.mkdtemp() def tearDown(self): """Clean up test fixtures.""" os.rmdir(self.temp_dir) def test_concurrent_agent_authentication(self): """Test concurrent agent authentication performance.""" # Simulate multiple agents authenticating simultaneously concurrent_agents = 50 authentication_times = [] for i in range(concurrent_agents): # Simulate authentication time start_time = time.time() # Mock authentication process agent_id = f"agent_load_test_{i:03d}" auth_result = { 'agent_id': agent_id, 'authenticated': True, 'token_generated': True } end_time = time.time() auth_time = end_time - start_time authentication_times.append(auth_time) self.assertTrue(auth_result['authenticated']) # Analyze performance avg_auth_time = sum(authentication_times) / len(authentication_times) max_auth_time = max(authentication_times) # Performance assertions self.assertLess(avg_auth_time, 1.0) # Average under 1 second self.assertLess(max_auth_time, 5.0) # Maximum under 5 seconds self.assertEqual(len(authentication_times), concurrent_agents) def test_api_throughput(self): """Test API request throughput.""" # Simulate high-frequency API requests total_requests = 1000 successful_requests = 0 failed_requests = 0 start_time = time.time() for i in range(total_requests): # Simulate API request processing request_success = True # Mock success if request_success: successful_requests += 1 else: failed_requests += 1 end_time = time.time() total_time = end_time - start_time # Calculate throughput requests_per_second = total_requests / total_time if total_time > 0 else 0 success_rate = successful_requests / total_requests # Performance assertions self.assertGreater(requests_per_second, 100) # At least 100 RPS self.assertGreaterEqual(success_rate, 0.95) # 95% success rate self.assertEqual(successful_requests + failed_requests, total_requests) def run_e2e_tests(): """Run all end-to-end tests.""" print("🎯 Running PyGuardian End-to-End Tests...") print("=" * 50) # Create test suite test_suite = unittest.TestSuite() # Add test classes test_classes = [ TestE2EWorkflow, TestPerformance ] for test_class in test_classes: tests = unittest.TestLoader().loadTestsFromTestCase(test_class) test_suite.addTests(tests) # Run tests runner = unittest.TextTestRunner(verbosity=2) result = runner.run(test_suite) # Print summary print("\n" + "=" * 50) print(f"🏁 E2E Tests completed:") print(f" ✅ Passed: {result.testsRun - len(result.failures) - len(result.errors)}") print(f" ❌ Failed: {len(result.failures)}") print(f" 💥 Errors: {len(result.errors)}") return 0 if result.wasSuccessful() else 1 if __name__ == '__main__': sys.exit(run_e2e_tests())