Files
Agent-System-Backend/internal/store/platform_test.go
weichenandCursor cd5b82186d Add the public extension surface and platform services
Why: Downstream products must extend the base through a public package and host API instead of editing internal code.
Evidence: go test ./... passed, including plugin v2 assets, sidecar startup, migration v13, pending confirms, HITL timeout, hash embedder, command pairs, and the extension surface snapshot.
Impact: apiVersion 2.0-experimental rejects empty network allowlists for declarative HTTP. Hash embeddings stay opt-in via models.embedding.provider=hash. Plugin secrets resolve per owner at execution time.
Refs: docs/proposals/2026-10-01-plugin-contract-v2.md
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-01 10:35:02 +00:00

98 lines
2.9 KiB
Go

package store
import (
"path/filepath"
"testing"
"time"
core "agent-system-core"
)
func TestPlatformTables(t *testing.T) {
st, err := OpenSQLite(filepath.Join(t.TempDir(), "p.db"))
if err != nil {
t.Fatal(err)
}
t.Cleanup(func() { st.Close() })
if err := st.SetPluginEnabled("acme", "rdm", false); err != nil {
t.Fatal(err)
}
on, err := st.PluginEnabled("acme", "rdm")
if err != nil || on {
t.Fatalf("disabled grant: on=%v err=%v", on, err)
}
on, err = st.PluginEnabled("acme", "other")
if err != nil || !on {
t.Fatalf("missing grant defaults to enabled: on=%v err=%v", on, err)
}
if err := st.SetPluginSchemaVersion("rdm", 2); err != nil {
t.Fatal(err)
}
if v, err := st.PluginSchemaVersion("rdm"); err != nil || v != 2 {
t.Fatalf("schema: %d %v", v, err)
}
if err := st.PutPluginKV("rdm", "acme", "slice", "s1"); err != nil {
t.Fatal(err)
}
got, ok, err := st.GetPluginKV("rdm", "acme", "slice")
if err != nil || !ok || got != "s1" {
t.Fatalf("kv: %q ok=%v err=%v", got, ok, err)
}
task, err := st.CreateBackgroundTask("acme", "ingest", "入库", "")
if err != nil {
t.Fatal(err)
}
if task.ConversationID != "" || task.Status != "queued" {
t.Fatalf("task should not require a conversation: %+v", task)
}
if err := st.UpdateBackgroundTask("acme", task.ID, "done", 100, ""); err != nil {
t.Fatal(err)
}
task, err = st.GetBackgroundTask("acme", task.ID)
if err != nil || task.Status != "done" || task.Progress != 100 {
t.Fatalf("updated: %+v %v", task, err)
}
exp := time.Now().UTC().Add(time.Hour)
mem, err := st.PutMemory("acme", core.MemoryEntry{Scope: "user", Type: "preference", Content: "用中文", Source: "manual", ExpiresAt: &exp})
if err != nil || mem.ID == "" {
t.Fatal(err)
}
list, err := st.ListMemory("acme", "user", "")
if err != nil || len(list) != 1 || list[0].Content != "用中文" || list[0].ExpiresAt == nil {
t.Fatalf("memory: %+v %v", list, err)
}
if err := st.AppendAuditEvent(AuditEvent{Owner: "acme", Action: "upload", Target: "f", Evidence: `{"ok":true}`, TraceID: "tr"}); err != nil {
t.Fatal(err)
}
evs, err := st.ListAuditEvents("acme", 10)
if err != nil || len(evs) != 1 || evs[0].Action != "upload" || evs[0].TraceID != "tr" {
t.Fatalf("audit: %+v %v", evs, err)
}
if err := st.SavePendingConfirm("card1", "acme", `{"id":"x"}`); err != nil {
t.Fatal(err)
}
owner, payload, ok, err := st.TakePendingConfirm("card1")
if err != nil || !ok || owner != "acme" || payload != `{"id":"x"}` {
t.Fatalf("take: %s %s %v %v", owner, payload, ok, err)
}
_, _, ok, err = st.TakePendingConfirm("card1")
if err != nil || ok {
t.Fatalf("second take must miss: ok=%v err=%v", ok, err)
}
st1, err := st.AccountTokens("acme", 30, 40)
if err != nil || st1.Total != 30 || st1.Over {
t.Fatalf("under budget: %+v %v", st1, err)
}
st2, err := st.AccountTokens("acme", 20, 40)
if err != nil || st2.Total != 50 || !st2.Over {
t.Fatalf("over budget: %+v %v", st2, err)
}
}