File size: 9,003 Bytes
dbb04e4 c3a3710 dbb04e4 c3a3710 dbb04e4 c3a3710 dbb04e4 c3a3710 dbb04e4 c3a3710 dbb04e4 | 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 | """
Tests for Dependency Injection Migration
=========================================
Verifies that the singleton pattern has been properly removed
and replaced with dependency injection.
"""
import pytest
from unittest.mock import MagicMock, AsyncMock, patch
class TestAsyncRedisStorageDI:
"""Tests for AsyncRedisStorage dependency injection."""
def test_no_get_instance_method(self):
"""AsyncRedisStorage should not have get_instance class method."""
from mnemocore.core.async_storage import AsyncRedisStorage
assert not hasattr(AsyncRedisStorage, 'get_instance'), \
"AsyncRedisStorage should not have get_instance method"
def test_constructor_accepts_parameters(self):
"""AsyncRedisStorage constructor should accept explicit parameters."""
from mnemocore.core.async_storage import AsyncRedisStorage
# Create with explicit parameters to verify they work
storage = AsyncRedisStorage(
url="redis://test:6379/0",
stream_key="test:stream",
max_connections=5,
socket_timeout=10,
password="testpass",
)
# Verify attributes are set
assert storage.stream_key == "test:stream"
def test_constructor_with_mock_client(self):
"""AsyncRedisStorage should accept a mock client for testing."""
from mnemocore.core.async_storage import AsyncRedisStorage
mock_client = MagicMock()
storage = AsyncRedisStorage(client=mock_client)
assert storage.redis_client is mock_client
class TestQdrantStoreDI:
"""Tests for QdrantStore dependency injection."""
def test_no_get_instance_method(self):
"""QdrantStore should not have get_instance class method."""
from mnemocore.core.qdrant_store import QdrantStore
assert not hasattr(QdrantStore, 'get_instance'), \
"QdrantStore should not have get_instance method"
def test_constructor_accepts_parameters(self):
"""QdrantStore constructor should accept explicit parameters."""
from mnemocore.core.qdrant_store import QdrantStore
store = QdrantStore(
url="http://test:6333",
api_key="test-key",
dimensionality=8192,
collection_hot="test_hot",
collection_warm="test_warm",
)
assert store.url == "http://test:6333"
assert store.api_key == "test-key"
assert store.dim == 8192
assert store.collection_hot == "test_hot"
assert store.collection_warm == "test_warm"
class TestContainer:
"""Tests for the dependency injection container."""
def test_container_exists(self):
"""Container module should exist and be importable."""
from mnemocore.core.container import Container, build_container
assert Container is not None
assert build_container is not None
def test_build_container_creates_dependencies(self):
"""build_container should create all required dependencies."""
from mnemocore.core.container import build_container
from mnemocore.core.config import HAIMConfig
# Create a minimal config
config = HAIMConfig()
with patch('mnemocore.core.container.AsyncRedisStorage') as mock_redis_class, \
patch('mnemocore.core.container.QdrantStore') as mock_qdrant_class:
mock_redis_class.return_value = MagicMock()
mock_qdrant_class.return_value = MagicMock()
container = build_container(config)
assert container.config is config
assert container.redis_storage is not None
assert container.qdrant_store is not None
def test_container_dataclass_fields(self):
"""Container should have expected fields."""
from mnemocore.core.container import Container
from mnemocore.core.config import HAIMConfig
config = HAIMConfig()
container = Container(config=config)
assert hasattr(container, 'config')
assert hasattr(container, 'redis_storage')
assert hasattr(container, 'qdrant_store')
class TestTierManagerDI:
"""Tests for TierManager dependency injection."""
def test_constructor_accepts_config(self):
"""TierManager constructor should accept config parameter."""
from mnemocore.core.tier_manager import TierManager
from mnemocore.core.config import HAIMConfig
config = HAIMConfig()
with patch('mnemocore.core.tier_manager.HNSW_AVAILABLE', False), \
patch('mnemocore.core.tier_manager.FAISS_AVAILABLE', False):
manager = TierManager(config=config)
assert manager.config is config
def test_constructor_accepts_qdrant_store(self):
"""TierManager constructor should accept qdrant_store parameter."""
from mnemocore.core.tier_manager import TierManager
from mnemocore.core.config import HAIMConfig
config = HAIMConfig()
mock_qdrant = MagicMock()
with patch('mnemocore.core.tier_manager.HNSW_AVAILABLE', False), \
patch('mnemocore.core.tier_manager.FAISS_AVAILABLE', False):
manager = TierManager(config=config, qdrant_store=mock_qdrant)
assert manager.qdrant is mock_qdrant
assert manager.use_qdrant is True
class TestHAIMEngineDI:
"""Tests for HAIMEngine dependency injection."""
def test_constructor_accepts_config(self):
"""HAIMEngine constructor should accept config parameter."""
from mnemocore.core.engine import HAIMEngine
from mnemocore.core.config import HAIMConfig
config = HAIMConfig()
# Patch at tier_manager level since that's where HNSW/FAISS is used
with patch('mnemocore.core.tier_manager.HNSW_AVAILABLE', False), \
patch('mnemocore.core.tier_manager.FAISS_AVAILABLE', False):
engine = HAIMEngine(config=config)
assert engine.config is config
def test_constructor_accepts_tier_manager(self):
"""HAIMEngine constructor should accept tier_manager parameter."""
from mnemocore.core.engine import HAIMEngine
from mnemocore.core.config import HAIMConfig
from mnemocore.core.tier_manager import TierManager
config = HAIMConfig()
with patch('mnemocore.core.tier_manager.HNSW_AVAILABLE', False), \
patch('mnemocore.core.tier_manager.FAISS_AVAILABLE', False):
tier_manager = TierManager(config=config)
engine = HAIMEngine(config=config, tier_manager=tier_manager)
assert engine.tier_manager is tier_manager
class TestConsolidationWorkerDI:
"""Tests for ConsolidationWorker dependency injection."""
def test_constructor_accepts_storage(self):
"""ConsolidationWorker constructor should accept storage parameter."""
from mnemocore.core.consolidation_worker import ConsolidationWorker
mock_storage = MagicMock()
mock_tier_manager = MagicMock()
worker = ConsolidationWorker(
storage=mock_storage,
tier_manager=mock_tier_manager,
)
assert worker.storage is mock_storage
assert worker.tier_manager is mock_tier_manager
class TestNoSingletonPattern:
"""Tests to ensure singleton pattern is fully removed."""
def test_no_singleton_instances(self):
"""Classes should not have _instance class attribute for singletons."""
from mnemocore.core.async_storage import AsyncRedisStorage
from mnemocore.core.qdrant_store import QdrantStore
# _instance is the typical singleton storage attribute
assert not hasattr(AsyncRedisStorage, '_instance') or \
AsyncRedisStorage._instance is None or \
'_instance' not in AsyncRedisStorage.__dict__
# Note: QdrantStore might have _instance from object base,
# but shouldn't have it defined explicitly for singleton use
if hasattr(QdrantStore, '_instance'):
# Check it's not being used as singleton storage
assert '_instance' not in QdrantStore.__dict__ or \
QdrantStore.__dict__['_instance'] is None
def test_multiple_instances_independent(self):
"""Creating multiple instances should work independently."""
from mnemocore.core.async_storage import AsyncRedisStorage
mock_client1 = MagicMock()
mock_client2 = MagicMock()
storage1 = AsyncRedisStorage(client=mock_client1)
storage2 = AsyncRedisStorage(client=mock_client2)
# Each should have its own client
assert storage1.redis_client is mock_client1
assert storage2.redis_client is mock_client2
assert storage1 is not storage2
|