Skip to main content
Glama
orneryd

M.I.M.I.R - Multi-agent Intelligent Memory & Insight Repository

by orneryd
spanning_tree_test.go13.4 kB
package cypher import ( "context" "testing" "github.com/orneryd/nornicdb/pkg/storage" ) // TestApocPathSpanningTreeBasic tests basic spanning tree functionality func TestApocPathSpanningTreeBasic(t *testing.T) { store := storage.NewMemoryEngine() e := NewStorageExecutor(store) ctx := context.Background() // Create a simple graph: A -> B -> C // A -> D store.CreateNode(&storage.Node{ID: "a", Labels: []string{"Node"}, Properties: map[string]interface{}{"name": "A"}}) store.CreateNode(&storage.Node{ID: "b", Labels: []string{"Node"}, Properties: map[string]interface{}{"name": "B"}}) store.CreateNode(&storage.Node{ID: "c", Labels: []string{"Node"}, Properties: map[string]interface{}{"name": "C"}}) store.CreateNode(&storage.Node{ID: "d", Labels: []string{"Node"}, Properties: map[string]interface{}{"name": "D"}}) store.CreateEdge(&storage.Edge{ID: "e1", Type: "CONNECTS", StartNode: "a", EndNode: "b"}) store.CreateEdge(&storage.Edge{ID: "e2", Type: "CONNECTS", StartNode: "b", EndNode: "c"}) store.CreateEdge(&storage.Edge{ID: "e3", Type: "CONNECTS", StartNode: "a", EndNode: "d"}) // Get spanning tree from node A (using node ID directly) query := `CALL apoc.path.spanningTree({id: 'a'}, {}) YIELD path RETURN path` result, err := e.Execute(ctx, query, nil) if err != nil { t.Fatalf("Spanning tree query failed: %v", err) } // Should have 3 edges in the spanning tree (connecting 4 nodes) if len(result.Rows) != 3 { t.Errorf("Expected 3 edges in spanning tree, got %d", len(result.Rows)) } } // TestApocPathSpanningTreeWithCycle tests spanning tree with cycles func TestApocPathSpanningTreeWithCycle(t *testing.T) { store := storage.NewMemoryEngine() e := NewStorageExecutor(store) ctx := context.Background() // Create a graph with a cycle: A -> B -> C -> A // A -> D store.CreateNode(&storage.Node{ID: "a", Labels: []string{"Node"}, Properties: map[string]interface{}{"name": "A"}}) store.CreateNode(&storage.Node{ID: "b", Labels: []string{"Node"}, Properties: map[string]interface{}{"name": "B"}}) store.CreateNode(&storage.Node{ID: "c", Labels: []string{"Node"}, Properties: map[string]interface{}{"name": "C"}}) store.CreateNode(&storage.Node{ID: "d", Labels: []string{"Node"}, Properties: map[string]interface{}{"name": "D"}}) store.CreateEdge(&storage.Edge{ID: "e1", Type: "CONNECTS", StartNode: "a", EndNode: "b"}) store.CreateEdge(&storage.Edge{ID: "e2", Type: "CONNECTS", StartNode: "b", EndNode: "c"}) store.CreateEdge(&storage.Edge{ID: "e3", Type: "CONNECTS", StartNode: "c", EndNode: "a"}) // Creates cycle store.CreateEdge(&storage.Edge{ID: "e4", Type: "CONNECTS", StartNode: "a", EndNode: "d"}) query := `CALL apoc.path.spanningTree({id: 'a'}, {}) YIELD path RETURN path` result, err := e.Execute(ctx, query, nil) if err != nil { t.Fatalf("Spanning tree query failed: %v", err) } // Should still have only 3 edges (spanning tree excludes cycle-creating edge) if len(result.Rows) != 3 { t.Errorf("Expected 3 edges in spanning tree (no cycles), got %d", len(result.Rows)) } } // TestApocPathSpanningTreeMaxLevel tests maxLevel configuration func TestApocPathSpanningTreeMaxLevel(t *testing.T) { store := storage.NewMemoryEngine() e := NewStorageExecutor(store) ctx := context.Background() // Create a chain: A -> B -> C -> D store.CreateNode(&storage.Node{ID: "a", Labels: []string{"Node"}, Properties: map[string]interface{}{"name": "A"}}) store.CreateNode(&storage.Node{ID: "b", Labels: []string{"Node"}, Properties: map[string]interface{}{"name": "B"}}) store.CreateNode(&storage.Node{ID: "c", Labels: []string{"Node"}, Properties: map[string]interface{}{"name": "C"}}) store.CreateNode(&storage.Node{ID: "d", Labels: []string{"Node"}, Properties: map[string]interface{}{"name": "D"}}) store.CreateEdge(&storage.Edge{ID: "e1", Type: "CONNECTS", StartNode: "a", EndNode: "b"}) store.CreateEdge(&storage.Edge{ID: "e2", Type: "CONNECTS", StartNode: "b", EndNode: "c"}) store.CreateEdge(&storage.Edge{ID: "e3", Type: "CONNECTS", StartNode: "c", EndNode: "d"}) // Test with maxLevel: 2 (should get only first 2 edges) query := `CALL apoc.path.spanningTree({id: 'a'}, {maxLevel: 2}) YIELD path RETURN path` result, err := e.Execute(ctx, query, nil) if err != nil { t.Fatalf("Spanning tree query failed: %v", err) } if len(result.Rows) != 2 { t.Errorf("Expected 2 edges with maxLevel:2, got %d", len(result.Rows)) } } // TestApocPathSpanningTreeRelationshipFilter tests relationship type filtering func TestApocPathSpanningTreeRelationshipFilter(t *testing.T) { store := storage.NewMemoryEngine() e := NewStorageExecutor(store) ctx := context.Background() // Create a graph with different relationship types store.CreateNode(&storage.Node{ID: "a", Labels: []string{"Node"}, Properties: map[string]interface{}{"name": "A"}}) store.CreateNode(&storage.Node{ID: "b", Labels: []string{"Node"}, Properties: map[string]interface{}{"name": "B"}}) store.CreateNode(&storage.Node{ID: "c", Labels: []string{"Node"}, Properties: map[string]interface{}{"name": "C"}}) store.CreateNode(&storage.Node{ID: "d", Labels: []string{"Node"}, Properties: map[string]interface{}{"name": "D"}}) store.CreateEdge(&storage.Edge{ID: "e1", Type: "FRIEND", StartNode: "a", EndNode: "b"}) store.CreateEdge(&storage.Edge{ID: "e2", Type: "FRIEND", StartNode: "b", EndNode: "c"}) store.CreateEdge(&storage.Edge{ID: "e3", Type: "COLLEAGUE", StartNode: "a", EndNode: "d"}) // Test with relationshipFilter for FRIEND only query := `CALL apoc.path.spanningTree({id: 'a'}, {relationshipFilter: 'FRIEND'}) YIELD path RETURN path` result, err := e.Execute(ctx, query, nil) if err != nil { t.Fatalf("Spanning tree query failed: %v", err) } // Should have only 2 edges (FRIEND relationships) if len(result.Rows) != 2 { t.Errorf("Expected 2 edges with FRIEND filter, got %d", len(result.Rows)) } } // TestApocPathSpanningTreeDFS tests depth-first search spanning tree func TestApocPathSpanningTreeDFS(t *testing.T) { store := storage.NewMemoryEngine() e := NewStorageExecutor(store) ctx := context.Background() // Create a binary tree store.CreateNode(&storage.Node{ID: "a", Labels: []string{"Node"}, Properties: map[string]interface{}{"name": "A"}}) store.CreateNode(&storage.Node{ID: "b", Labels: []string{"Node"}, Properties: map[string]interface{}{"name": "B"}}) store.CreateNode(&storage.Node{ID: "c", Labels: []string{"Node"}, Properties: map[string]interface{}{"name": "C"}}) store.CreateNode(&storage.Node{ID: "d", Labels: []string{"Node"}, Properties: map[string]interface{}{"name": "D"}}) store.CreateNode(&storage.Node{ID: "e", Labels: []string{"Node"}, Properties: map[string]interface{}{"name": "E"}}) store.CreateEdge(&storage.Edge{ID: "e1", Type: "CONNECTS", StartNode: "a", EndNode: "b"}) store.CreateEdge(&storage.Edge{ID: "e2", Type: "CONNECTS", StartNode: "a", EndNode: "c"}) store.CreateEdge(&storage.Edge{ID: "e3", Type: "CONNECTS", StartNode: "b", EndNode: "d"}) store.CreateEdge(&storage.Edge{ID: "e4", Type: "CONNECTS", StartNode: "b", EndNode: "e"}) // Test with DFS query := `CALL apoc.path.spanningTree({id: 'a'}, {bfs: false}) YIELD path RETURN path` result, err := e.Execute(ctx, query, nil) if err != nil { t.Fatalf("Spanning tree DFS query failed: %v", err) } // Should have 4 edges in the spanning tree if len(result.Rows) != 4 { t.Errorf("Expected 4 edges in DFS spanning tree, got %d", len(result.Rows)) } } // TestApocPathSpanningTreeLabelFilter tests label filtering func TestApocPathSpanningTreeLabelFilter(t *testing.T) { store := storage.NewMemoryEngine() e := NewStorageExecutor(store) ctx := context.Background() // Create a graph with different labels store.CreateNode(&storage.Node{ID: "a", Labels: []string{"Start"}, Properties: map[string]interface{}{"name": "A"}}) store.CreateNode(&storage.Node{ID: "b", Labels: []string{"Good"}, Properties: map[string]interface{}{"name": "B"}}) store.CreateNode(&storage.Node{ID: "c", Labels: []string{"Good"}, Properties: map[string]interface{}{"name": "C"}}) store.CreateNode(&storage.Node{ID: "d", Labels: []string{"Bad"}, Properties: map[string]interface{}{"name": "D"}}) store.CreateEdge(&storage.Edge{ID: "e1", Type: "CONNECTS", StartNode: "a", EndNode: "b"}) store.CreateEdge(&storage.Edge{ID: "e2", Type: "CONNECTS", StartNode: "b", EndNode: "c"}) store.CreateEdge(&storage.Edge{ID: "e3", Type: "CONNECTS", StartNode: "a", EndNode: "d"}) // Test with labelFilter to include only Good nodes query := `CALL apoc.path.spanningTree({id: 'a'}, {labelFilter: '+Good'}) YIELD path RETURN path` result, err := e.Execute(ctx, query, nil) if err != nil { t.Fatalf("Spanning tree query failed: %v", err) } // Should have only 2 edges (excluding Bad labeled node) if len(result.Rows) != 2 { t.Errorf("Expected 2 edges with Good label filter, got %d", len(result.Rows)) } } // TestApocPathSpanningTreeLimit tests limit configuration func TestApocPathSpanningTreeLimit(t *testing.T) { store := storage.NewMemoryEngine() e := NewStorageExecutor(store) ctx := context.Background() // Create a star graph: A connected to B, C, D, E store.CreateNode(&storage.Node{ID: "a", Labels: []string{"Node"}, Properties: map[string]interface{}{"name": "A"}}) store.CreateNode(&storage.Node{ID: "b", Labels: []string{"Node"}, Properties: map[string]interface{}{"name": "B"}}) store.CreateNode(&storage.Node{ID: "c", Labels: []string{"Node"}, Properties: map[string]interface{}{"name": "C"}}) store.CreateNode(&storage.Node{ID: "d", Labels: []string{"Node"}, Properties: map[string]interface{}{"name": "D"}}) store.CreateNode(&storage.Node{ID: "e", Labels: []string{"Node"}, Properties: map[string]interface{}{"name": "E"}}) store.CreateEdge(&storage.Edge{ID: "e1", Type: "CONNECTS", StartNode: "a", EndNode: "b"}) store.CreateEdge(&storage.Edge{ID: "e2", Type: "CONNECTS", StartNode: "a", EndNode: "c"}) store.CreateEdge(&storage.Edge{ID: "e3", Type: "CONNECTS", StartNode: "a", EndNode: "d"}) store.CreateEdge(&storage.Edge{ID: "e4", Type: "CONNECTS", StartNode: "a", EndNode: "e"}) // Test with limit: 2 query := `CALL apoc.path.spanningTree({id: 'a'}, {limit: 2}) YIELD path RETURN path` result, err := e.Execute(ctx, query, nil) if err != nil { t.Fatalf("Spanning tree query failed: %v", err) } if len(result.Rows) != 2 { t.Errorf("Expected 2 edges with limit:2, got %d", len(result.Rows)) } } // TestApocPathSpanningTreeDisconnectedGraph tests with disconnected components func TestApocPathSpanningTreeDisconnectedGraph(t *testing.T) { store := storage.NewMemoryEngine() e := NewStorageExecutor(store) ctx := context.Background() // Create two disconnected components: A-B and C-D store.CreateNode(&storage.Node{ID: "a", Labels: []string{"Node"}, Properties: map[string]interface{}{"name": "A"}}) store.CreateNode(&storage.Node{ID: "b", Labels: []string{"Node"}, Properties: map[string]interface{}{"name": "B"}}) store.CreateNode(&storage.Node{ID: "c", Labels: []string{"Node"}, Properties: map[string]interface{}{"name": "C"}}) store.CreateNode(&storage.Node{ID: "d", Labels: []string{"Node"}, Properties: map[string]interface{}{"name": "D"}}) store.CreateEdge(&storage.Edge{ID: "e1", Type: "CONNECTS", StartNode: "a", EndNode: "b"}) store.CreateEdge(&storage.Edge{ID: "e2", Type: "CONNECTS", StartNode: "c", EndNode: "d"}) // Get spanning tree from node A (should only include A-B component) query := `CALL apoc.path.spanningTree({id: 'a'}, {}) YIELD path RETURN path` result, err := e.Execute(ctx, query, nil) if err != nil { t.Fatalf("Spanning tree query failed: %v", err) } // Should have only 1 edge (A-B), not reaching C-D if len(result.Rows) != 1 { t.Errorf("Expected 1 edge in disconnected graph spanning tree, got %d", len(result.Rows)) } } // TestApocPathSpanningTreeDirection tests directional traversal func TestApocPathSpanningTreeDirection(t *testing.T) { store := storage.NewMemoryEngine() e := NewStorageExecutor(store) ctx := context.Background() // Create a directed graph: A -> B -> C // A <- D store.CreateNode(&storage.Node{ID: "a", Labels: []string{"Node"}, Properties: map[string]interface{}{"name": "A"}}) store.CreateNode(&storage.Node{ID: "b", Labels: []string{"Node"}, Properties: map[string]interface{}{"name": "B"}}) store.CreateNode(&storage.Node{ID: "c", Labels: []string{"Node"}, Properties: map[string]interface{}{"name": "C"}}) store.CreateNode(&storage.Node{ID: "d", Labels: []string{"Node"}, Properties: map[string]interface{}{"name": "D"}}) store.CreateEdge(&storage.Edge{ID: "e1", Type: "POINTS_TO", StartNode: "a", EndNode: "b"}) store.CreateEdge(&storage.Edge{ID: "e2", Type: "POINTS_TO", StartNode: "b", EndNode: "c"}) store.CreateEdge(&storage.Edge{ID: "e3", Type: "POINTS_TO", StartNode: "d", EndNode: "a"}) // Test with outgoing relationships only query := `CALL apoc.path.spanningTree({id: 'a'}, {relationshipFilter: '>POINTS_TO'}) YIELD path RETURN path` result, err := e.Execute(ctx, query, nil) if err != nil { t.Fatalf("Spanning tree query failed: %v", err) } // Should have only 2 edges (A->B->C), not including D->A if len(result.Rows) != 2 { t.Errorf("Expected 2 edges with outgoing filter, got %d", len(result.Rows)) } }

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/orneryd/Mimir'

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