Skip to main content
Glama
test_instance_manager.py8.96 kB
"""Tests for the HippoRAG instance manager.""" import unittest import time import pytest import pytest_asyncio from datetime import datetime, timedelta from unittest.mock import patch, MagicMock from mcp_mem.instance_manager import HippoRAGInstanceManager from mcp_mem.config import MemoryConfig, update_config class TestHippoRAGInstanceManager(unittest.TestCase): """Test cases for the HippoRAGInstanceManager.""" def setUp(self): """Set up test fixtures.""" # Use a short TTL for testing update_config({"instance_ttl_minutes": 1}) # Create a mock HippoRAG class self.mock_hipporag = MagicMock() # Patch the cleanup loop to prevent background thread from running with patch('mcp_mem.instance_manager.threading.Thread'): self.manager = HippoRAGInstanceManager() # Manually set running to False to prevent cleanup thread self.manager._running = False def test_add_instance(self): """Test adding instances.""" # Add an instance self.manager.add("session1", self.mock_hipporag) # Verify it was added self.assertTrue(self.manager.contains("session1")) self.assertEqual(self.manager._instances["session1"], self.mock_hipporag) @patch('mcp_mem.instance_manager.HippoRAGInstanceManager.create_memory') def test_get_existing_instance(self, mock_create_memory): """Test retrieving an existing instance.""" # Add an instance self.manager.add("session1", self.mock_hipporag) # Verify it can be retrieved without calling create_memory import asyncio instance = asyncio.run(self.manager.get("session1")) self.assertEqual(instance, self.mock_hipporag) mock_create_memory.assert_not_called() @patch('mcp_mem.instance_manager.HippoRAGInstanceManager.create_memory') def test_get_nonexistent_instance(self, mock_create_memory): """Test retrieving a non-existent instance creates it.""" # Setup the mock to do nothing (we'll test create_memory separately) mock_create_memory.return_value = None # Call get on a non-existent session import asyncio asyncio.run(self.manager.get("nonexistent")) # Verify create_memory was called mock_create_memory.assert_called_once_with("nonexistent") def test_contains_and_remove(self): """Test contains and remove functionality.""" # Add an instance self.manager.add("session1", self.mock_hipporag) # Verify contains works self.assertTrue(self.manager.contains("session1")) self.assertFalse(self.manager.contains("nonexistent")) # Remove the instance self.manager.remove("session1") # Verify it's gone self.assertFalse(self.manager.contains("session1")) def test_get_all_session_ids(self): """Test getting all session IDs.""" # Add some instances self.manager.add("session1", self.mock_hipporag) self.manager.add("session2", self.mock_hipporag) # Verify all sessions are returned session_ids = self.manager.get_all_session_ids() self.assertEqual(session_ids, {"session1", "session2"}) def test_cleanup_expired_instances(self): """Test cleanup of expired instances.""" # Add some instances self.manager.add("session1", self.mock_hipporag) self.manager.add("session2", self.mock_hipporag) # Manually set last_accessed time for session1 to be expired self.manager._last_accessed["session1"] = datetime.now() - timedelta(minutes=2) # Run cleanup self.manager._cleanup_expired_instances() # Verify session1 was removed but session2 remains self.assertFalse(self.manager.contains("session1")) self.assertTrue(self.manager.contains("session2")) def test_ttl_disabled(self): """Test that cleanup doesn't happen when TTL is disabled.""" # Set TTL to 0 (disabled) update_config({"instance_ttl_minutes": 0}) # Add an instance self.manager.add("session1", self.mock_hipporag) # Manually set last_accessed time to be expired self.manager._last_accessed["session1"] = datetime.now() - timedelta(minutes=10) # Run cleanup self.manager._cleanup_expired_instances() # Verify session1 still exists self.assertTrue(self.manager.contains("session1")) @pytest.mark.asyncio async def test_access_updates_timestamp(self): """Test that accessing an instance updates its timestamp.""" # Add an instance self.manager.add("session1", self.mock_hipporag) # Get the initial timestamp initial_timestamp = self.manager._last_accessed["session1"] # Wait a moment time.sleep(0.1) # Access the instance await self.manager.get("session1") # Verify timestamp was updated self.assertGreater(self.manager._last_accessed["session1"], initial_timestamp) def test_shutdown(self): """Test manager shutdown.""" # Create a manager with a mocked thread with patch('mcp_mem.instance_manager.threading.Thread') as mock_thread: manager = HippoRAGInstanceManager() mock_thread_instance = mock_thread.return_value # Call shutdown manager.shutdown() # Verify running flag is set to False self.assertFalse(manager._running) # Verify join was called on the thread mock_thread_instance.join.assert_called_once() @patch('mcp_mem.instance_manager.os') @patch('mcp_mem.instance_manager.HippoRAG') def test_create_memory(self, mock_hipporag_class, mock_os): """Test the create_memory method.""" # Setup mock_hipporag_instance = MagicMock() mock_hipporag_class.return_value = mock_hipporag_instance # Create a manager with mocked methods manager = HippoRAGInstanceManager() manager._ensure_session_exists = MagicMock() manager._initialize_hipporag = MagicMock(return_value=mock_hipporag_instance) # Call create_memory synchronously for testing import asyncio asyncio.run(manager.create_memory("test-session")) # Verify the session was created self.assertTrue(manager.contains("test-session")) manager._ensure_session_exists.assert_called_once_with("test-session") manager._initialize_hipporag.assert_called_once_with("test-session") def test_get_session_path(self): """Test the _get_session_path method.""" # Setup manager = HippoRAGInstanceManager() manager._config.memory_dir = "/tmp/memory" # Test path = manager._get_session_path("test-session") # Verify self.assertEqual(path, "/tmp/memory/session_test-session") @patch('mcp_mem.instance_manager.os') def test_ensure_session_exists(self, mock_os): """Test the _ensure_session_exists method.""" # Setup manager = HippoRAGInstanceManager() manager._get_session_path = MagicMock(return_value="/tmp/memory/session_test") # Reset the mock to clear the call from __init__ mock_os.makedirs.reset_mock() # Test manager._ensure_session_exists("test-session") # Verify mock_os.makedirs.assert_called_once_with("/tmp/memory/session_test", exist_ok=True) @patch('mcp_mem.instance_manager.BaseConfig') @patch('mcp_mem.instance_manager.HippoRAG') def test_initialize_hipporag(self, mock_hipporag_class, mock_base_config): """Test the _initialize_hipporag method.""" # Setup mock_config = MagicMock() mock_base_config.return_value = mock_config mock_hipporag_instance = MagicMock() mock_hipporag_class.return_value = mock_hipporag_instance manager = HippoRAGInstanceManager() manager._get_session_path = MagicMock(return_value="/tmp/memory/session_test") manager._config.hipporag_config = {"model_name": "gpt-4", "embedding_model": "text-embedding-3-large"} # Test result = manager._initialize_hipporag("test-session") # Verify self.assertEqual(result, mock_hipporag_instance) self.assertEqual(mock_config.save_dir, "/tmp/memory/session_test") mock_hipporag_class.assert_called_once_with( global_config=mock_config, save_dir="/tmp/memory/session_test" ) if __name__ == '__main__': unittest.main()

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/ddkang1/mcp-mem'

If you have feedback or need assistance with the MCP directory API, please join our Discord server