97 lines
3.5 KiB
Go
97 lines
3.5 KiB
Go
package layercompositions
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"testing"
|
|
"time"
|
|
|
|
"git.nianxx.cn/wangxuming/NianAIGC/backend/internal/assets"
|
|
)
|
|
|
|
type compositionRepositoryStub struct {
|
|
value Composition
|
|
found bool
|
|
}
|
|
|
|
func (repository *compositionRepositoryStub) FindLayerComposition(_ context.Context, ownerID, jobID string) (Composition, bool, error) {
|
|
if !repository.found || repository.value.OwnerID != ownerID || repository.value.JobID != jobID {
|
|
return Composition{}, false, nil
|
|
}
|
|
return repository.value, true, nil
|
|
}
|
|
|
|
func (repository *compositionRepositoryStub) SaveLayerComposition(_ context.Context, value Composition, expectedVersion int64) (Composition, error) {
|
|
if repository.found && repository.value.Version != expectedVersion {
|
|
return Composition{}, ErrConflict
|
|
}
|
|
if !repository.found && expectedVersion != 0 {
|
|
return Composition{}, ErrConflict
|
|
}
|
|
now := time.Date(2026, 9, 2, 8, 0, 0, 0, time.UTC)
|
|
value.Version = expectedVersion + 1
|
|
value.CreatedAt = now
|
|
value.UpdatedAt = now
|
|
repository.value = value
|
|
repository.found = true
|
|
return value, nil
|
|
}
|
|
|
|
type assetCatalogStub map[string]assets.Asset
|
|
|
|
func (catalog assetCatalogStub) GetOwner(_ context.Context, ownerID, assetID string) (assets.Asset, bool, error) {
|
|
asset, found := catalog[assetID]
|
|
return asset, found && asset.OwnerID == ownerID, nil
|
|
}
|
|
|
|
func TestServiceSavesOwnedCompositionAndNormalizesRotation(t *testing.T) {
|
|
repository := &compositionRepositoryStub{}
|
|
catalog := assetCatalogStub{
|
|
"base": {ID: "base", OwnerID: "owner", Kind: assets.KindImage},
|
|
"layer": {ID: "layer", OwnerID: "owner", Kind: assets.KindImage},
|
|
}
|
|
service := NewService(repository, catalog)
|
|
|
|
saved, err := service.Save(context.Background(), "owner", "job-1", 0, Composition{
|
|
BaseAssetID: "base", BaseVisible: true,
|
|
Layers: []Layer{{ID: "layer-1", AssetID: "layer", Name: "主体", Visible: true, Box: Box{100, 100, 900, 900}, Rotation: 450, Source: "upload"}},
|
|
})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if saved.Version != 1 || saved.OwnerID != "owner" || saved.JobID != "job-1" || saved.Layers[0].Rotation != 90 {
|
|
t.Fatalf("saved=%#v", saved)
|
|
}
|
|
}
|
|
|
|
func TestServiceRejectsForeignOrMalformedLayerAssets(t *testing.T) {
|
|
service := NewService(&compositionRepositoryStub{}, assetCatalogStub{
|
|
"base": {ID: "base", OwnerID: "owner", Kind: assets.KindImage},
|
|
"foreign": {ID: "foreign", OwnerID: "another-owner", Kind: assets.KindImage},
|
|
})
|
|
_, err := service.Save(context.Background(), "owner", "job-1", 0, Composition{
|
|
BaseAssetID: "base", BaseVisible: true,
|
|
Layers: []Layer{{ID: "layer-1", AssetID: "foreign", Name: "主体", Visible: true, Box: Box{100, 100, 900, 900}, Source: "library"}},
|
|
})
|
|
if !errors.Is(err, ErrAssetNotFound) {
|
|
t.Fatalf("foreign asset err=%v", err)
|
|
}
|
|
|
|
_, err = service.Save(context.Background(), "owner", "job-1", 0, Composition{
|
|
BaseAssetID: "base", BaseVisible: true,
|
|
Layers: []Layer{{ID: "layer-1", AssetID: "base", Name: "主体", Visible: true, Box: Box{900, 100, 100, 900}, Source: "provider"}},
|
|
})
|
|
if !errors.Is(err, ErrInvalid) {
|
|
t.Fatalf("invalid box err=%v", err)
|
|
}
|
|
}
|
|
|
|
func TestServiceUsesOptimisticVersion(t *testing.T) {
|
|
repository := &compositionRepositoryStub{found: true, value: Composition{JobID: "job-1", OwnerID: "owner", Version: 3}}
|
|
service := NewService(repository, assetCatalogStub{"base": {ID: "base", OwnerID: "owner", Kind: assets.KindImage}})
|
|
_, err := service.Save(context.Background(), "owner", "job-1", 2, Composition{BaseAssetID: "base", BaseVisible: true})
|
|
if !errors.Is(err, ErrConflict) {
|
|
t.Fatalf("err=%v", err)
|
|
}
|
|
}
|