update
This commit is contained in:
86
internal/service/ingest_service_test.go
Normal file
86
internal/service/ingest_service_test.go
Normal file
@ -0,0 +1,86 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"fashionapi/internal/model"
|
||||
"fashionapi/internal/pkg/storage"
|
||||
"fashionapi/internal/repository"
|
||||
)
|
||||
|
||||
// fakeMediaRepo 计数固定返回 0:即所有 key 都是孤儿,应被真删(不误删的前提是调用方已软删引用)。
|
||||
type fakeMediaRepo struct{ repository.MediaRepository }
|
||||
|
||||
func (fakeMediaRepo) CountImageKeyRefs(ctx context.Context, key string) (int, error) { return 0, nil }
|
||||
|
||||
// fakeIngestRepo 仅实现 processMediaCleanup 需要的 MarkDone/MarkFailed(其余由内嵌 nil 接口兜底,不会被调用)。
|
||||
type fakeIngestRepo struct{ repository.IngestRepository }
|
||||
|
||||
func (fakeIngestRepo) MarkDone(ctx context.Context, id uint32) error { return nil }
|
||||
func (fakeIngestRepo) MarkFailed(ctx context.Context, id uint32, errMsg string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// countingDeleter 包装 LocalUploader,记录被删除的 key,便于断言。
|
||||
type countingDeleter struct {
|
||||
*storage.LocalUploader
|
||||
deleted []string
|
||||
}
|
||||
|
||||
func (c *countingDeleter) Delete(ctx context.Context, key string) error {
|
||||
c.deleted = append(c.deleted, key)
|
||||
return c.LocalUploader.Delete(ctx, key)
|
||||
}
|
||||
|
||||
// TestProcessMediaCleanup 验证「清理七牛孤儿图」任务:引用计数为 0 的 key 会被真删。
|
||||
func TestProcessMediaCleanup(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
up := storage.NewLocalUploader(dir, "/uploads")
|
||||
del := &countingDeleter{LocalUploader: up}
|
||||
|
||||
// 预置一个"孤儿"文件,确认它确实存在。
|
||||
if _, err := up.Upload(context.Background(), "runway/abc.jpg", []byte("x"), "image/jpeg"); err != nil {
|
||||
t.Fatalf("预置文件失败: %v", err)
|
||||
}
|
||||
|
||||
svc := NewIngestService(fakeIngestRepo{}, nil, fakeMediaRepo{}, up, del, up)
|
||||
job := model.IngestJob{Kind: model.IngestKindMediaCleanup, Payload: `{"keys":["runway/abc.jpg"]}`}
|
||||
svc.processMediaCleanup(context.Background(), job)
|
||||
|
||||
if len(del.deleted) != 1 || del.deleted[0] != "runway/abc.jpg" {
|
||||
t.Fatalf("期望删除 1 个孤儿 key,实际 %v", del.deleted)
|
||||
}
|
||||
}
|
||||
|
||||
// TestProcessMediaCleanupSkipsReferenced 引用计数 > 0 的 key 必须保留(不误删共享 key)。
|
||||
func TestProcessMediaCleanupSkipsReferenced(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
up := storage.NewLocalUploader(dir, "/uploads")
|
||||
del := &countingDeleter{LocalUploader: up}
|
||||
|
||||
// 引用计数恒为 1(仍被其他图集使用),不应真删。
|
||||
svc := NewIngestService(fakeIngestRepo{}, nil, referencedMediaRepo{}, up, del, up)
|
||||
job := model.IngestJob{Kind: model.IngestKindMediaCleanup, Payload: `{"keys":["runway/shared.jpg"]}`}
|
||||
svc.processMediaCleanup(context.Background(), job)
|
||||
|
||||
if len(del.deleted) != 0 {
|
||||
t.Fatalf("被引用的 key 不应被删除,实际 %v", del.deleted)
|
||||
}
|
||||
}
|
||||
|
||||
type referencedMediaRepo struct{ repository.MediaRepository }
|
||||
|
||||
func (referencedMediaRepo) CountImageKeyRefs(ctx context.Context, key string) (int, error) {
|
||||
return 1, nil
|
||||
}
|
||||
|
||||
// TestIngestRetryBackoff 验证指数退避:30s / 60s / 120s 且封顶 600s。
|
||||
func TestIngestRetryBackoff(t *testing.T) {
|
||||
cases := map[int]int{1: 30, 2: 60, 3: 120, 10: 600}
|
||||
for attempts, want := range cases {
|
||||
if got := model.IngestRetryBackoff(attempts); got != want {
|
||||
t.Fatalf("IngestRetryBackoff(%d)=%d, want %d", attempts, got, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user