Files
Agent-System-Backend/internal/server/adminzone_test.go
T
weichen 62bfc6068a
ci / vet-and-test (pull_request) Successful in 46s
Declare admin-zone sections from compiled plugins (surface 2.9.0)
Why: the admin zone could not host plugin-declared partitions - KTD4
requires the RDM audit partition to be reachable by RDM domain admins and
base superadmins without hardcoding RDM into the base AdminZone.
Evidence: go test ./internal/app ./internal/server ./pkg/extension green
incl. new admin-zone recording/endpoint tests; surface snapshot test
green after surface.txt update; CI (Dev composite) is authoritative.
Impact: extension surface 2.8.0 -> 2.9.0 (Registry.AddAdminZone +
AdminZoneSpec, fail-closed on invalid specs); applyCompiled records
declarations into the plugin summary; new authenticated GET
/api/admin-zone/sections returns the flattened, ordered declaration list.
Entry visibility stays metadata-only - data capability remains enforced
by each section's own command surface (fail-closed).
Refs: WP3-I3/KTD4; task card feature-adminzone-plugin-sections.
2026-10-12 02:28:51 +00:00

92 lines
2.9 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 server
import (
"encoding/json"
"net/http"
"net/http/httptest"
"path/filepath"
"testing"
"agent-system-backend/internal/bus"
"agent-system-backend/internal/plugins"
"agent-system-backend/internal/profiles"
"agent-system-backend/internal/runmgr"
"agent-system-backend/internal/runtime"
"agent-system-backend/internal/settings"
"agent-system-backend/internal/store"
"agent-system-backend/internal/tools"
)
// WP3-I3:GET /api/admin-zone/sections 展平编译插件的分区声明并按
// Order→ID 稳定排序;无声明时空数组(非 null)。
func TestListAdminZoneSections(t *testing.T) {
dir := t.TempDir()
st, err := store.OpenSQLite(filepath.Join(dir, "test.db"))
if err != nil {
t.Fatal(err)
}
t.Cleanup(func() { st.Close() })
b := bus.New()
reg := tools.NewRegistry()
reg.RegisterBuiltin()
setSvc := settings.NewService(st)
profSvc := profiles.New(st)
profSvc.EnsureDefault()
mgr := runmgr.New(st, b, reg, profSvc, setSvc, &runtime.LLMRunner{}, &runtime.SubLLMRunner{}, &runtime.MockRunner{}, &runtime.MockSubagent{})
ph := plugins.New(st, reg, setSvc, filepath.Join(dir, "plugins"))
srv := New(st, mgr, reg, profSvc, setSvc, ph)
srv.Auth = NewAuthenticator(st, true)
srv.CompiledPlugins = []CompiledPlugin{
{ID: "rdm", AdminZones: []AdminZoneSection{
{ID: "rdm.audit", Title: "项目追溯与审计", Icon: "search", Order: 20},
}},
{ID: "other", AdminZones: []AdminZoneSection{
{ID: "other.z", Title: "Z", Order: 10},
{ID: "other.a", Title: "A", Order: 10},
}},
}
h := srv.Handler()
key, err := st.CreateAPIKey("alice", "e2e")
if err != nil {
t.Fatal(err)
}
get := func(path string) *httptest.ResponseRecorder {
req := httptest.NewRequest(http.MethodGet, path, nil)
req.Header.Set("Authorization", "Bearer "+key)
rec := httptest.NewRecorder()
h.ServeHTTP(rec, req)
return rec
}
// 未认证拒绝。
if rec := httptest.NewRecorder(); func() *httptest.ResponseRecorder {
req := httptest.NewRequest(http.MethodGet, "/api/admin-zone/sections", nil)
h.ServeHTTP(rec, req)
return rec
}().Code != http.StatusUnauthorized {
t.Fatalf("unauthenticated request should 401")
}
rec := get("/api/admin-zone/sections")
if rec.Code != http.StatusOK {
t.Fatalf("status %d: %s", rec.Code, rec.Body.String())
}
var got []AdminZoneSection
if err := json.Unmarshal(rec.Body.Bytes(), &got); err != nil {
t.Fatal(err)
}
wantIDs := []string{"other.a", "other.z", "rdm.audit"} // Order 同为 10 的按 ID,再 Order 20
if len(got) != 3 {
t.Fatalf("sections = %+v", got)
}
for i, w := range wantIDs {
if got[i].ID != w {
t.Fatalf("sections[%d] = %s, want %s (full: %+v)", i, got[i].ID, w, got)
}
}
// 无声明时空数组非 null。
srv.CompiledPlugins = nil
if rec := get("/api/admin-zone/sections"); rec.Body.String() == "null" {
t.Fatalf("empty listing must be [] not null: %s", rec.Body.String())
}
}