check / check (push) Canceled after 0s
The new package internal/providers builds the cache, the fetcher, the processor, the image service, the session manager and the encrypted URL generator from the config. pixad's fx graph provides them with providers.Constructors(), and handlers.New receives them built. The server tests build the same graph, with only the fetcher's dial function replaced. database.New opens the database, so these parts can read it while fx builds them; the cache's stop hook still runs before the database's. Each setting's default is declared in internal/config, and internal/providers works out the default cache_max_bytes. The cache's MaxBytes is the one value for the disk cache limit, and 0 turns the disk cache off. The fetcher and the processor take explicit values. Model: opus-5-5
126 lines
3.7 KiB
Go
126 lines
3.7 KiB
Go
package imageprocessor
|
|
|
|
import (
|
|
"bytes"
|
|
"errors"
|
|
"testing"
|
|
|
|
"sneak.berlin/go/pixa/internal/imagerequest"
|
|
)
|
|
|
|
// TestImageProcessor_RefusesFitOutsideAboveMaximum verifies that FitOutside,
|
|
// which scales the input to cover the requested size and so past it on one
|
|
// side, is refused with ErrOutputTooLarge when that side would come out above
|
|
// MaxOutputDimension, and otherwise makes the scaled size. A 1024x256 or
|
|
// 256x1024 input scaled by 8 has 8192 for its long side.
|
|
func TestImageProcessor_RefusesFitOutsideAboveMaximum(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tests := []struct {
|
|
name string
|
|
inputWidth, inputHeight int
|
|
size imagerequest.Size
|
|
// wantWidth and wantHeight are the output's, 0 for a refusal
|
|
wantWidth, wantHeight int
|
|
}{
|
|
{"width above the maximum", 3000, 600,
|
|
imagerequest.Size{Width: 1, Height: 8192}, 0, 0},
|
|
{"height above the maximum", 600, 3000,
|
|
imagerequest.Size{Width: 8192, Height: 1}, 0, 0},
|
|
{"width at the maximum", 1024, 256,
|
|
imagerequest.Size{Width: 1, Height: 2048}, 8192, 2048},
|
|
{"height at the maximum", 256, 1024,
|
|
imagerequest.Size{Width: 2048, Height: 1}, 2048, 8192},
|
|
{"within the maximum", 3000, 600,
|
|
imagerequest.Size{Width: 1, Height: 1200}, 6000, 1200},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
input := createTestJPEG(t, tt.inputWidth, tt.inputHeight)
|
|
|
|
result, err := New(Params{
|
|
MaxInputBytes: 50 << 20,
|
|
MaxConcurrentProcessing: 1,
|
|
}).Process(t.Context(),
|
|
bytes.NewReader(input),
|
|
&imagerequest.Transform{
|
|
Size: tt.size,
|
|
Format: imagerequest.FormatJPEG,
|
|
FitMode: imagerequest.FitOutside,
|
|
})
|
|
if result != nil {
|
|
t.Logf("Process() made %dx%d", result.Width, result.Height)
|
|
}
|
|
|
|
if tt.wantWidth == 0 {
|
|
if !errors.Is(err, ErrOutputTooLarge) {
|
|
t.Errorf("Process() error = %v, want %v", err, ErrOutputTooLarge)
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
if err != nil {
|
|
t.Fatalf("Process() error = %v", err)
|
|
}
|
|
|
|
if result.Width != tt.wantWidth || result.Height != tt.wantHeight {
|
|
t.Errorf("Process() made %dx%d, want %dx%d",
|
|
result.Width, result.Height, tt.wantWidth, tt.wantHeight)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// TestImageProcessor_FitOutsideSideIsAtLeastOne verifies that FitOutside
|
|
// keeps each side at 1 or more when it works both sides out again from the
|
|
// larger scale. A side of 49 scaled to 1 is 49 times 1/49, which in floating
|
|
// point is just under 1 and so rounded down to 0, a width libvips refuses.
|
|
func TestImageProcessor_FitOutsideSideIsAtLeastOne(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tests := []struct {
|
|
name string
|
|
inputWidth, inputHeight int
|
|
size imagerequest.Size
|
|
wantWidth, wantHeight int
|
|
}{
|
|
{"49x8192 at 0x100", 49, 8192, imagerequest.Size{Height: 100}, 1, 167},
|
|
{"49x49 at 1x1", 49, 49, imagerequest.Size{Width: 1, Height: 1}, 1, 1},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
input := createTestJPEG(t, tt.inputWidth, tt.inputHeight)
|
|
|
|
result, err := New(Params{
|
|
MaxInputBytes: 50 << 20,
|
|
MaxConcurrentProcessing: 1,
|
|
}).Process(t.Context(),
|
|
bytes.NewReader(input),
|
|
&imagerequest.Transform{
|
|
Size: tt.size,
|
|
Format: imagerequest.FormatJPEG,
|
|
FitMode: imagerequest.FitOutside,
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("Process() error = %v", err)
|
|
}
|
|
|
|
defer func() { _ = result.Content.Close() }()
|
|
|
|
t.Logf("Process() made %dx%d", result.Width, result.Height)
|
|
|
|
if result.Width != tt.wantWidth || result.Height != tt.wantHeight {
|
|
t.Errorf("Process() made %dx%d, want %dx%d",
|
|
result.Width, result.Height, tt.wantWidth, tt.wantHeight)
|
|
}
|
|
})
|
|
}
|
|
}
|