findEthics/Atlas
0
1#!/usr/bin/env python32"""3Performance tests for user authentication feature4 5This test file focuses on performance testing of user_id queries, indexes,6and analytics functions to ensure the user authentication feature doesn't7negatively impact system performance.8"""9 10import sys11import os12sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))13 14# Load environment variables15try:16 from dotenv import load_dotenv17 load_dotenv()18except ImportError:19 pass # dotenv not available, continue without it20 21import asyncio22import time23import random24import string25from datetime import datetime, timedelta26from typing import List, Dict, Any27 28from analytics.collectors import create_session, track_message, track_search29from analytics.dashboard import (30 get_user_statistics,31 get_user_analytics,32 get_authenticated_vs_anonymous_metrics,33 get_basic_stats,34 get_hourly_message_stats35)36from analytics.database import (37 get_sessions_collection,38 get_messages_collection,39 get_search_analytics_collection40)41 42 43class TestDatabaseIndexPerformance:44 """Test performance of database indexes for user_id queries"""45 46 async def test_user_id_index_performance(self):47 """Test performance of user_id index queries"""48 print("๐ Testing user_id index performance...")49 50 # Create test data with multiple users51 user_ids = [f"perf_user_{i}" for i in range(20)]52 sessions_per_user = 353 messages_per_session = 554 55 print(f"Creating test data: {len(user_ids)} users, {sessions_per_user} sessions each, {messages_per_session} messages each")56 57 # Create test data58 start_time = time.time()59 all_sessions = []60 61 for user_id in user_ids:62 for session_num in range(sessions_per_user):63 session = await create_session(user_id=user_id)64 all_sessions.append((session, user_id))65 66 for msg_num in range(messages_per_session):67 await track_message(68 session_id=session.session_id,69 prompt_length=random.randint(20, 100),70 response_length=random.randint(50, 200),71 response_time_ms=random.randint(500, 2000),72 used_search=random.choice([True, False]),73 user_id=user_id74 )75 76 data_creation_time = time.time() - start_time77 print(f"โ
Test data created in {data_creation_time:.2f} seconds")78 79 # Test query performance80 sessions_collection = await get_sessions_collection()81 messages_collection = await get_messages_collection()82 83 if sessions_collection and messages_collection:84 # Test individual user queries85 print("Testing individual user queries...")86 start_time = time.time()87 88 for user_id in user_ids:89 user_sessions = await sessions_collection.count_documents({"user_id": user_id})90 assert user_sessions == sessions_per_user91 92 user_messages = await messages_collection.count_documents({"user_id": user_id})93 assert user_messages == sessions_per_user * messages_per_session94 95 individual_query_time = time.time() - start_time96 avg_query_time = individual_query_time / len(user_ids)97 98 print(f"โ
Individual user queries: {individual_query_time:.2f}s total, {avg_query_time:.4f}s average")99 100 # Performance assertion101 assert avg_query_time < 0.1, f"Individual queries too slow: {avg_query_time:.4f}s average"102 103 # Test bulk queries104 print("Testing bulk user queries...")105 start_time = time.time()106 107 # Query all authenticated sessions108 auth_sessions = await sessions_collection.count_documents({"user_id": {"$ne": None}})109 assert auth_sessions == len(user_ids) * sessions_per_user110 111 # Query all authenticated messages112 auth_messages = await messages_collection.count_documents({"user_id": {"$ne": None}})113 assert auth_messages == len(user_ids) * sessions_per_user * messages_per_session114 115 bulk_query_time = time.time() - start_time116 print(f"โ
Bulk queries: {bulk_query_time:.2f}s")117 118 # Performance assertion119 assert bulk_query_time < 2.0, f"Bulk queries too slow: {bulk_query_time:.2f}s"120 121 else:122 print("โ ๏ธ Database not available - skipping index performance test")123 124 async def test_compound_index_performance(self):125 """Test performance of compound (user_id, timestamp) index queries"""126 print("๐ Testing compound index performance...")127 128 # Create test data with timestamps spread over time129 user_id = "compound_perf_user"130 session = await create_session(user_id=user_id)131 132 num_messages = 100133 print(f"Creating {num_messages} messages with varied timestamps...")134 135 start_time = time.time()136 base_time = datetime.utcnow()137 138 for i in range(num_messages):139 # Create messages with timestamps spread over the last 24 hours140 timestamp_offset = timedelta(hours=random.uniform(0, 24))141 message_time = base_time - timestamp_offset142 143 await track_message(144 session_id=session.session_id,145 prompt_length=50,146 response_length=100,147 response_time_ms=1000,148 user_id=user_id149 )150 151 # Small delay to ensure different timestamps152 await asyncio.sleep(0.001)153 154 data_creation_time = time.time() - start_time155 print(f"โ
Test data created in {data_creation_time:.2f} seconds")156 157 # Test compound queries158 messages_collection = await get_messages_collection()159 160 if messages_collection:161 # Test various time range queries162 time_ranges = [163 ("1 hour", timedelta(hours=1)),164 ("6 hours", timedelta(hours=6)),165 ("12 hours", timedelta(hours=12)),166 ("24 hours", timedelta(hours=24))167 ]168 169 for range_name, time_delta in time_ranges:170 start_time = time.time()171 cutoff_time = datetime.utcnow() - time_delta172 173 recent_messages = await messages_collection.count_documents({174 "user_id": user_id,175 "timestamp": {"$gte": cutoff_time}176 })177 178 query_time = time.time() - start_time179 print(f"โ
{range_name} query: {query_time:.4f}s ({recent_messages} messages)")180 181 # Performance assertion182 assert query_time < 0.5, f"{range_name} query too slow: {query_time:.4f}s"183 184 else:185 print("โ ๏ธ Database not available - skipping compound index test")186 187 async def test_sparse_index_performance(self):188 """Test performance of sparse indexes with mixed null/non-null user_id values"""189 print("๐ Testing sparse index performance...")190 191 # Create mixed data (authenticated and anonymous)192 num_auth_users = 10193 num_anon_sessions = 20194 messages_per_session = 5195 196 print(f"Creating mixed data: {num_auth_users} auth users, {num_anon_sessions} anon sessions")197 198 start_time = time.time()199 200 # Create authenticated user data201 auth_sessions = []202 for i in range(num_auth_users):203 user_id = f"sparse_user_{i}"204 session = await create_session(user_id=user_id)205 auth_sessions.append(session)206 207 for j in range(messages_per_session):208 await track_message(209 session_id=session.session_id,210 prompt_length=50,211 response_length=100,212 response_time_ms=1000,213 user_id=user_id214 )215 216 # Create anonymous user data217 anon_sessions = []218 for i in range(num_anon_sessions):219 session = await create_session(user_id=None)220 anon_sessions.append(session)221 222 for j in range(messages_per_session):223 await track_message(224 session_id=session.session_id,225 prompt_length=50,226 response_length=100,227 response_time_ms=1000,228 user_id=None229 )230 231 data_creation_time = time.time() - start_time232 print(f"โ
Mixed data created in {data_creation_time:.2f} seconds")233 234 # Test sparse index queries235 sessions_collection = await get_sessions_collection()236 messages_collection = await get_messages_collection()237 238 if sessions_collection and messages_collection:239 # Test authenticated user queries240 start_time = time.time()241 auth_session_count = await sessions_collection.count_documents({"user_id": {"$ne": None}})242 auth_query_time = time.time() - start_time243 244 assert auth_session_count >= num_auth_users245 print(f"โ
Authenticated sessions query: {auth_query_time:.4f}s ({auth_session_count} sessions)")246 247 # Test anonymous user queries248 start_time = time.time()249 anon_session_count = await sessions_collection.count_documents({"user_id": None})250 anon_query_time = time.time() - start_time251 252 assert anon_session_count >= num_anon_sessions253 print(f"โ
Anonymous sessions query: {anon_query_time:.4f}s ({anon_session_count} sessions)")254 255 # Test specific user queries256 start_time = time.time()257 specific_user_sessions = await sessions_collection.count_documents({"user_id": "sparse_user_0"})258 specific_query_time = time.time() - start_time259 260 assert specific_user_sessions == 1261 print(f"โ
Specific user query: {specific_query_time:.4f}s")262 263 # Performance assertions264 assert auth_query_time < 0.5, f"Auth query too slow: {auth_query_time:.4f}s"265 assert anon_query_time < 0.5, f"Anon query too slow: {anon_query_time:.4f}s"266 assert specific_query_time < 0.1, f"Specific query too slow: {specific_query_time:.4f}s"267 268 else:269 print("โ ๏ธ Database not available - skipping sparse index test")270 271 272class TestAnalyticsFunctionPerformance:273 """Test performance of analytics functions with user authentication"""274 275 async def test_user_statistics_performance(self):276 """Test performance of get_user_statistics function"""277 print("๐ Testing user statistics performance...")278 279 # Create test data280 await self._create_performance_test_data()281 282 # Test get_user_statistics performance283 start_time = time.time()284 user_stats = await get_user_statistics()285 stats_time = time.time() - start_time286 287 assert isinstance(user_stats, dict)288 assert "unique_authenticated_users" in user_stats289 assert "authenticated_sessions" in user_stats290 assert "anonymous_sessions" in user_stats291 292 print(f"โ
User statistics query: {stats_time:.4f}s")293 294 # Performance assertion295 assert stats_time < 5.0, f"User statistics too slow: {stats_time:.4f}s"296 297 async def test_user_analytics_performance(self):298 """Test performance of get_user_analytics function"""299 print("๐ Testing individual user analytics performance...")300 301 # Create test user with substantial data302 user_id = "analytics_perf_user"303 session = await create_session(user_id=user_id)304 305 # Create many messages for this user306 num_messages = 50307 print(f"Creating {num_messages} messages for performance test...")308 309 for i in range(num_messages):310 await track_message(311 session_id=session.session_id,312 prompt_length=random.randint(20, 100),313 response_length=random.randint(50, 200),314 response_time_ms=random.randint(500, 2000),315 used_search=random.choice([True, False]),316 user_id=user_id317 )318 319 # Test get_user_analytics performance320 start_time = time.time()321 user_analytics = await get_user_analytics(user_id)322 analytics_time = time.time() - start_time323 324 assert isinstance(user_analytics, dict)325 assert user_analytics.get("user_id") == user_id326 assert user_analytics.get("total_messages") == num_messages327 328 print(f"โ
User analytics query: {analytics_time:.4f}s")329 330 # Performance assertion331 assert analytics_time < 3.0, f"User analytics too slow: {analytics_time:.4f}s"332 333 async def test_authenticated_vs_anonymous_performance(self):334 """Test performance of get_authenticated_vs_anonymous_metrics function"""335 print("๐ Testing authenticated vs anonymous metrics performance...")336 337 # Create mixed test data338 await self._create_performance_test_data()339 340 # Test get_authenticated_vs_anonymous_metrics performance341 start_time = time.time()342 comparison_metrics = await get_authenticated_vs_anonymous_metrics()343 comparison_time = time.time() - start_time344 345 assert isinstance(comparison_metrics, dict)346 assert "authenticated" in comparison_metrics347 assert "anonymous" in comparison_metrics348 assert "comparison" in comparison_metrics349 350 print(f"โ
Comparison metrics query: {comparison_time:.4f}s")351 352 # Performance assertion353 assert comparison_time < 5.0, f"Comparison metrics too slow: {comparison_time:.4f}s"354 355 async def test_basic_stats_with_filter_performance(self):356 """Test performance of get_basic_stats with user_id filter"""357 print("๐ Testing filtered basic stats performance...")358 359 # Create test data360 await self._create_performance_test_data()361 362 # Test unfiltered stats363 start_time = time.time()364 all_stats = await get_basic_stats()365 all_stats_time = time.time() - start_time366 367 print(f"โ
Unfiltered basic stats: {all_stats_time:.4f}s")368 369 # Test filtered stats370 start_time = time.time()371 filtered_stats = await get_basic_stats(user_id="perf_test_user_0")372 filtered_stats_time = time.time() - start_time373 374 assert "filtered_by_user_id" in filtered_stats375 print(f"โ
Filtered basic stats: {filtered_stats_time:.4f}s")376 377 # Performance assertions378 assert all_stats_time < 3.0, f"Unfiltered stats too slow: {all_stats_time:.4f}s"379 assert filtered_stats_time < 2.0, f"Filtered stats too slow: {filtered_stats_time:.4f}s"380 381 async def test_hourly_stats_with_filter_performance(self):382 """Test performance of get_hourly_message_stats with user_id filter"""383 print("๐ Testing filtered hourly stats performance...")384 385 # Create test data386 await self._create_performance_test_data()387 388 # Test unfiltered hourly stats389 start_time = time.time()390 all_hourly = await get_hourly_message_stats(hours=24)391 all_hourly_time = time.time() - start_time392 393 print(f"โ
Unfiltered hourly stats: {all_hourly_time:.4f}s")394 395 # Test filtered hourly stats396 start_time = time.time()397 filtered_hourly = await get_hourly_message_stats(hours=24, user_id="perf_test_user_0")398 filtered_hourly_time = time.time() - start_time399 400 print(f"โ
Filtered hourly stats: {filtered_hourly_time:.4f}s")401 402 # Performance assertions403 assert all_hourly_time < 3.0, f"Unfiltered hourly stats too slow: {all_hourly_time:.4f}s"404 assert filtered_hourly_time < 2.0, f"Filtered hourly stats too slow: {filtered_hourly_time:.4f}s"405 406 async def _create_performance_test_data(self):407 """Create test data for performance testing"""408 # Create authenticated users409 for i in range(5):410 user_id = f"perf_test_user_{i}"411 session = await create_session(user_id=user_id)412 413 # Create messages for each user414 for j in range(10):415 await track_message(416 session_id=session.session_id,417 prompt_length=random.randint(20, 100),418 response_length=random.randint(50, 200),419 response_time_ms=random.randint(500, 2000),420 used_search=random.choice([True, False]),421 user_id=user_id422 )423 424 # Create anonymous users425 for i in range(3):426 session = await create_session(user_id=None)427 428 # Create messages for anonymous users429 for j in range(8):430 await track_message(431 session_id=session.session_id,432 prompt_length=random.randint(20, 100),433 response_length=random.randint(50, 200),434 response_time_ms=random.randint(500, 2000),435 used_search=random.choice([True, False]),436 user_id=None437 )438 439 440class TestConcurrentUserPerformance:441 """Test performance with concurrent user operations"""442 443 async def test_concurrent_user_creation(self):444 """Test performance of concurrent user session creation"""445 print("๐ Testing concurrent user creation performance...")446 447 num_concurrent_users = 20448 449 async def create_user_session(user_id: str):450 session = await create_session(user_id=user_id)451 452 # Create a few messages for each user453 for i in range(3):454 await track_message(455 session_id=session.session_id,456 prompt_length=50,457 response_length=100,458 response_time_ms=1000,459 user_id=user_id460 )461 462 return session463 464 # Create concurrent tasks465 start_time = time.time()466 tasks = [467 create_user_session(f"concurrent_user_{i}")468 for i in range(num_concurrent_users)469 ]470 471 sessions = await asyncio.gather(*tasks)472 concurrent_time = time.time() - start_time473 474 assert len(sessions) == num_concurrent_users475 print(f"โ
Concurrent user creation: {concurrent_time:.2f}s for {num_concurrent_users} users")476 477 # Performance assertion478 avg_time_per_user = concurrent_time / num_concurrent_users479 assert avg_time_per_user < 1.0, f"Concurrent creation too slow: {avg_time_per_user:.2f}s per user"480 481 async def test_concurrent_user_queries(self):482 """Test performance of concurrent user-specific queries"""483 print("๐ Testing concurrent user query performance...")484 485 # Create test users first486 user_ids = [f"query_user_{i}" for i in range(10)]487 488 for user_id in user_ids:489 session = await create_session(user_id=user_id)490 await track_message(491 session_id=session.session_id,492 prompt_length=50,493 response_length=100,494 response_time_ms=1000,495 user_id=user_id496 )497 498 # Test concurrent queries499 async def query_user_analytics(user_id: str):500 return await get_user_analytics(user_id)501 502 start_time = time.time()503 tasks = [query_user_analytics(user_id) for user_id in user_ids]504 results = await asyncio.gather(*tasks)505 concurrent_query_time = time.time() - start_time506 507 assert len(results) == len(user_ids)508 for i, result in enumerate(results):509 assert result.get("user_id") == user_ids[i]510 511 print(f"โ
Concurrent user queries: {concurrent_query_time:.2f}s for {len(user_ids)} users")512 513 # Performance assertion514 avg_query_time = concurrent_query_time / len(user_ids)515 assert avg_query_time < 0.5, f"Concurrent queries too slow: {avg_query_time:.2f}s per query"516 517 518class TestMemoryPerformance:519 """Test memory usage with user authentication"""520 521 async def test_memory_usage_with_users(self):522 """Test that user_id fields don't significantly increase memory usage"""523 print("๐พ Testing memory usage with user authentication...")524 525 import psutil526 import os527 528 # Get initial memory usage529 process = psutil.Process(os.getpid())530 initial_memory = process.memory_info().rss / 1024 / 1024 # MB531 532 # Create substantial amount of data533 num_users = 50534 messages_per_user = 20535 536 print(f"Creating {num_users} users with {messages_per_user} messages each...")537 538 for i in range(num_users):539 user_id = f"memory_test_user_{i}"540 session = await create_session(user_id=user_id)541 542 for j in range(messages_per_user):543 await track_message(544 session_id=session.session_id,545 prompt_length=50,546 response_length=100,547 response_time_ms=1000,548 user_id=user_id549 )550 551 # Get final memory usage552 final_memory = process.memory_info().rss / 1024 / 1024 # MB553 memory_increase = final_memory - initial_memory554 555 print(f"โ
Memory usage: {initial_memory:.1f}MB โ {final_memory:.1f}MB (+{memory_increase:.1f}MB)")556 557 # Memory increase should be reasonable558 total_records = num_users * (1 + messages_per_user) # sessions + messages559 memory_per_record = memory_increase / total_records560 561 print(f"โ
Memory per record: {memory_per_record:.3f}MB")562 563 # Performance assertion (should be less than 1MB per record)564 assert memory_per_record < 1.0, f"Memory usage too high: {memory_per_record:.3f}MB per record"565 566 567async def run_performance_tests():568 """Run all performance tests"""569 print("โก Running Performance Tests for User Authentication")570 print("=" * 60)571 572 # Test database index performance573 index_test = TestDatabaseIndexPerformance()574 await index_test.test_user_id_index_performance()575 await index_test.test_compound_index_performance()576 await index_test.test_sparse_index_performance()577 print("โ
Database index performance tests completed")578 579 # Test analytics function performance580 analytics_test = TestAnalyticsFunctionPerformance()581 await analytics_test.test_user_statistics_performance()582 await analytics_test.test_user_analytics_performance()583 await analytics_test.test_authenticated_vs_anonymous_performance()584 await analytics_test.test_basic_stats_with_filter_performance()585 await analytics_test.test_hourly_stats_with_filter_performance()586 print("โ
Analytics function performance tests completed")587 588 # Test concurrent performance589 concurrent_test = TestConcurrentUserPerformance()590 await concurrent_test.test_concurrent_user_creation()591 await concurrent_test.test_concurrent_user_queries()592 print("โ
Concurrent performance tests completed")593 594 # Test memory performance595 memory_test = TestMemoryPerformance()596 await memory_test.test_memory_usage_with_users()597 print("โ
Memory performance tests completed")598 599 print("\n๐ ALL PERFORMANCE TESTS COMPLETED!")600 print("User authentication feature maintains good performance characteristics.")601 602 603if __name__ == "__main__":604 asyncio.run(run_performance_tests())