feat: complete remaining Go backend modules
This commit is contained in:
1 parent
cea2751dc5
commit
aef5a97165
145 files changed
+18376
-199
No files matched your search
@@ -0,0 +1,161 @@
|
||||
package httpapi
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"git.nianxx.cn/wangxuming/NianAIGC/backend/internal/identity"
|
||||
"git.nianxx.cn/wangxuming/NianAIGC/backend/internal/prompt"
|
||||
"git.nianxx.cn/wangxuming/NianAIGC/backend/internal/publicapi"
|
||||
"git.nianxx.cn/wangxuming/NianAIGC/backend/internal/templates"
|
||||
)
|
||||
|
||||
type miscResolver struct {
|
||||
session identity.Session
|
||||
err error
|
||||
}
|
||||
|
||||
func (resolver miscResolver) Resolve(context.Context, string) (identity.Session, error) {
|
||||
return resolver.session, resolver.err
|
||||
}
|
||||
|
||||
type miscTemplateCatalog struct{ items []templates.Template }
|
||||
|
||||
func (c *miscTemplateCatalog) ListTemplates(context.Context, string) ([]templates.Template, error) {
|
||||
return c.items, nil
|
||||
}
|
||||
func (c *miscTemplateCatalog) CreateTemplate(_ context.Context, item templates.Template) (templates.Template, error) {
|
||||
c.items = append(c.items, item)
|
||||
return item, nil
|
||||
}
|
||||
func (c *miscTemplateCatalog) UpdateTemplate(context.Context, string, string, templates.Patch, time.Time) (templates.Template, bool, error) {
|
||||
return templates.Template{}, false, nil
|
||||
}
|
||||
func (c *miscTemplateCatalog) DeleteTemplate(context.Context, string, string) (templates.Template, bool, error) {
|
||||
return templates.Template{}, false, nil
|
||||
}
|
||||
|
||||
func TestMiscTemplateAndPromptRoutes(t *testing.T) {
|
||||
version := 1
|
||||
session := identity.Session{Version: 1, AuthMode: identity.AuthModeUser, SessionVersion: &version, User: identity.User{ID: "u1", ClientID: "platform", Role: "user"}}
|
||||
authorizer, _ := NewPlatformAuthorizer(AuthState{Required: true, Configured: true}, miscResolver{session: session})
|
||||
catalog := &miscTemplateCatalog{}
|
||||
service := templates.NewService(catalog, func() time.Time { return time.Date(2026, 8, 13, 0, 0, 0, 0, time.UTC) }, func() string { return "t1" })
|
||||
handler, err := NewMiscHandler(MiscDependencies{Platform: authorizer, Templates: service, PromptAssembler: prompt.Assemble})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
post := httptest.NewRequest(http.MethodPost, "/api/image-templates", bytes.NewBufferString(`{"name":" N ","prompt":" P "}`))
|
||||
post.AddCookie(&http.Cookie{Name: identity.SessionCookieName, Value: "cookie"})
|
||||
w := httptest.NewRecorder()
|
||||
handler.ServeHTTP(w, post)
|
||||
if w.Code != http.StatusCreated {
|
||||
t.Fatalf("create status=%d body=%s", w.Code, w.Body.String())
|
||||
}
|
||||
get := httptest.NewRequest(http.MethodGet, "/api/image-templates", nil)
|
||||
get.AddCookie(&http.Cookie{Name: identity.SessionCookieName, Value: "cookie"})
|
||||
w = httptest.NewRecorder()
|
||||
handler.ServeHTTP(w, get)
|
||||
if w.Code != 200 || !bytes.Contains(w.Body.Bytes(), []byte(`"templates"`)) {
|
||||
t.Fatalf("list status=%d body=%s", w.Code, w.Body.String())
|
||||
}
|
||||
assemble := httptest.NewRequest(http.MethodPost, "/api/prompt/assemble", bytes.NewBufferString(`{"mode":"image","manualPrompt":"@图片1","materials":[]}`))
|
||||
assemble.AddCookie(&http.Cookie{Name: identity.SessionCookieName, Value: "cookie"})
|
||||
w = httptest.NewRecorder()
|
||||
handler.ServeHTTP(w, assemble)
|
||||
if w.Code != 200 || !bytes.Contains(w.Body.Bytes(), []byte(`"requirements":{"image":1`)) {
|
||||
t.Fatalf("prompt status=%d body=%s", w.Code, w.Body.String())
|
||||
}
|
||||
}
|
||||
|
||||
type settingsStub struct {
|
||||
read any
|
||||
saved map[string]any
|
||||
err error
|
||||
}
|
||||
|
||||
func (s *settingsStub) Get(context.Context) (any, error) { return s.read, s.err }
|
||||
func (s *settingsStub) Save(_ context.Context, v map[string]any) (any, error) {
|
||||
s.saved = v
|
||||
return s.read, s.err
|
||||
}
|
||||
|
||||
type logsStub struct {
|
||||
entries any
|
||||
cleared bool
|
||||
err error
|
||||
}
|
||||
|
||||
func (s *logsStub) List(context.Context, LogFilters) (any, error) { return s.entries, s.err }
|
||||
func (s *logsStub) Clear(context.Context) error { s.cleared = true; return s.err }
|
||||
|
||||
func TestMiscSettingsLogsCapabilitiesAndOpenAPI(t *testing.T) {
|
||||
session := identity.Session{AuthMode: identity.AuthModeAdmin, User: identity.User{ID: "root", ClientID: "platform", Role: "super_admin"}}
|
||||
authorizer, _ := NewPlatformAuthorizer(AuthState{Required: true, Configured: true}, miscResolver{session: session})
|
||||
settings := &settingsStub{read: map[string]any{"groups": []any{}}}
|
||||
logs := &logsStub{entries: []any{map[string]any{"id": "l1"}}}
|
||||
public := publicapi.NewAuthenticator(publicapi.Config{APIKeys: "client:key"})
|
||||
handler, err := NewMiscHandler(MiscDependencies{Platform: authorizer, Settings: settings, Logs: logs, Public: public, Capabilities: func(context.Context) (any, error) { return []any{map[string]any{"id": "image.generate"}}, nil }})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for _, path := range []string{"/api/settings", "/api/logs"} {
|
||||
request := httptest.NewRequest(http.MethodGet, path, nil)
|
||||
request.AddCookie(&http.Cookie{Name: identity.SessionCookieName, Value: "cookie"})
|
||||
w := httptest.NewRecorder()
|
||||
handler.ServeHTTP(w, request)
|
||||
if w.Code != 200 {
|
||||
t.Fatalf("%s status %d %s", path, w.Code, w.Body.String())
|
||||
}
|
||||
}
|
||||
capRequest := httptest.NewRequest(http.MethodGet, "/api/v1/capabilities", nil)
|
||||
capRequest.Header.Set("authorization", "Bearer key")
|
||||
w := httptest.NewRecorder()
|
||||
handler.ServeHTTP(w, capRequest)
|
||||
if w.Code != 200 {
|
||||
t.Fatalf("capabilities %d %s", w.Code, w.Body.String())
|
||||
}
|
||||
w = httptest.NewRecorder()
|
||||
handler.ServeHTTP(w, httptest.NewRequest(http.MethodGet, "https://app.example.test/api/v1/openapi.json", nil))
|
||||
if w.Code != 200 || !bytes.Contains(w.Body.Bytes(), []byte(`"openapi":"3.1.0"`)) || !bytes.Contains(w.Body.Bytes(), []byte(`https://app.example.test`)) {
|
||||
t.Fatalf("openapi %d %s", w.Code, w.Body.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestMiscOpenAPIUsesConfiguredPublicOrigin(t *testing.T) {
|
||||
authorizer, _ := NewPlatformAuthorizer(AuthState{}, nil)
|
||||
handler, err := NewMiscHandler(MiscDependencies{Platform: authorizer, PublicOrigin: "https://public.example.test/base/"})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
response := httptest.NewRecorder()
|
||||
handler.ServeHTTP(response, httptest.NewRequest(http.MethodGet, "http://internal:3000/api/v1/openapi.json", nil))
|
||||
if response.Code != http.StatusOK || !bytes.Contains(response.Body.Bytes(), []byte(`"url":"https://public.example.test"`)) {
|
||||
t.Fatalf("status=%d body=%s", response.Code, response.Body.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestMiscFailsClosedAndHidesInfrastructureErrors(t *testing.T) {
|
||||
authorizer, _ := NewPlatformAuthorizer(AuthState{Required: true, Configured: true}, miscResolver{err: errors.New("db password secret")})
|
||||
handler, _ := NewMiscHandler(MiscDependencies{Platform: authorizer, PromptAssembler: prompt.Assemble})
|
||||
request := httptest.NewRequest(http.MethodPost, "/api/prompt/assemble", bytes.NewBufferString(`{"mode":"image"}`))
|
||||
request.AddCookie(&http.Cookie{Name: identity.SessionCookieName, Value: "cookie"})
|
||||
w := httptest.NewRecorder()
|
||||
handler.ServeHTTP(w, request)
|
||||
if w.Code != 500 || bytes.Contains(w.Body.Bytes(), []byte("password")) {
|
||||
t.Fatalf("status=%d body=%s", w.Code, w.Body.String())
|
||||
}
|
||||
w = httptest.NewRecorder()
|
||||
handler.ServeHTTP(w, httptest.NewRequest(http.MethodGet, "/api/settings", nil))
|
||||
var body map[string]any
|
||||
_ = json.Unmarshal(w.Body.Bytes(), &body)
|
||||
if w.Code != 401 {
|
||||
t.Fatalf("status=%d body=%#v", w.Code, body)
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user