Files
HomeAgent/internal/plugins/webui/test/graph_source_test.go
JianFeeeee bb29096f60 refactor(webui): 图谱判据迁到 test/ —— 导出 GraphDataForVisual 一层转换
graph_source_test.go        → test/
    handler_graph_pulse_test.go → test/     (7 条判据)
    webui/       174 → 167
    webui/test/   28 →  35
    合计 202 不变

## 这一条必须动生产代码,理由要写清

判据想测的是「GraphData 的 raw map 被裁成可视化视图时,稠密向量必须被剥掉」。
两条路都不通:

    走 HTTP 端点 /api/v1/memory/graph
      → 端点输入来自 h.memory.GraphData(),h.memory 是私有字段,
        包外无法注入合成数据。测不了。

    包内测试直接调 graphDataForVisual
      → 这正是要摆脱的白盒写法。

所以导出这一层转换 `graphDataForVisual → GraphDataForVisual`。它不是
为测试造出来的形状:函数的输入输出本来就是本包唯一的「raw map →
visual map」语义,端点在 handler_memory.go:199 调它。导出的是真实边界,
不是内部细节。(判据 §5.3「不要为满足测试导出内部」指的是后者。)

顺带把 `graphBlockView`(私有 JSON 结构)在测试侧改成匿名结构体 ——
它只用于反序列化断言,没有必要引用包内类型。

## 改走真实路由暴露的两个事实

### ① `newGraphHandler` 直接设 `&Handler{memory: m}`

改成 `NewHandler(sdk.New("webui", sdk.SDKConfig{Memory: m, ...}))` ——
`Memory` 确实能经 SDKConfig 注入(plugin.go:457 `base.SetMemoryAPI(cfg.Memory)`)。

### ② 503 暴露了鉴权要求

改走路由后立刻:

    status = 503, want 200

`requireAPI` 需要 api_key,而最小装配没配。补 `seedWebUIConfig` 后 200。
之前直接调 handler 的写法**从来不知道有这个要求** —— 路由层挡掉的东西,
绕过路由就看不见。

## 判据有效性(变异验证)

在 `GraphDataForVisual` 里把裁剪短路掉(`if blocks != nil { return out }`),
实测红,且输出直接暴露泄漏内容:

    --- FAIL: TestHandleMemoryGraph_StripsVector
        response still contains vector field:
        {"data":{"memory_blocks":[{"id":"b_old",...,"vector":[0.1,0.2,0.3],...
         "success":true}

稠密向量确实会被下发到前端。恢复后全绿。

## 验证

    go build ./...                  PASS
    go vet ./...                    PASS
    gofmt -l                        干净
    go test ./... -count=1          67 包全过,0 FAIL
2026-11-04 22:06:35 +08:00

55 lines
2.2 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package test
import (
"encoding/json"
"testing"
"github.com/JianFeeeee/HologramAgent/internal/memory"
"github.com/JianFeeeee/HologramAgent/internal/plugins/webui"
)
// 星图数据源必须来自块体系(memory_blocks),而不是停写的旧表 entities。
//
// 判据:真实图谱里 memory_blocks 远多于 entities,且块侧仍在增长。
// 这里用合成数据钉住「有块时节点数 == 块数」,防未来又切回 nodes。
func TestGraphDataExposesBlocksForStarmap(t *testing.T) {
// 模拟后端 GraphData 的返回:旧表 1 个节点,块表 3 个块 + 2 条边
data := map[string]interface{}{
"nodes": []map[string]interface{}{{"id": int64(1), "name": "旧表实体", "type": "Concept"}},
"edges": []map[string]interface{}{},
"memory_blocks": []memory.MemoryBlock{
{ID: "blk_src_a", Modality: memory.BlockText, Text: "张三喜欢咖啡", Source: "sentence"},
{ID: "blk_ent_b", Modality: memory.BlockText, Text: "张三", Source: "triple", SemanticType: "Person"},
{ID: "blk_ent_c", Modality: memory.BlockText, Text: "咖啡", Source: "triple"},
},
"memory_block_edges": []memory.MemoryBlockEdge{
{ID: 1, SourceKind: "block", SourceID: "blk_src_a", TargetKind: "block", TargetID: "blk_ent_b", Type: "contains"},
{ID: 2, SourceKind: "block", SourceID: "blk_src_a", TargetKind: "block", TargetID: "blk_ent_c", Type: "contains"},
},
}
out := webui.GraphDataForVisual(data)
// 前端读的是 memory_blocks 字段
blocks, ok := out["memory_blocks"]
if !ok {
t.Fatal("GraphData 必须下发 memory_blocks(前端星图的真实数据源)")
}
raw, _ := json.Marshal(blocks)
// 只用 JSON 结构断言下发内容,不引用包内私有类型。
var got []struct {
ID string `json:"id"`
Modality string `json:"modality"`
Text string `json:"text"`
HasData bool `json:"has_data"`
Size int64 `json:"size"`
}
if err := json.Unmarshal(raw, &got); err != nil {
t.Fatal(err)
}
if len(got) != 3 {
t.Fatalf("memory_blocks 应下发 3 个,实际 %d", len(got))
}
if _, hasNodes := out["nodes"]; !hasNodes {
t.Fatal("旧 nodes 字段应保留(向后兼容),只是前端不再依赖它")
}
}