Why: Allow consumers to download an immutable module revision without nested source checkouts or local path replacements. Evidence: SELF package tests and the prior canonical-path rejection are recorded in the Dev dependency-workspace task card; remote consumption is replayed against the committed candidate. Impact: Change the module identity and its Go imports while preserving API behavior. Existing historical submodule revisions remain buildable. Refs: Versioned dependencies U1/U3; feature/dependency-workspace
58 lines
2.0 KiB
Go
58 lines
2.0 KiB
Go
package app
|
||
|
||
import (
|
||
"context"
|
||
"path/filepath"
|
||
"testing"
|
||
|
||
"git-ssh.u1680832.nyat.app/weichen/Agent-System-Backend.git/internal/rag"
|
||
"git-ssh.u1680832.nyat.app/weichen/Agent-System-Backend.git/internal/settings"
|
||
"git-ssh.u1680832.nyat.app/weichen/Agent-System-Backend.git/internal/store"
|
||
"git-ssh.u1680832.nyat.app/weichen/Agent-System-Backend.git/pkg/extension"
|
||
)
|
||
|
||
// EXT-11 红测:注入前 NewScopedHost fail-closed;注入后重建句柄与分发期同构
|
||
// (owner 作用域、PluginID、KV 隔离、知识删除前缀强制)。
|
||
func TestScopedHostFactory(t *testing.T) {
|
||
// 注入前:fail-closed。
|
||
if _, err := extension.NewScopedHost("alice", "rdm"); err == nil {
|
||
t.Fatal("before wiring, NewScopedHost must fail closed(工厂未注入)")
|
||
}
|
||
|
||
st, err := store.OpenSQLite(filepath.Join(t.TempDir(), "t.db"))
|
||
if err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
t.Cleanup(func() { st.Close() })
|
||
set := settings.NewService(st)
|
||
pipe := rag.NewPipeline(st, set, nil, nil)
|
||
caps := hostcaps{st: st, pipe: pipe, set: set}
|
||
|
||
// 组合根同款注入(app.Run 内以 wireScopedHostFactory 接线;此处直接调内部函数)。
|
||
wireScopedHostFactory(caps)
|
||
t.Cleanup(func() { extension.SetScopedHostFactory(nil) })
|
||
|
||
h, err := extension.NewScopedHost("alice", "rdm")
|
||
if err != nil {
|
||
t.Fatalf("NewScopedHost: %v", err)
|
||
}
|
||
if h.Owner() != "alice" || h.PluginID() != "rdm" {
|
||
t.Fatalf("Owner/PluginID = %s/%s, want alice/rdm", h.Owner(), h.PluginID())
|
||
}
|
||
// KV 往返落 owner 作用域。
|
||
if err := h.KVPut("k1", "v1"); err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
if v, ok, err := h.KVGet("k1"); err != nil || !ok || v != "v1" {
|
||
t.Fatalf("KVGet = %q ok=%v err=%v", v, ok, err)
|
||
}
|
||
// 同构性:知识删除前缀强制(manual 不可及)。
|
||
if err := h.KnowledgeDelete(context.Background(), "manual"); err == nil {
|
||
t.Fatal("scoped host must keep the plugin:<id> prefix enforcement")
|
||
}
|
||
// 空 owner/pluginID:拒绝。
|
||
if _, err := extension.NewScopedHost("", "rdm"); err == nil {
|
||
t.Fatal("empty owner must be rejected")
|
||
}
|
||
}
|