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
92 lines
3.2 KiB
Go
92 lines
3.2 KiB
Go
package server
|
||
|
||
import (
|
||
"encoding/json"
|
||
"net/http"
|
||
"net/http/httptest"
|
||
"path/filepath"
|
||
"testing"
|
||
|
||
"git-ssh.u1680832.nyat.app/weichen/Agent-System-Backend.git/internal/bus"
|
||
"git-ssh.u1680832.nyat.app/weichen/Agent-System-Backend.git/internal/plugins"
|
||
"git-ssh.u1680832.nyat.app/weichen/Agent-System-Backend.git/internal/profiles"
|
||
"git-ssh.u1680832.nyat.app/weichen/Agent-System-Backend.git/internal/runmgr"
|
||
"git-ssh.u1680832.nyat.app/weichen/Agent-System-Backend.git/internal/runtime"
|
||
"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/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())
|
||
}
|
||
}
|