90 lines
3.9 KiB
Go
90 lines
3.9 KiB
Go
package app
|
|
|
|
import (
|
|
"testing"
|
|
"time"
|
|
|
|
"yingce/backend/internal/model"
|
|
)
|
|
|
|
func TestPurgeAssetsBatchSharedResourcesAndHistory(t *testing.T) {
|
|
svc, db, _ := newResourceDeletionTestService(t)
|
|
for _, id := range []string{"batch-shared", "keep-shared", "same-object", "foreign-alias"} {
|
|
owner, objectKey := "user-1", id+".png"
|
|
if id == "foreign-alias" {
|
|
owner, objectKey = "user-2", "same-object.png"
|
|
}
|
|
if err := db.Create(&model.Resource{ID: id, UserID: owner, Provider: "unsupported-test-provider", ObjectKey: objectKey, Status: model.ResourceStatusReady}).Error; err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
for _, record := range []any{
|
|
&model.Asset{ID: "first", UserID: "user-1", Status: model.AssetVersionStatusConfirmed, PayloadJSON: `{"resourceIds":["batch-shared","keep-shared","same-object"]}`},
|
|
&model.Asset{ID: "second", UserID: "user-1", Status: model.AssetVersionStatusArchived, PayloadJSON: `{}`},
|
|
&model.AssetVersion{ID: "second-version", AssetID: "second", DefinitionJSON: `{"resourceId":"batch-shared"}`},
|
|
&model.AssetRepresentation{ID: "second-representation", AssetVersionID: "second-version", Role: "image", ResourceID: "batch-shared", MetadataJSON: `{}`},
|
|
&model.Asset{ID: "unselected", UserID: "user-1", PayloadJSON: `{}`},
|
|
&model.AssetVersion{ID: "unselected-version", AssetID: "unselected", DefinitionJSON: `{}`},
|
|
&model.AssetRepresentation{ID: "unselected-representation", AssetVersionID: "unselected-version", Role: "video", MetadataJSON: `{"resourceId":"keep-shared"}`},
|
|
&model.Task{ID: "batch-task", UserID: "user-1", Status: model.TaskStatusRunning, InputJSON: `{"resourceId":"batch-shared"}`},
|
|
&model.CanvasProject{ID: "batch-canvas", UserID: "user-1", PayloadJSON: `{"resourceId":"batch-shared"}`},
|
|
&model.CanvasSnapshot{ID: "batch-snapshot", CanvasID: "batch-canvas", UserID: "user-1", Revision: 1, PayloadJSON: `{}`, CreatedAt: time.Now()},
|
|
&model.CanvasSnapshotResource{SnapshotID: "batch-snapshot", ResourceID: "batch-shared"},
|
|
} {
|
|
if err := db.Create(record).Error; err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
assertCount := func(record any, want int64) {
|
|
t.Helper()
|
|
var count int64
|
|
if err := db.Model(record).Count(&count).Error; err != nil || count != want {
|
|
t.Fatalf("%T count=%d want=%d err=%v", record, count, want, err)
|
|
}
|
|
}
|
|
|
|
// 彻底删除不受任务、画布与画布历史引用拦截(产品约定);
|
|
// 但事务后段失败时,素材、版本、表现、历史索引与 Outbox 必须整批回滚。
|
|
if err := db.Exec("CREATE TRIGGER fail_batch_resource_delete BEFORE DELETE ON resources BEGIN SELECT RAISE(ABORT, 'forced failure'); END;").Error; err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := svc.PurgeUserAssets("user-1", []string{"first", "second"}); err == nil {
|
|
t.Fatal("expected rollback")
|
|
}
|
|
assertCount(&model.Asset{}, 3)
|
|
assertCount(&model.Resource{}, 4)
|
|
assertCount(&model.ResourceDeletionJob{}, 0)
|
|
assertCount(&model.CanvasSnapshotResource{}, 1)
|
|
assertCount(&model.AssetVersion{}, 2)
|
|
assertCount(&model.AssetRepresentation{}, 2)
|
|
if err := db.Exec("DROP TRIGGER fail_batch_resource_delete").Error; err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if err := svc.PurgeUserAssets("user-1", []string{"first", " second ", "first"}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
assertCount(&model.Asset{}, 1)
|
|
assertCount(&model.Resource{}, 2)
|
|
assertCount(&model.ResourceDeletionJob{}, 1)
|
|
assertCount(&model.CanvasSnapshotResource{}, 0)
|
|
assertCount(&model.CanvasSnapshot{}, 1)
|
|
assertCount(&model.Task{}, 1)
|
|
assertCount(&model.CanvasProject{}, 1)
|
|
assertCount(&model.AssetVersion{}, 1)
|
|
assertCount(&model.AssetRepresentation{}, 1)
|
|
var job model.ResourceDeletionJob
|
|
if err := db.First(&job).Error; err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if job.ResourceID != "batch-shared" {
|
|
t.Fatalf("wrong physical object queued: %s", job.ResourceID)
|
|
}
|
|
for _, id := range []string{"keep-shared", "foreign-alias"} {
|
|
var resource model.Resource
|
|
if err := db.First(&resource, "id = ?", id).Error; err != nil {
|
|
t.Fatalf("shared resource %s lost: %v", id, err)
|
|
}
|
|
}
|
|
}
|