117 lines
3.9 KiB
Go
117 lines
3.9 KiB
Go
package test
|
|
|
|
import (
|
|
domain "RenewCMS/internal/domain/image"
|
|
"RenewCMS/internal/infrastructure/useCases"
|
|
"errors"
|
|
"io"
|
|
"testing"
|
|
)
|
|
|
|
type understatedSizeVariantStorage struct {
|
|
*mockVariantStorage
|
|
}
|
|
|
|
func (s understatedSizeVariantStorage) Open(storedName string) (domain.Blob, error) {
|
|
blob, err := s.mockVariantStorage.Open(storedName)
|
|
blob.Size = 1
|
|
return blob, err
|
|
}
|
|
|
|
type sizingVariantRenderer struct {
|
|
received int
|
|
calls int
|
|
}
|
|
|
|
func (r *sizingVariantRenderer) Render(source io.Reader, settings domain.VariantSettings) (domain.RenderedVariant, error) {
|
|
data, err := io.ReadAll(source)
|
|
r.received = len(data)
|
|
r.calls++
|
|
return domain.RenderedVariant{Content: []byte("rendered"), ContentType: "image/png"}, err
|
|
}
|
|
|
|
func (r *sizingVariantRenderer) DeclaredSize(source io.Reader) (int, int, error) {
|
|
return 1, 1, nil
|
|
}
|
|
|
|
func (r *sizingVariantRenderer) EncodableFormats() []domain.VariantFormat {
|
|
return []domain.VariantFormat{domain.FormatOriginal, domain.FormatJPEG, domain.FormatPNG}
|
|
}
|
|
|
|
type lateStaleVariantFileRepo struct {
|
|
*mockVariantFileRepo
|
|
finds int
|
|
stale domain.VariantFile
|
|
}
|
|
|
|
func (r *lateStaleVariantFileRepo) Find(variantName string, sourceName string) (domain.VariantFile, bool, error) {
|
|
r.finds++
|
|
if r.finds == 1 {
|
|
return domain.VariantFile{}, false, nil
|
|
}
|
|
return r.stale, true, nil
|
|
}
|
|
|
|
func TestImageVariantsServeInternals(t *testing.T) {
|
|
const cap = 1000
|
|
|
|
serve := func(storage domain.Storage, files domain.VariantFileRepository, renderer domain.VariantRenderer, variants *mockVariantRepo) (useCases.ServedVariant, error) {
|
|
name := "thumb"
|
|
images := newMockImageRepo()
|
|
images.images[1] = domain.Image{ID: 1, Path: domain.PublicPath("a.png")}
|
|
return useCases.NewServeVariantUseCase(variants, files, images, storage, renderer, defaultServeLimits(cap)).Serve(useCases.ServeVariantRequest{StoredName: "a.png", Variant: &name})
|
|
}
|
|
|
|
t.Run("A streamed source of exactly the cap is rendered whole", func(t *testing.T) {
|
|
variants := newMockVariantRepo()
|
|
seedVariant(variants, "thumb", 400, 300, domain.FitCover, domain.FormatJPEG, 80)
|
|
storage := newMockVariantStorage()
|
|
storage.seed("a.png", make([]byte, cap))
|
|
renderer := &sizingVariantRenderer{}
|
|
|
|
_, err := serve(understatedSizeVariantStorage{storage}, newMockVariantFileRepo(), renderer, variants)
|
|
|
|
if err != nil || renderer.calls != 1 || renderer.received != cap {
|
|
t.Errorf("err = %v, calls = %d, received = %d", err, renderer.calls, renderer.received)
|
|
}
|
|
})
|
|
|
|
t.Run("A streamed source beyond the cap is rejected even when its reported size is small", func(t *testing.T) {
|
|
variants := newMockVariantRepo()
|
|
seedVariant(variants, "thumb", 400, 300, domain.FitCover, domain.FormatJPEG, 80)
|
|
storage := newMockVariantStorage()
|
|
storage.seed("a.png", make([]byte, cap+1))
|
|
renderer := &sizingVariantRenderer{}
|
|
|
|
_, err := serve(understatedSizeVariantStorage{storage}, newMockVariantFileRepo(), renderer, variants)
|
|
|
|
if !errors.Is(err, domain.ErrSourceTooLarge) || renderer.calls != 0 {
|
|
t.Errorf("err = %v, calls = %d", err, renderer.calls)
|
|
}
|
|
})
|
|
|
|
t.Run("A stale row that appears during generation is regenerated, not served", func(t *testing.T) {
|
|
variants := newMockVariantRepo()
|
|
seedVariant(variants, "thumb", 400, 300, domain.FitCover, domain.FormatJPEG, 80)
|
|
storage := newMockVariantStorage()
|
|
storage.seed("a.png", []byte("source"))
|
|
storage.seed("old.png", []byte("old"))
|
|
files := &lateStaleVariantFileRepo{
|
|
mockVariantFileRepo: newMockVariantFileRepo(),
|
|
stale: domain.VariantFile{VariantName: "thumb", SourceName: "a.png", CachedName: "old.png", ContentType: "image/png", Size: 3, Fingerprint: "stale"},
|
|
}
|
|
renderer := &sizingVariantRenderer{}
|
|
|
|
served, err := serve(storage, files, renderer, variants)
|
|
|
|
if err != nil || renderer.calls != 1 {
|
|
t.Fatalf("err = %v, calls = %d", err, renderer.calls)
|
|
}
|
|
defer served.Content.Close()
|
|
body, _ := io.ReadAll(served.Content)
|
|
if string(body) != "rendered" {
|
|
t.Errorf("body = %q", body)
|
|
}
|
|
})
|
|
}
|