Commit c9b29a5

mo khan <mo@mokhan.ca>
2025-06-23 22:09:56
test: add memory persistence integration test
- Added testMemoryPersistence function to verify data persists across server restarts - Tests entity creation in first server instance and retrieval in second instance - Validates complete entity properties (name, type, observations) persist correctly - Ensures memory file is created and loaded properly on server startup - Comprehensive test coverage for the lazy loading persistence fix 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 01571b1
Changed files (1)
test/integration_test.go
@@ -294,6 +294,15 @@ func testMemorySpecific(t *testing.T, server TestServer) {
 
 		t.Log("Memory read_graph test passed")
 	})
+
+	t.Run("MemoryPersistence", func(t *testing.T) {
+		testDir, err := os.MkdirTemp("", "memory-persistence-test-*")
+		if err != nil {
+			t.Fatalf("Failed to create temp directory: %v", err)
+		}
+		defer os.RemoveAll(testDir)
+		testMemoryPersistence(t, testDir)
+	})
 }
 
 func testFetchSpecific(t *testing.T, server TestServer) {
@@ -547,4 +556,131 @@ func setupBenchEnvironment(b *testing.B) string {
 	}
 
 	return testDir
+}
+
+// testMemoryPersistence tests that memory server properly persists data to disk and loads it on restart
+func testMemoryPersistence(t *testing.T, testDir string) {
+	memoryFile := filepath.Join(testDir, "test_memory.json")
+	
+	// Phase 1: Create entities in first server instance
+	testEntity := map[string]interface{}{
+		"name":        "test_persistence_entity",
+		"entityType":  "concept",
+		"observations": []string{"This entity should persist across server restarts"},
+	}
+	
+	server1 := TestServer{
+		Name:   "memory",
+		Binary: "mcp-memory",
+		Args:   []string{"--memory-file", memoryFile},
+	}
+	
+	// Create entity in first server instance
+	resp1 := sendMCPRequest(t, server1, MCPRequest{
+		JSONRPC: "2.0",
+		ID:      1,
+		Method:  "tools/call",
+		Params: map[string]interface{}{
+			"name": "create_entities",
+			"arguments": map[string]interface{}{
+				"entities": []interface{}{testEntity},
+			},
+		},
+	})
+	
+	if resp1.Error != nil {
+		t.Fatalf("Failed to create entity in first server instance: %s", resp1.Error.Message)
+	}
+	
+	// Verify memory file was created
+	if _, err := os.Stat(memoryFile); os.IsNotExist(err) {
+		t.Fatalf("Memory file was not created: %s", memoryFile)
+	}
+	
+	// Phase 2: Start new server instance and verify entity persists
+	server2 := TestServer{
+		Name:   "memory",
+		Binary: "mcp-memory", 
+		Args:   []string{"--memory-file", memoryFile},
+	}
+	
+	// Read graph from second server instance
+	resp2 := sendMCPRequest(t, server2, MCPRequest{
+		JSONRPC: "2.0",
+		ID:      2,
+		Method:  "tools/call",
+		Params: map[string]interface{}{
+			"name":      "read_graph",
+			"arguments": map[string]interface{}{},
+		},
+	})
+	
+	if resp2.Error != nil {
+		t.Fatalf("Failed to read graph from second server instance: %s", resp2.Error.Message)
+	}
+	
+	// Parse and verify the persisted entity
+	var result map[string]interface{}
+	if err := json.Unmarshal(resp2.Result, &result); err != nil {
+		t.Fatalf("Failed to parse read_graph result: %v", err)
+	}
+	
+	content, ok := result["content"].([]interface{})
+	if !ok || len(content) == 0 {
+		t.Fatalf("Expected content array in response")
+	}
+	
+	textContent, ok := content[0].(map[string]interface{})
+	if !ok {
+		t.Fatalf("Expected text content object")
+	}
+	
+	graphText, ok := textContent["text"].(string)
+	if !ok {
+		t.Fatalf("Expected text field in content")
+	}
+	
+	var graph map[string]interface{}
+	if err := json.Unmarshal([]byte(graphText), &graph); err != nil {
+		t.Fatalf("Failed to parse graph JSON: %v", err)
+	}
+	
+	entities, ok := graph["entities"].(map[string]interface{})
+	if !ok {
+		t.Fatalf("Expected entities object in graph")
+	}
+	
+	// Verify our test entity persisted
+	persistedEntity, exists := entities["test_persistence_entity"]
+	if !exists {
+		t.Fatalf("Test entity did not persist across server restart")
+	}
+	
+	persistedEntityMap, ok := persistedEntity.(map[string]interface{})
+	if !ok {
+		t.Fatalf("Persisted entity is not a valid object")
+	}
+	
+	// Verify entity properties
+	if persistedEntityMap["name"] != "test_persistence_entity" {
+		t.Fatalf("Entity name did not persist correctly")
+	}
+	
+	if persistedEntityMap["entityType"] != "concept" {
+		t.Fatalf("Entity type did not persist correctly")
+	}
+	
+	observations, ok := persistedEntityMap["observations"].([]interface{})
+	if !ok || len(observations) != 1 {
+		t.Fatalf("Entity observations did not persist correctly")
+	}
+	
+	if observations[0] != "This entity should persist across server restarts" {
+		t.Fatalf("Entity observation content did not persist correctly")
+	}
+	
+	t.Log("Memory persistence test passed - entity persisted across server restart")
+	
+	// Clean up test memory file
+	os.Remove(memoryFile)
 }
\ No newline at end of file