Spaces:
Sleeping
Sleeping
File size: 18,534 Bytes
7611990 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 | """
Regression tests for database operations and repositories
"""
import pytest
from unittest.mock import AsyncMock, MagicMock, patch
from typing import Dict, Any, List
import asyncio
class TestMongoDBOperations:
"""Test MongoDB database operations"""
@pytest.mark.asyncio
async def test_mongodb_connection_health(self):
"""Test MongoDB connection health check"""
from app.nosql import check_mongodb_health
with patch('app.nosql.db') as mock_db:
mock_db.command.return_value = {"ok": 1}
result = await check_mongodb_health()
assert result is True
@pytest.mark.asyncio
async def test_mongodb_connection_failure(self):
"""Test MongoDB connection failure handling"""
from app.nosql import check_mongodb_health
with patch('app.nosql.db') as mock_db:
mock_db.command.side_effect = Exception("Connection failed")
result = await check_mongodb_health()
assert result is False
@pytest.mark.asyncio
async def test_fetch_documents(self, sample_merchant_data):
"""Test retrieving documents from database"""
from app.repositories.db_repository import fetch_documents
with patch('app.nosql.db') as mock_db:
mock_collection = AsyncMock()
mock_db.__getitem__.return_value = mock_collection
mock_collection.count_documents.return_value = 1
mock_collection.find.return_value.skip.return_value.limit.return_value.to_list.return_value = [sample_merchant_data]
result = await fetch_documents("merchants", {}, {}, 0, 10)
assert result["total"] == 1
assert len(result["documents"]) == 1
assert result["documents"][0]["name"] == "Test Hair Salon"
@pytest.mark.asyncio
async def test_execute_query(self, sample_merchant_data):
"""Test executing aggregation query"""
from app.repositories.db_repository import execute_query
with patch('app.nosql.db') as mock_db:
mock_collection = AsyncMock()
mock_db.__getitem__.return_value = mock_collection
mock_collection.aggregate.return_value.to_list.return_value = [sample_merchant_data]
pipeline = [{"$match": {"_id": "test_merchant_123"}}]
result = await execute_query("merchants", pipeline, use_optimization=False)
assert len(result) == 1
assert result[0]["name"] == "Test Hair Salon"
@pytest.mark.asyncio
async def test_count_documents(self):
"""Test counting documents in collection"""
from app.repositories.db_repository import count_documents
with patch('app.nosql.db') as mock_db:
mock_collection = AsyncMock()
mock_db.__getitem__.return_value = mock_collection
mock_collection.count_documents.return_value = 5
result = await count_documents("merchants", {"category": "salon"})
assert result == 5
mock_collection.count_documents.assert_called_once_with({"category": "salon"})
@pytest.mark.asyncio
async def test_serialize_mongo_document(self):
"""Test MongoDB document serialization"""
from app.repositories.db_repository import serialize_mongo_document
from bson import ObjectId
from datetime import datetime
test_doc = {
"_id": ObjectId("507f1f77bcf86cd799439011"),
"name": "Test Merchant",
"created_at": datetime(2024, 1, 1, 12, 0, 0),
"nested": {
"id": ObjectId("507f1f77bcf86cd799439012"),
"date": datetime(2024, 1, 2, 12, 0, 0)
}
}
result = serialize_mongo_document(test_doc)
assert isinstance(result["_id"], str)
assert isinstance(result["created_at"], str)
assert isinstance(result["nested"]["id"], str)
assert isinstance(result["nested"]["date"], str)
class TestRedisOperations:
"""Test Redis cache operations"""
@pytest.mark.asyncio
async def test_redis_connection_health(self):
"""Test Redis connection health check"""
from app.nosql import check_redis_health
with patch('app.nosql.get_redis_client') as mock_client:
mock_redis = AsyncMock()
mock_client.return_value = mock_redis
mock_redis.ping.return_value = True
result = await check_redis_health()
assert result is True
@pytest.mark.asyncio
async def test_redis_connection_failure(self):
"""Test Redis connection failure handling"""
from app.nosql import check_redis_health
with patch('app.nosql.get_redis_client') as mock_client:
mock_client.side_effect = Exception("Redis connection failed")
result = await check_redis_health()
assert result is False
@pytest.mark.asyncio
async def test_cache_merchant_data(self, sample_merchant_data):
"""Test caching merchant data in Redis"""
from app.repositories.cache_repository import cache_merchant_data
with patch('app.nosql.get_redis_client') as mock_client:
mock_redis = AsyncMock()
mock_client.return_value = mock_redis
mock_redis.setex.return_value = True
result = await cache_merchant_data("test_merchant_123", sample_merchant_data)
assert result is True
mock_redis.setex.assert_called_once()
@pytest.mark.asyncio
async def test_cache_manager_get_or_set(self, sample_merchant_data):
"""Test cache manager get_or_set functionality"""
from app.repositories.cache_repository import cache_manager
import json
with patch('app.nosql.redis_client') as mock_redis:
mock_redis.get.return_value = None # Cache miss
mock_redis.set.return_value = True
async def fetch_func():
return sample_merchant_data
result = await cache_manager.get_or_set_cache("test_key", fetch_func)
assert result["name"] == "Test Hair Salon"
mock_redis.set.assert_called_once()
@pytest.mark.asyncio
async def test_cache_manager_hit(self, sample_merchant_data):
"""Test cache manager cache hit"""
from app.repositories.cache_repository import cache_manager
import json
with patch('app.nosql.redis_client') as mock_redis:
mock_redis.get.return_value = json.dumps(sample_merchant_data)
async def fetch_func():
return {"should": "not_be_called"}
result = await cache_manager.get_or_set_cache("test_key", fetch_func)
assert result["name"] == "Test Hair Salon"
mock_redis.get.assert_called_once()
@pytest.mark.asyncio
async def test_cache_manager_invalidate(self):
"""Test cache invalidation"""
from app.repositories.cache_repository import cache_manager
with patch('app.nosql.redis_client') as mock_redis:
mock_redis.delete.return_value = 1
await cache_manager.invalidate_cache("test_key")
mock_redis.delete.assert_called_once()
@pytest.mark.asyncio
async def test_invalidate_cache(self):
"""Test cache invalidation"""
from app.repositories.cache_repository import invalidate_cache
with patch('app.nosql.get_redis_client') as mock_client:
mock_redis = AsyncMock()
mock_client.return_value = mock_redis
mock_redis.delete.return_value = 1
result = await invalidate_cache("test_key")
assert result is True
mock_redis.delete.assert_called_once_with("test_key")
class TestDatabaseIndexes:
"""Test database indexing functionality"""
@pytest.mark.asyncio
async def test_create_geospatial_index(self):
"""Test creating geospatial index"""
from app.database.indexes import create_geospatial_index
with patch('app.nosql.get_mongodb_client') as mock_client:
mock_collection = MagicMock()
mock_client.return_value.__getitem__.return_value.__getitem__.return_value = mock_collection
mock_collection.create_index.return_value = "location_2dsphere"
result = await create_geospatial_index()
assert result == "location_2dsphere"
mock_collection.create_index.assert_called_once()
@pytest.mark.asyncio
async def test_create_text_search_index(self):
"""Test creating text search index"""
from app.database.indexes import create_text_search_index
with patch('app.nosql.get_mongodb_client') as mock_client:
mock_collection = MagicMock()
mock_client.return_value.__getitem__.return_value.__getitem__.return_value = mock_collection
mock_collection.create_index.return_value = "text_search_index"
result = await create_text_search_index()
assert result == "text_search_index"
mock_collection.create_index.assert_called_once()
@pytest.mark.asyncio
async def test_create_category_index(self):
"""Test creating category index"""
from app.database.indexes import create_category_index
with patch('app.nosql.get_mongodb_client') as mock_client:
mock_collection = MagicMock()
mock_client.return_value.__getitem__.return_value.__getitem__.return_value = mock_collection
mock_collection.create_index.return_value = "category_index"
result = await create_category_index()
assert result == "category_index"
mock_collection.create_index.assert_called_once()
class TestQueryOptimization:
"""Test database query optimization"""
@pytest.mark.asyncio
async def test_optimized_merchant_search(self, sample_merchant_data):
"""Test optimized merchant search query"""
from app.database.query_optimizer import optimize_search_query
search_params = {
"category": "salon",
"latitude": 40.7128,
"longitude": -74.0060,
"radius": 5000,
"min_rating": 4.0
}
optimized_query = optimize_search_query(search_params)
assert isinstance(optimized_query, dict)
assert "location" in optimized_query
assert "category" in optimized_query
assert "average_rating" in optimized_query
@pytest.mark.asyncio
async def test_query_performance_analysis(self):
"""Test query performance analysis"""
from app.database.query_optimizer import analyze_query_performance
with patch('app.nosql.get_mongodb_client') as mock_client:
mock_collection = MagicMock()
mock_client.return_value.__getitem__.return_value.__getitem__.return_value = mock_collection
# Mock explain output
mock_collection.find.return_value.explain.return_value = {
"executionStats": {
"totalDocsExamined": 100,
"totalDocsReturned": 10,
"executionTimeMillis": 50
}
}
query = {"category": "salon"}
result = await analyze_query_performance(query)
assert "executionStats" in result
assert result["executionStats"]["totalDocsExamined"] == 100
class TestDatabaseTransactions:
"""Test database transaction handling"""
@pytest.mark.asyncio
async def test_merchant_creation_transaction(self, sample_merchant_data):
"""Test merchant creation with transaction"""
from app.repositories.db_repository import create_merchant_with_transaction
with patch('app.nosql.get_mongodb_client') as mock_client:
mock_session = AsyncMock()
mock_client.return_value.start_session.return_value.__aenter__.return_value = mock_session
mock_collection = MagicMock()
mock_client.return_value.__getitem__.return_value.__getitem__.return_value = mock_collection
mock_collection.insert_one.return_value.inserted_id = "new_merchant_id"
result = await create_merchant_with_transaction(sample_merchant_data)
assert result == "new_merchant_id"
mock_session.start_transaction.assert_called_once()
@pytest.mark.asyncio
async def test_transaction_rollback(self, sample_merchant_data):
"""Test transaction rollback on error"""
from app.repositories.db_repository import create_merchant_with_transaction
with patch('app.nosql.get_mongodb_client') as mock_client:
mock_session = AsyncMock()
mock_client.return_value.start_session.return_value.__aenter__.return_value = mock_session
mock_collection = MagicMock()
mock_client.return_value.__getitem__.return_value.__getitem__.return_value = mock_collection
mock_collection.insert_one.side_effect = Exception("Insert failed")
with pytest.raises(Exception):
await create_merchant_with_transaction(sample_merchant_data)
mock_session.abort_transaction.assert_called_once()
class TestDatabasePerformance:
"""Test database performance characteristics"""
@pytest.mark.asyncio
async def test_concurrent_database_operations(self, sample_merchant_data):
"""Test concurrent database operations"""
from app.repositories.db_repository import get_merchant_by_id_from_db
with patch('app.nosql.get_mongodb_client') as mock_client:
mock_collection = MagicMock()
mock_client.return_value.__getitem__.return_value.__getitem__.return_value = mock_collection
mock_collection.find_one.return_value = sample_merchant_data
# Create multiple concurrent requests
tasks = [
get_merchant_by_id_from_db(f"merchant_{i}")
for i in range(20)
]
results = await asyncio.gather(*tasks)
assert len(results) == 20
assert all(result["name"] == "Test Hair Salon" for result in results)
@pytest.mark.asyncio
async def test_large_result_set_handling(self):
"""Test handling of large result sets"""
from app.repositories.db_repository import get_merchants_from_db
# Create mock data for large result set
large_dataset = [{"_id": f"merchant_{i}", "name": f"Merchant {i}"} for i in range(1000)]
with patch('app.nosql.get_mongodb_client') as mock_client:
mock_collection = MagicMock()
mock_client.return_value.__getitem__.return_value.__getitem__.return_value = mock_collection
mock_collection.find.return_value.limit.return_value.skip.return_value.to_list.return_value = large_dataset[:100]
result = await get_merchants_from_db(limit=100, skip=0)
assert len(result) == 100
# Verify pagination was applied
mock_collection.find.return_value.limit.assert_called_with(100)
@pytest.mark.asyncio
async def test_connection_pool_management(self):
"""Test database connection pool management"""
from app.nosql import get_mongodb_client
# Test multiple client requests
clients = []
for _ in range(10):
client = get_mongodb_client()
clients.append(client)
# All clients should be the same instance (singleton pattern)
assert all(client is clients[0] for client in clients)
class TestDatabaseErrorHandling:
"""Test database error handling scenarios"""
@pytest.mark.asyncio
async def test_connection_timeout_handling(self):
"""Test handling of connection timeouts"""
from app.repositories.db_repository import get_merchants_from_db
with patch('app.nosql.get_mongodb_client') as mock_client:
mock_client.side_effect = Exception("Connection timeout")
with pytest.raises(Exception) as exc_info:
await get_merchants_from_db()
assert "Connection timeout" in str(exc_info.value)
@pytest.mark.asyncio
async def test_invalid_query_handling(self):
"""Test handling of invalid queries"""
from app.repositories.db_repository import search_merchants_in_db
with patch('app.nosql.get_mongodb_client') as mock_client:
mock_collection = MagicMock()
mock_client.return_value.__getitem__.return_value.__getitem__.return_value = mock_collection
mock_collection.find.side_effect = Exception("Invalid query")
with pytest.raises(Exception) as exc_info:
await search_merchants_in_db(latitude=200, longitude=200) # Invalid coordinates
assert "Invalid query" in str(exc_info.value)
@pytest.mark.asyncio
async def test_duplicate_key_error_handling(self, sample_merchant_data):
"""Test handling of duplicate key errors"""
from app.repositories.db_repository import create_merchant_in_db
with patch('app.nosql.get_mongodb_client') as mock_client:
mock_collection = MagicMock()
mock_client.return_value.__getitem__.return_value.__getitem__.return_value = mock_collection
mock_collection.insert_one.side_effect = Exception("Duplicate key error")
with pytest.raises(Exception) as exc_info:
await create_merchant_in_db(sample_merchant_data)
assert "Duplicate key error" in str(exc_info.value) |