""" Fake Redis Repository adapter for testing. This adapter implements the RedisRepository interface using fakeredis to provide an in-memory Redis server for testing. """ import json from typing import Any import fakeredis 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 class FakeRedisRepository(SientiaMonitoring): """ Fake Redis Repository that uses fakeredis for testing. Implements the same interface as RedisRepository but uses fakeredis for in-memory Redis operations. """ def __init__( self, host: str, port: int, username: str, password: str, logger: Logger, notification_handler: NotificationHandler, metrics_controller: MetricsController, ): """ Initialize fake Redis repository with fakeredis. Args: host: Redis server address (ignored in fake mode) port: Redis server port (ignored in fake mode) username: Username (ignored in fake mode) password: Password (ignored in fake mode) logger: Logger instance notification_handler: Notification handler metrics_controller: Metrics controller """ SientiaMonitoring.__init__( self, logger=logger, notification_handler=notification_handler, metrics_controller=metrics_controller, ) # Create fake Redis server self.redis_client = fakeredis.FakeStrictRedis( decode_responses=True ) def _get_redis(self): """Get fakeredis connection.""" return self.redis_client async def get(self, key: str, metadata: dict | None = None): """ Gets a value from fake Redis by key. Args: key: Key of the value to retrieve metadata: Optional dictionary with additional metadata Return: Deserialized value from Redis or None if not found """ redis = self._get_redis() try: history = redis.get(key) return json.loads(history) if history else None except Exception as e: self.error(f'Error getting data from fake redis: {e}', metadata or {}) raise e async def set( self, key: str, data: dict, ttl: int = 600, nx: bool = False, metadata: dict | None = None, ) -> bool: """ Sets a value in fake Redis with optional TTL. Args: key: Key of the value to set data: Dictionary with data to store ttl: Time to live in seconds (default: 600) nx: If True, only sets if key doesn't exist (default: False) metadata: Optional dictionary with additional metadata Return: True if value was set, False otherwise """ redis = self._get_redis() try: result = redis.set( key, json.dumps(data), ex=ttl, nx=nx ) return bool(result) except Exception as e: self.error(f'Error setting data in fake redis: {e}', metadata or {}) raise e async def delete(self, key: str, metadata: dict | None = None): """ Removes a key from fake Redis. Args: key: Key to be removed metadata: Optional dictionary with additional metadata """ redis = self._get_redis() try: redis.delete(key) except Exception as e: self.error(f'Error deleting data from fake redis: {e}', metadata or {}) raise e async def expire(self, key: str, ttl: int, metadata: dict | None = None): """ Sets the time to live (TTL) of an existing Redis key. Args: key: Key whose TTL will be set ttl: Time to live in seconds metadata: Optional dictionary with additional metadata """ redis = self._get_redis() try: redis.expire(key, ttl) except Exception as e: self.error(f'Error expiring data from fake redis: {e}', metadata or {}) raise e async def keys(self, pattern: str, metadata: dict | None = None): """ Gets all keys matching the specified pattern. Args: pattern: Search pattern for keys metadata: Optional dictionary with additional metadata Return: List of keys matching the pattern """ redis = self._get_redis() try: keys = redis.keys(pattern) return keys except Exception as e: self.error(f'Error getting keys from fake redis: {e}', metadata or {}) raise e def close(self): """ Closes fake Redis connection and shuts down monitoring. """ if self.redis_client: self.redis_client.close() SientiaMonitoring.shutdown(self)