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) } }) }