ci / vet-and-test (pull_request) Successful in 46s
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.
92 lines
2.9 KiB
Go
92 lines
2.9 KiB
Go
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())
|
||
}
|
||
}
|