Files
Codex Local bf1233d5df
ci / verify (push) Canceled after 0s
feat: expand companion platform, device controls, and memoir workflows
Add customer and operator login, BLE provisioning, device fleet controls, call memory, memoir generation, and refreshed family and maintenance portals. Include API contracts, migrations, firmware sources, tests, assets, and deployment documentation.
2026-10-08 10:06:44 +08:00

114 lines
4.6 KiB
Go

package elderagent
import (
"context"
"encoding/json"
"fmt"
"net/http"
"net/http/httptest"
"strings"
"testing"
)
func TestProviderCreateAndRecover(t *testing.T) {
var created, updated int
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Method != "POST" || r.URL.Query().Get("Version") != "2025-08-01" || r.Header.Get("Authorization") == "" {
t.Error("incorrect signed API request")
}
var body map[string]any
json.NewDecoder(r.Body).Decode(&body)
switch r.URL.Query().Get("Action") {
case "AibotQuery":
if body["AccessType"] != "public" {
t.Error("name lookup requires public AccessType")
}
if created == 0 {
fmt.Fprint(w, `{"Result":{"Bots":[]}}`)
} else {
fmt.Fprint(w, `{"Result":{"Bots":[{"Id":"bot-elder","Name":"elder-1"}]}}`)
}
case "AibotCreate":
created++
if body["AccessType"] != "public" || body["Config"] == nil || body["Name"] != "elder-1" {
t.Error("missing creation fields")
}
fmt.Fprint(w, `{"Result":{"Id":"bot-elder"}}`)
case "AibotUpdate":
updated++
fmt.Fprint(w, `{"Result":{}}`)
default:
t.Error("unexpected action")
}
}))
defer server.Close()
c := NewClient("test-ak", "test-sk", "", server.URL, "")
for n := 0; n < 2; n++ {
b, err := c.Ensure(context.Background(), "elder-1", map[string]any{"S2SConfig": map[string]any{}}, map[string]any{})
if err != nil || b.ID != "bot-elder" {
t.Fatal(b, err)
}
}
if created != 1 || updated != 1 {
t.Fatal(created, updated)
}
}
func TestConfigurationIsPerElderAndKeepsS2SOnServer(t *testing.T) {
s := Service{Template: []byte(`{"templates":{"s2s_hybrid":{"Config":{"S2SConfig":{"Provider":"volcano","OutputMode":1,"ProviderParams":{"app":{"appid":"test-app","token":"test-token"},"dialog":{"system_role":"温暖陪伴","dialog_id":"shared"}}},"MemoryConfig":{"Enable":true}}}}}`), CallbackURL: "https://example.com/callback", CallbackSecret: []byte(strings.Repeat("k", 32))}
a, aa, err := s.Configuration("elder-1", "张奶奶")
if err != nil {
t.Fatal(err)
}
b, ba, err := s.Configuration("elder-2", "李爷爷")
if err != nil {
t.Fatal(err)
}
rawA, _ := json.Marshal(a)
rawB, _ := json.Marshal(b)
if !strings.Contains(string(rawA), "张奶奶") || strings.Contains(string(rawB), "张奶奶") || strings.Contains(string(rawA), "dialog_id") {
t.Fatal("elder config isolation failed")
}
if a["S2SConfig"].(map[string]any)["OutputMode"] != 0 || aa["ServerMessageURLForRTS"] == ba["ServerMessageURLForRTS"] {
t.Fatal("incorrect S2S/callback config")
}
if a["MemoryConfig"].(map[string]any)["Enable"] != false {
t.Fatal("inherited shared memory")
}
}
func TestProviderErrorDoesNotExposeConfiguration(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, `{"ResponseMetadata":{"Error":{"Code":"InvalidParameter","Message":"secret-token"}}}`)
}))
defer server.Close()
_, err := NewClient("ak", "sk", "", server.URL, "").Ensure(context.Background(), "elder", nil, nil)
if err == nil || strings.Contains(err.Error(), "secret-token") {
t.Fatal(err)
}
}
func TestPersonaReadbackChecksManagedFieldsAndMasksErrors(t *testing.T) {
config := map[string]any{"S2SConfig": map[string]any{"ProviderParams": map[string]any{"app": map[string]any{"token": "SECRET_TOKEN"}, "dialog": map[string]any{"system_role": "新角色"}}}, "MemoryConfig": map[string]any{"Enable": false}}
agent := map[string]any{"WelcomeMessage": "开场", "ServerMessageURLForRTS": "https://example.com/callback", "ServerMessageSignatureForRTS": "signature"}
stale := false
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.URL.Query().Get("Action") != "AibotQuery" {
t.Error("wrong verification action")
}
role := "新角色"
if stale {
role = "SECRET_STALE_ROLE"
}
actual := map[string]any{"S2SConfig": map[string]any{"ProviderParams": map[string]any{"dialog": map[string]any{"system_role": role}}}, "MemoryConfig": map[string]any{"Enable": false}}
json.NewEncoder(w).Encode(map[string]any{"Result": map[string]any{"Bots": []Bot{{ID: "bot", Config: actual, AgentConfig: agent}}}})
}))
defer server.Close()
c := NewClient("ak", "sk", "", server.URL, "")
if err := c.VerifyConfiguration(context.Background(), "bot", config, agent); err != nil {
t.Fatal("masked credentials failed verification", err)
}
stale = true
if err := c.VerifyConfiguration(context.Background(), "bot", config, agent); err == nil || strings.Contains(err.Error(), "SECRET") {
t.Fatal("unverified or exposed provider config", err)
}
}