Update requirements-dev.txt to add E2E testing dependencies: fakeredis and mongomock for in-memory testing, and include testcontainers for PostgreSQL support.
242 lines
7.5 KiB
Python
242 lines
7.5 KiB
Python
"""
|
|
Fake MongoDB Repository adapter for testing.
|
|
|
|
This adapter implements the MongoDBRepository interface using mongomock
|
|
to provide an in-memory MongoDB server for testing.
|
|
"""
|
|
|
|
import time
|
|
from typing import Any
|
|
|
|
from mongomock import MongoClient
|
|
from sientia_do.notifications.handlers import CoreNotificationHandler as NotificationHandler
|
|
from sientia_do.observability.logger import Logger
|
|
from sientia_do.observability.metrics_controller import MetricsController
|
|
from sientia_do.observability.sientia_monitoring import SientiaMonitoring
|
|
|
|
|
|
def clear_mongo_id(docs: list) -> list:
|
|
"""
|
|
Remove MongoDB internal `_id` fields from nested structures.
|
|
|
|
Same implementation as in the real MongoDBRepository.
|
|
|
|
Args:
|
|
docs: The list of documents or nested structures to clean.
|
|
|
|
Returns:
|
|
The cleaned documents with `_id` fields removed wherever present.
|
|
"""
|
|
for doc in docs:
|
|
if isinstance(doc, list):
|
|
clear_mongo_id(doc)
|
|
elif isinstance(doc, dict):
|
|
if '_id' in doc:
|
|
del doc['_id']
|
|
for _key, value in doc.items():
|
|
if isinstance(value, list):
|
|
clear_mongo_id(value)
|
|
elif isinstance(value, dict):
|
|
clear_mongo_id([value])
|
|
return docs
|
|
|
|
|
|
class FakeMongoDBRepository(SientiaMonitoring):
|
|
"""
|
|
Fake MongoDB Repository that uses mongomock for testing.
|
|
|
|
Implements the same interface as MongoDBRepository but uses
|
|
mongomock for in-memory MongoDB operations.
|
|
"""
|
|
|
|
def __init__(
|
|
self,
|
|
connection_string: str,
|
|
database_name: str,
|
|
logger: Logger,
|
|
notification_handler: NotificationHandler,
|
|
metrics_controller: MetricsController,
|
|
):
|
|
"""
|
|
Initialize fake MongoDB repository with mongomock.
|
|
|
|
Args:
|
|
connection_string: MongoDB connection string (ignored in fake mode)
|
|
database_name: Target database name
|
|
logger: Logger instance
|
|
notification_handler: Notification handler
|
|
metrics_controller: Metrics controller
|
|
"""
|
|
SientiaMonitoring.__init__(
|
|
self,
|
|
logger=logger,
|
|
notification_handler=notification_handler,
|
|
metrics_controller=metrics_controller,
|
|
)
|
|
|
|
self.database_name = database_name
|
|
# Use mongomock instead of real MongoDB
|
|
self.mongo_client = MongoClient()
|
|
self.database = self.mongo_client[self.database_name]
|
|
logger.info('Fake MongoDB connection initialized')
|
|
|
|
def close(self):
|
|
"""
|
|
Closes fake MongoDB connection and shuts down monitoring.
|
|
"""
|
|
try:
|
|
if self.mongo_client:
|
|
self.logger.info('Closing fake MongoDB connection...')
|
|
self.mongo_client.close()
|
|
self.logger.info('Fake MongoDB connection closed successfully')
|
|
except Exception as e:
|
|
self.logger.error(f'Failed to close fake MongoDB connection: {e}')
|
|
SientiaMonitoring.shutdown(self)
|
|
|
|
def __del__(self):
|
|
"""
|
|
Destructor that closes the connection when destroying the instance.
|
|
"""
|
|
self.close()
|
|
|
|
async def find(
|
|
self,
|
|
collection_name: str,
|
|
filters: dict[str, Any],
|
|
metadata: dict[str, Any],
|
|
) -> list[dict[str, Any]]:
|
|
"""
|
|
Finds documents in a MongoDB collection based on provided filters.
|
|
|
|
Args:
|
|
collection_name: Name of the collection to search
|
|
filters: Query filters to apply
|
|
metadata: Dictionary with additional metadata
|
|
|
|
Return:
|
|
List of documents matching the filters (with `_id` removed)
|
|
"""
|
|
try:
|
|
start_time = time.time()
|
|
collection = self.database[collection_name]
|
|
documents = list(collection.find(filters, {'_id': 0}))
|
|
except Exception as e:
|
|
self.logger.error(f'Failed to find documents in fake MongoDB: {e}')
|
|
raise e
|
|
|
|
return clear_mongo_id(documents)
|
|
|
|
async def aggregate(
|
|
self,
|
|
collection_name: str,
|
|
pipeline: list[dict[str, Any]],
|
|
metadata: dict[str, Any],
|
|
) -> list[dict[str, Any]]:
|
|
"""
|
|
Executes an aggregation on a MongoDB collection.
|
|
|
|
Args:
|
|
collection_name: Name of the collection to aggregate
|
|
pipeline: MongoDB aggregation pipeline
|
|
metadata: Dictionary with additional metadata
|
|
|
|
Return:
|
|
List of documents resulting from aggregation (with `_id` removed)
|
|
"""
|
|
try:
|
|
start_time = time.time()
|
|
collection = self.database[collection_name]
|
|
documents = list(collection.aggregate(pipeline))
|
|
except Exception as e:
|
|
self.logger.error(f'Failed to aggregate documents in fake MongoDB: {e}')
|
|
raise e
|
|
|
|
return clear_mongo_id(documents)
|
|
|
|
async def update_many(
|
|
self,
|
|
collection_name: str,
|
|
filters: dict[str, Any],
|
|
update: dict[str, Any],
|
|
metadata: dict[str, Any],
|
|
) -> None:
|
|
"""
|
|
Updates multiple documents in a MongoDB collection.
|
|
|
|
Args:
|
|
collection_name: Collection name
|
|
filters: Filters to identify documents to update
|
|
update: Update operations to apply
|
|
metadata: Dictionary with additional metadata
|
|
"""
|
|
try:
|
|
collection = self.database[collection_name]
|
|
collection.update_many(filters, update)
|
|
except Exception as e:
|
|
self.logger.error(f'Failed to update documents in fake MongoDB: {e}')
|
|
raise e
|
|
|
|
async def insert_many(
|
|
self,
|
|
collection_name: str,
|
|
documents: list[dict[str, Any]],
|
|
metadata: dict[str, Any],
|
|
) -> None:
|
|
"""
|
|
Inserts multiple documents into a MongoDB collection.
|
|
|
|
Args:
|
|
collection_name: Collection name
|
|
documents: List of documents to insert
|
|
metadata: Dictionary with additional metadata
|
|
"""
|
|
try:
|
|
collection = self.database[collection_name]
|
|
collection.insert_many(documents)
|
|
except Exception as e:
|
|
self.logger.error(f'Failed to insert documents in fake MongoDB: {e}')
|
|
raise e
|
|
|
|
async def insert(
|
|
self,
|
|
collection_name: str,
|
|
document: dict[str, Any],
|
|
metadata: dict[str, Any],
|
|
) -> None:
|
|
"""
|
|
Inserts a document into a MongoDB collection.
|
|
|
|
Args:
|
|
collection_name: Collection name
|
|
document: Document to insert
|
|
metadata: Dictionary with additional metadata
|
|
"""
|
|
try:
|
|
collection = self.database[collection_name]
|
|
collection.insert_one(document)
|
|
except Exception as e:
|
|
self.logger.error(f'Failed to insert document in fake MongoDB: {e}')
|
|
raise e
|
|
|
|
async def delete_many(
|
|
self,
|
|
collection_name: str,
|
|
filters: dict[str, Any],
|
|
metadata: dict[str, Any],
|
|
) -> None:
|
|
"""
|
|
Removes multiple documents from a MongoDB collection.
|
|
|
|
Args:
|
|
collection_name: Collection name
|
|
filters: Filters to identify documents to remove
|
|
metadata: Dictionary with additional metadata
|
|
"""
|
|
try:
|
|
collection = self.database[collection_name]
|
|
collection.delete_many(filters)
|
|
except Exception as e:
|
|
self.logger.error(f'Failed to delete documents in fake MongoDB: {e}')
|
|
raise e
|
|
|