95 lines
4.0 KiB
Go
95 lines
4.0 KiB
Go
package httpapi
|
|
|
|
import (
|
|
"context"
|
|
"net/http"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"git.nianxx.cn/wangxuming/NianAIGC/backend/internal/assets"
|
|
"git.nianxx.cn/wangxuming/NianAIGC/backend/internal/identity"
|
|
"git.nianxx.cn/wangxuming/NianAIGC/backend/internal/jobs"
|
|
"git.nianxx.cn/wangxuming/NianAIGC/backend/internal/layercompositions"
|
|
)
|
|
|
|
type layerCompositionRepositoryStub struct {
|
|
value layercompositions.Composition
|
|
found bool
|
|
}
|
|
|
|
func (repository *layerCompositionRepositoryStub) FindLayerComposition(_ context.Context, ownerID, jobID string) (layercompositions.Composition, bool, error) {
|
|
if !repository.found || repository.value.OwnerID != ownerID || repository.value.JobID != jobID {
|
|
return layercompositions.Composition{}, false, nil
|
|
}
|
|
return repository.value, true, nil
|
|
}
|
|
|
|
func (repository *layerCompositionRepositoryStub) SaveLayerComposition(_ context.Context, value layercompositions.Composition, version int64) (layercompositions.Composition, error) {
|
|
if repository.found && repository.value.Version != version {
|
|
return layercompositions.Composition{}, layercompositions.ErrConflict
|
|
}
|
|
if !repository.found && version != 0 {
|
|
return layercompositions.Composition{}, layercompositions.ErrConflict
|
|
}
|
|
value.Version = version + 1
|
|
value.CreatedAt = time.Date(2026, 9, 2, 8, 0, 0, 0, time.UTC)
|
|
value.UpdatedAt = value.CreatedAt
|
|
repository.value = value
|
|
repository.found = true
|
|
return value, nil
|
|
}
|
|
|
|
type layerCompositionAssetCatalog map[string]assets.Asset
|
|
|
|
func (catalog layerCompositionAssetCatalog) GetOwner(_ context.Context, ownerID, assetID string) (assets.Asset, bool, error) {
|
|
asset, found := catalog[assetID]
|
|
return asset, found && asset.OwnerID == ownerID, nil
|
|
}
|
|
|
|
func TestLayerCompositionsHTTPPersistsOnlyOwnedJobOutputsAndAssets(t *testing.T) {
|
|
jobStore := &httpJobStore{values: map[string]jobs.Job{
|
|
"job-1": {ID: "job-1", OwnerID: "owner", Capability: "image.generate", OutputAssetIDs: []string{"base"}},
|
|
"job-2": {ID: "job-2", OwnerID: "another-owner", Capability: "image.generate", OutputAssetIDs: []string{"foreign-base"}},
|
|
}}
|
|
jobService := jobs.NewService(jobStore, nil)
|
|
repository := &layerCompositionRepositoryStub{}
|
|
compositionService := layercompositions.NewService(repository, layerCompositionAssetCatalog{
|
|
"base": {ID: "base", OwnerID: "owner", Kind: assets.KindImage},
|
|
"layer": {ID: "layer", OwnerID: "owner", Kind: assets.KindImage},
|
|
})
|
|
authorizer, err := NewPlatformAuthorizer(AuthState{Required: true, Configured: true}, &fixedSessionResolver{session: identity.Session{User: identity.User{ID: "owner", ClientID: "platform", Role: "user"}}})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
handler, err := NewLayerCompositionsHandler(authorizer, jobService, compositionService, LayerCompositionsConfig{})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
missing := serveJSON(t, handler, http.MethodGet, "/api/layer-compositions/job-1", nil)
|
|
if missing.Code != http.StatusOK || strings.TrimSpace(missing.Body.String()) != `{"composition":null}` {
|
|
t.Fatalf("missing=%d %s", missing.Code, missing.Body.String())
|
|
}
|
|
|
|
saved := serveJSON(t, handler, http.MethodPut, "/api/layer-compositions/job-1", map[string]any{
|
|
"version": 0, "baseAssetId": "base", "baseVisible": true,
|
|
"layers": []any{map[string]any{"id": "layer-1", "assetId": "layer", "name": "主体", "visible": true, "box": []any{100, 100, 900, 900}, "rotation": 15, "source": "provider"}},
|
|
})
|
|
if saved.Code != http.StatusOK || repository.value.Version != 1 || repository.value.Layers[0].Rotation != 15 {
|
|
t.Fatalf("saved=%d %s value=%#v", saved.Code, saved.Body.String(), repository.value)
|
|
}
|
|
|
|
foreignJob := serveJSON(t, handler, http.MethodGet, "/api/layer-compositions/job-2", nil)
|
|
if foreignJob.Code != http.StatusNotFound {
|
|
t.Fatalf("foreign job=%d %s", foreignJob.Code, foreignJob.Body.String())
|
|
}
|
|
|
|
invalidBase := serveJSON(t, handler, http.MethodPut, "/api/layer-compositions/job-1", map[string]any{
|
|
"version": 1, "baseAssetId": "layer", "baseVisible": true, "layers": []any{},
|
|
})
|
|
if invalidBase.Code != http.StatusBadRequest {
|
|
t.Fatalf("invalid base=%d %s", invalidBase.Code, invalidBase.Body.String())
|
|
}
|
|
}
|