Skip to main content
Glama

Dynamic Per-User Tool Generation MCP Server

test_hierarchy_cache.py9.13 kB
""" Tests for Hierarchical Entity Cache System Tests the hierarchy_cache module including: - Node creation and tree building - Path generation - Search functionality - Elasticsearch integration - Edge cases (orphaned nodes, circular references) """ import pytest import sys import os # Add parent directory to path for imports sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) from hierarchy_cache import ( HierarchicalNode, HierarchicalCache, LocationCacheLoader, DepartmentCacheLoader, HierarchyCacheManager, initialize_hierarchy_caches, get_hierarchy_cache_manager ) class TestHierarchicalNode: """Test HierarchicalNode dataclass.""" def test_node_creation(self): """Test creating a hierarchical node.""" node = HierarchicalNode(name="Test Node", id=1, parent_id=None) assert node.name == "Test Node" assert node.id == 1 assert node.parent_id is None def test_node_with_parent(self): """Test creating a node with parent.""" node = HierarchicalNode(name="Child Node", id=2, parent_id=1) assert node.name == "Child Node" assert node.id == 2 assert node.parent_id == 1 def test_node_repr(self): """Test node string representation.""" node = HierarchicalNode(name="Test", id=1) assert "Test" in repr(node) assert "1" in repr(node) class TestHierarchicalCache: """Test HierarchicalCache class.""" def test_cache_creation(self): """Test creating a cache.""" cache = HierarchicalCache(entity_type="test") assert cache.entity_type == "test" assert len(cache.nodes_by_id) == 0 def test_add_single_node(self): """Test adding a single node.""" cache = HierarchicalCache() cache.add_node("Root", 1) assert len(cache.nodes_by_id) == 1 assert 1 in cache.nodes_by_id assert cache.nodes_by_id[1].name == "Root" def test_add_hierarchical_nodes(self): """Test adding nodes with parent-child relationships.""" cache = HierarchicalCache() # Add root cache.add_node("Root", 1) # Add children cache.add_node("Child 1", 2, parent_id=1) cache.add_node("Child 2", 3, parent_id=1) # Add grandchild cache.add_node("Grandchild", 4, parent_id=2) assert len(cache.nodes_by_id) == 4 assert len(cache.children_by_parent[1]) == 2 assert len(cache.children_by_parent[2]) == 1 def test_search_by_name_exact(self): """Test exact name search.""" cache = HierarchicalCache() cache.add_node("Test Location", 1) cache.add_node("Another Location", 2) cache.add_node("Test Location", 3) # Duplicate name results = cache.search_by_name_exact("Test Location") assert len(results) == 2 assert all(node.name == "Test Location" for node in results) def test_search_by_name_prefix(self): """Test prefix name search.""" cache = HierarchicalCache() cache.add_node("California", 1) cache.add_node("Canada", 2) cache.add_node("Texas", 3) results = cache.search_by_name_prefix("Ca") assert len(results) == 2 assert all(node.name.startswith("Ca") for node in results) def test_get_full_path(self): """Test getting full path by ID.""" cache = HierarchicalCache() cache.add_node("Root", 1) cache.add_node("Child", 2, parent_id=1) cache.add_node("Grandchild", 3, parent_id=2) path = cache.get_full_path(3) assert path == "1 -> 2 -> 3" def test_get_full_path_name(self): """Test getting full path by name.""" cache = HierarchicalCache() cache.add_node("Root", 1) cache.add_node("Child", 2, parent_id=1) cache.add_node("Grandchild", 3, parent_id=2) # By ID path = cache.get_full_path_name(3) assert path == "Root -> Child -> Grandchild" # By name (unique) path = cache.get_full_path_name("Grandchild") assert path == "Root -> Child -> Grandchild" def test_get_full_path_name_multiple_matches(self): """Test getting paths when multiple nodes have same name.""" cache = HierarchicalCache() cache.add_node("Root", 1) cache.add_node("HR", 2, parent_id=1) cache.add_node("HR", 3, parent_id=1) paths = cache.get_full_path_name("HR") assert isinstance(paths, list) assert len(paths) == 2 assert all("Root -> HR" in path for path in paths) def test_get_children(self): """Test getting direct children.""" cache = HierarchicalCache() cache.add_node("Root", 1) cache.add_node("Child 1", 2, parent_id=1) cache.add_node("Child 2", 3, parent_id=1) cache.add_node("Grandchild", 4, parent_id=2) children = cache.get_children(1) assert len(children) == 2 assert all(child.parent_id == 1 for child in children) def test_circular_reference_handling(self): """Test that circular references are detected and handled.""" cache = HierarchicalCache() # Manually create circular reference (shouldn't happen in real data) cache.add_node("Node 1", 1, parent_id=2) cache.add_node("Node 2", 2, parent_id=1) # Should not crash, should detect cycle path = cache.get_full_path(1) # Path should be limited and not infinite assert len(path) < 100 # Sanity check def test_get_stats(self): """Test getting cache statistics.""" cache = HierarchicalCache(entity_type="location") cache.add_node("Root 1", 1) cache.add_node("Root 2", 2) cache.add_node("Child", 3, parent_id=1) stats = cache.get_stats() assert stats['entity_type'] == "location" assert stats['total_nodes'] == 3 assert stats['root_nodes'] == 2 assert stats['max_depth'] >= 0 class TestHierarchyCacheManager: """Test HierarchyCacheManager singleton.""" def test_singleton_pattern(self): """Test that manager follows singleton pattern.""" manager1 = HierarchyCacheManager.get_instance() manager2 = HierarchyCacheManager.get_instance() assert manager1 is manager2 def test_manager_initialization(self): """Test manager provides access to caches.""" manager = HierarchyCacheManager.get_instance() # Before initialization assert manager.get_location_cache() is None or isinstance(manager.get_location_cache(), HierarchicalCache) assert manager.get_department_cache() is None or isinstance(manager.get_department_cache(), HierarchicalCache) def test_get_statistics(self): """Test getting statistics from manager.""" manager = HierarchyCacheManager.get_instance() stats = manager.get_statistics() assert 'initialized' in stats assert 'location' in stats assert 'department' in stats class TestElasticsearchIntegration: """Test Elasticsearch integration (requires ES to be running).""" @pytest.mark.skipif( not os.getenv("ES_HOST"), reason="Elasticsearch not configured (ES_HOST not set)" ) def test_location_loader_connection(self): """Test location loader can connect to Elasticsearch.""" loader = LocationCacheLoader("apolo") connected = loader.connect() # Connection may fail if ES is not running, which is okay assert isinstance(connected, bool) @pytest.mark.skipif( not os.getenv("ES_HOST"), reason="Elasticsearch not configured (ES_HOST not set)" ) def test_department_loader_connection(self): """Test department loader can connect to Elasticsearch.""" loader = DepartmentCacheLoader("apolo") connected = loader.connect() # Connection may fail if ES is not running, which is okay assert isinstance(connected, bool) class TestPublicAPI: """Test public API functions.""" def test_initialize_hierarchy_caches(self): """Test initialization function.""" # This may fail if ES is not available, but should not crash manager = initialize_hierarchy_caches("apolo") # Should return a manager instance even if initialization failed assert manager is None or isinstance(manager, HierarchyCacheManager) def test_get_hierarchy_cache_manager(self): """Test getting manager instance.""" manager = get_hierarchy_cache_manager() # Should return manager or None assert manager is None or isinstance(manager, HierarchyCacheManager) if __name__ == "__main__": # Run tests with pytest pytest.main([__file__, "-v", "-s"])

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/ShivamPansuriya/MCP-server-Python'

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