mirror of
https://gitcode.com/JianFeeeee/HomeAgent.git
synced 2026-09-21 17:38:10 +00:00
228 lines
5.1 KiB
Go
228 lines
5.1 KiB
Go
package memory
|
||
|
||
import (
|
||
"os"
|
||
"testing"
|
||
)
|
||
|
||
func newTestGraph(t *testing.T) *GraphDB {
|
||
t.Helper()
|
||
f, err := os.CreateTemp("", "graph_test_*.db")
|
||
if err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
f.Close()
|
||
os.Remove(f.Name())
|
||
|
||
g, err := NewGraphDB(f.Name())
|
||
if err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
return g
|
||
}
|
||
|
||
func TestNewGraphDB(t *testing.T) {
|
||
g := newTestGraph(t)
|
||
defer os.Remove(g.dbPath)
|
||
defer g.Close()
|
||
|
||
stats, err := g.Introspect()
|
||
if err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
if stats["entity_count"].(int) != 0 {
|
||
t.Errorf("expected 0 entities, got %d", stats["entity_count"])
|
||
}
|
||
if stats["relation_count"].(int) != 0 {
|
||
t.Errorf("expected 0 relations, got %d", stats["relation_count"])
|
||
}
|
||
}
|
||
|
||
func TestCommitTriples(t *testing.T) {
|
||
g := newTestGraph(t)
|
||
defer os.Remove(g.dbPath)
|
||
defer g.Close()
|
||
|
||
triples := []Triple{
|
||
{Subject: "张三", Relation: "喜欢", Object: "编程"},
|
||
{Subject: "张三", Relation: "居住", Object: "北京"},
|
||
}
|
||
|
||
ec, rc, err := g.Commit(triples, "test_session", 1)
|
||
if err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
if ec != 4 {
|
||
t.Errorf("expected 4 entity ops (张三×2, 编程, 北京), got %d", ec)
|
||
}
|
||
if rc != 2 {
|
||
t.Errorf("expected 2 relations, got %d", rc)
|
||
}
|
||
}
|
||
|
||
func TestCommitEmptyTriples(t *testing.T) {
|
||
g := newTestGraph(t)
|
||
defer os.Remove(g.dbPath)
|
||
defer g.Close()
|
||
|
||
ec, rc, err := g.Commit(nil, "test", 0)
|
||
if err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
if ec != 0 || rc != 0 {
|
||
t.Errorf("expected 0,0 for nil triples, got %d,%d", ec, rc)
|
||
}
|
||
}
|
||
|
||
func TestRecallByKeywords(t *testing.T) {
|
||
g := newTestGraph(t)
|
||
defer os.Remove(g.dbPath)
|
||
defer g.Close()
|
||
|
||
g.Commit([]Triple{
|
||
{Subject: "咖啡", Relation: "属于", Object: "饮品"},
|
||
{Subject: "咖啡", Relation: "含有", Object: "咖啡因"},
|
||
}, "session1", 0)
|
||
|
||
result, err := g.Recall([]string{"咖啡"}, nil, 1, "")
|
||
if err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
if len(result.Entities) == 0 {
|
||
t.Error("expected entities for keyword '咖啡'")
|
||
}
|
||
}
|
||
|
||
func TestRecallBySeedEntity(t *testing.T) {
|
||
g := newTestGraph(t)
|
||
defer os.Remove(g.dbPath)
|
||
defer g.Close()
|
||
|
||
g.Commit([]Triple{
|
||
{Subject: "Go", Relation: "是", Object: "编程语言"},
|
||
{Subject: "Go", Relation: "用于", Object: "后端开发"},
|
||
}, "session2", 0)
|
||
|
||
result, err := g.Recall(nil, []string{"Go"}, 1, "")
|
||
if err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
if len(result.Entities) == 0 {
|
||
t.Error("expected entities for seed 'Go'")
|
||
}
|
||
}
|
||
|
||
func TestRecallWithDepth(t *testing.T) {
|
||
g := newTestGraph(t)
|
||
defer os.Remove(g.dbPath)
|
||
defer g.Close()
|
||
|
||
g.Commit([]Triple{
|
||
{Subject: "甲", Relation: "认识", Object: "乙"},
|
||
{Subject: "乙", Relation: "认识", Object: "丙"},
|
||
}, "session3", 0)
|
||
|
||
result, err := g.Recall(nil, []string{"甲"}, 2, "")
|
||
if err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
if len(result.Relations) == 0 {
|
||
t.Error("expected relations with depth search")
|
||
}
|
||
}
|
||
|
||
func TestPurgeHard(t *testing.T) {
|
||
g := newTestGraph(t)
|
||
defer os.Remove(g.dbPath)
|
||
defer g.Close()
|
||
|
||
g.Commit([]Triple{
|
||
{Subject: "临时", Relation: "用于", Object: "测试"},
|
||
}, "session4", 0)
|
||
|
||
n, err := g.Purge(map[string]string{"subject_contains": "临时"}, "hard")
|
||
if err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
if n != 1 {
|
||
t.Errorf("expected 1 purged relation, got %d", n)
|
||
}
|
||
|
||
stats, _ := g.Introspect()
|
||
if stats["relation_count"].(int) != 0 {
|
||
t.Errorf("expected 0 relations after purge, got %d", stats["relation_count"])
|
||
}
|
||
}
|
||
|
||
func TestPurgeSoft(t *testing.T) {
|
||
g := newTestGraph(t)
|
||
defer os.Remove(g.dbPath)
|
||
defer g.Close()
|
||
|
||
g.Commit([]Triple{
|
||
{Subject: "可删除", Relation: "属于", Object: "测试"},
|
||
}, "session5", 0)
|
||
|
||
n, err := g.Purge(map[string]string{"subject_contains": "可删除"}, "soft")
|
||
if err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
if n != 1 {
|
||
t.Errorf("expected 1 soft-deleted relation, got %d", n)
|
||
}
|
||
|
||
stats, _ := g.Introspect()
|
||
if stats["relation_count"].(int) != 0 {
|
||
t.Errorf("expected 0 active relations after soft-delete, got %d", stats["relation_count"])
|
||
}
|
||
}
|
||
|
||
func TestArchive(t *testing.T) {
|
||
g := newTestGraph(t)
|
||
defer os.Remove(g.dbPath)
|
||
defer g.Close()
|
||
|
||
// 直接插入一条旧记录
|
||
g.db.Exec(`INSERT INTO entities (id, name, type) VALUES (1, '旧数据', 'Concept')`)
|
||
g.db.Exec(`INSERT INTO relations (source_id, target_id, relation_type, created_at)
|
||
VALUES (1, 1, '包含', datetime('now', '-1 day'))`)
|
||
|
||
n, err := g.Archive(0)
|
||
if err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
if n != 1 {
|
||
t.Errorf("expected 1 archived relation, got %d", n)
|
||
}
|
||
}
|
||
|
||
func TestIntrospectHotspots(t *testing.T) {
|
||
g := newTestGraph(t)
|
||
defer os.Remove(g.dbPath)
|
||
defer g.Close()
|
||
|
||
g.Commit([]Triple{
|
||
{Subject: "热门话题", Relation: "关于", Object: "AI"},
|
||
{Subject: "热门话题", Relation: "关于", Object: "机器学习"},
|
||
{Subject: "冷门话题", Relation: "关于", Object: "旧技术"},
|
||
}, "session7", 0)
|
||
|
||
stats, _ := g.Introspect()
|
||
hotspots := stats["memory_hotspots"].([]map[string]interface{})
|
||
if len(hotspots) == 0 {
|
||
t.Error("expected hotspots")
|
||
}
|
||
}
|
||
|
||
func TestPlaceholders(t *testing.T) {
|
||
if placeholders(0) != "NULL" {
|
||
t.Errorf("expected NULL for n=0, got %s", placeholders(0))
|
||
}
|
||
if placeholders(1) != "?" {
|
||
t.Errorf("expected '?' for n=1, got %s", placeholders(1))
|
||
}
|
||
if placeholders(3) != "?,?,?" {
|
||
t.Errorf("expected '?,?,?' for n=3, got %s", placeholders(3))
|
||
}
|
||
}
|