1 Commits
Author SHA1 Message Date
sneak fece3b69c9 One image request type instead of five (closes #307)
check / check (push) Canceled after 0s
The new package internal/imagerequest holds the request type, its two
parts Source and Transform, the Format and Fit types, the dimension and
fit checks, the /v1/image/ path parsing and the variant key; it imports
no other package of pixa. imgcache.ParsedURL, imgcache.ImageRequest,
signature.Request, imageprocessor.Request, the second Size, format and
fit types and the conversions between them are gone. The image
processor takes a Transform only. encurl keeps a private struct with the
token's CBOR field names, so tokens made before still decode. VariantKey
moves with the function that makes it. Tests follow the moved and
renamed code; the tests of the removed conversions go with them.

Model: opus-5-5
2026-10-21 12:27:29 +00:00
7 changed files with 63 additions and 63 deletions
@@ -86,7 +86,7 @@ func checkProcessStopsAtDeadline(
proc := New(Params{MaxConcurrentProcessing: 1})
result, err := proc.Process(ctx, input, smallJPEGRequest())
result, err := proc.Process(ctx, input, smallJPEGTransform())
if result != nil {
t.Logf("Process() made a %dx%d image after its deadline passed",
result.Width, result.Height)
@@ -14,11 +14,11 @@ import (
// processedSize runs input through Process and returns the output's size in
// bytes.
func processedSize(
t *testing.T, input []byte, req *imagerequest.Transform,
t *testing.T, input []byte, transform *imagerequest.Transform,
) int64 {
t.Helper()
result, err := New(Params{}).Process(t.Context(), bytes.NewReader(input), req)
result, err := New(Params{}).Process(t.Context(), bytes.NewReader(input), transform)
if err != nil {
t.Fatalf("Process() error = %v", err)
}
@@ -124,14 +124,14 @@ func TestImageProcessor_ResizeJPEG(t *testing.T) {
input := createTestJPEG(t, 800, 600)
req := &imagerequest.Transform{
transform := &imagerequest.Transform{
Size: imagerequest.Size{Width: 400, Height: 300},
Format: imagerequest.FormatJPEG,
Quality: 85,
FitMode: imagerequest.FitCover,
}
result, err := proc.Process(ctx, bytes.NewReader(input), req)
result, err := proc.Process(ctx, bytes.NewReader(input), transform)
if err != nil {
t.Fatalf("Process() error = %v", err)
}
@@ -170,13 +170,13 @@ func TestImageProcessor_ConvertToPNG(t *testing.T) {
input := createTestJPEG(t, 200, 150)
req := &imagerequest.Transform{
transform := &imagerequest.Transform{
Size: imagerequest.Size{Width: 200, Height: 150},
Format: imagerequest.FormatPNG,
FitMode: imagerequest.FitCover,
}
result, err := proc.Process(ctx, bytes.NewReader(input), req)
result, err := proc.Process(ctx, bytes.NewReader(input), transform)
if err != nil {
t.Fatalf("Process() error = %v", err)
}
@@ -206,14 +206,14 @@ func processAndCheckSize(
input := createTestJPEG(t, inputW, inputH)
req := &imagerequest.Transform{
transform := &imagerequest.Transform{
Size: size,
Format: imagerequest.FormatJPEG,
Quality: 85,
FitMode: imagerequest.FitCover,
}
result, err := proc.Process(ctx, bytes.NewReader(input), req)
result, err := proc.Process(ctx, bytes.NewReader(input), transform)
if err != nil {
t.Fatalf("Process() error = %v", err)
}
@@ -246,14 +246,14 @@ func TestImageProcessor_FitContain(t *testing.T) {
// Should result in 400x200 (maintaining aspect ratio)
input := createTestJPEG(t, 800, 400)
req := &imagerequest.Transform{
transform := &imagerequest.Transform{
Size: imagerequest.Size{Width: 400, Height: 400},
Format: imagerequest.FormatJPEG,
Quality: 85,
FitMode: imagerequest.FitContain,
}
result, err := proc.Process(ctx, bytes.NewReader(input), req)
result, err := proc.Process(ctx, bytes.NewReader(input), transform)
if err != nil {
t.Fatalf("Process() error = %v", err)
}
@@ -290,13 +290,13 @@ func TestImageProcessor_ProcessPNG(t *testing.T) {
input := createTestPNG(t, 400, 300)
req := &imagerequest.Transform{
transform := &imagerequest.Transform{
Size: imagerequest.Size{Width: 200, Height: 150},
Format: imagerequest.FormatPNG,
FitMode: imagerequest.FitCover,
}
result, err := proc.Process(ctx, bytes.NewReader(input), req)
result, err := proc.Process(ctx, bytes.NewReader(input), transform)
if err != nil {
t.Fatalf("Process() error = %v", err)
}
@@ -350,14 +350,14 @@ func TestImageProcessor_RejectsOversizedInput(t *testing.T) {
ctx := context.Background()
input := createTestJPEG(t, tt.width, tt.height)
req := &imagerequest.Transform{
transform := &imagerequest.Transform{
Size: imagerequest.Size{Width: 100, Height: 100},
Format: imagerequest.FormatJPEG,
Quality: 85,
FitMode: imagerequest.FitCover,
}
_, err := proc.Process(ctx, bytes.NewReader(input), req)
_, err := proc.Process(ctx, bytes.NewReader(input), transform)
if err == nil {
t.Error("Process() should reject oversized input images")
}
@@ -378,14 +378,14 @@ func TestImageProcessor_AcceptsMaxDimensionInput(t *testing.T) {
// Create an image at exactly MaxInputDimension - should be accepted
input := createTestJPEG(t, MaxInputDimension, 100)
req := &imagerequest.Transform{
transform := &imagerequest.Transform{
Size: imagerequest.Size{Width: 100, Height: 100},
Format: imagerequest.FormatJPEG,
Quality: 85,
FitMode: imagerequest.FitCover,
}
result, err := proc.Process(ctx, bytes.NewReader(input), req)
result, err := proc.Process(ctx, bytes.NewReader(input), transform)
if err != nil {
t.Fatalf(
"Process() should accept images at MaxInputDimension, got error: %v",
@@ -408,14 +408,14 @@ func encodeAndCheck(
input := createTestJPEG(t, 200, 150)
req := &imagerequest.Transform{
transform := &imagerequest.Transform{
Size: imagerequest.Size{Width: 100, Height: 75},
Format: format,
Quality: quality,
FitMode: imagerequest.FitCover,
}
result, err := proc.Process(ctx, bytes.NewReader(input), req)
result, err := proc.Process(ctx, bytes.NewReader(input), transform)
if err != nil {
t.Fatalf("Process() error = %v, want nil", err)
}
@@ -462,14 +462,14 @@ func TestImageProcessor_DecodeAVIF(t *testing.T) {
}
// Request resize and convert to JPEG
req := &imagerequest.Transform{
transform := &imagerequest.Transform{
Size: imagerequest.Size{Width: 2, Height: 2},
Format: imagerequest.FormatJPEG,
Quality: 85,
FitMode: imagerequest.FitCover,
}
result, err := proc.Process(ctx, bytes.NewReader(input), req)
result, err := proc.Process(ctx, bytes.NewReader(input), transform)
if err != nil {
t.Fatalf("Process() error = %v, want nil (AVIF decoding should work)", err)
}
@@ -503,14 +503,14 @@ func TestImageProcessor_RejectsOversizedInputData(t *testing.T) {
t.Fatalf("test JPEG must exceed %d bytes, got %d", limit, len(input))
}
req := &imagerequest.Transform{
transform := &imagerequest.Transform{
Size: imagerequest.Size{Width: 100, Height: 75},
Format: imagerequest.FormatJPEG,
Quality: 85,
FitMode: imagerequest.FitCover,
}
_, err := proc.Process(ctx, bytes.NewReader(input), req)
_, err := proc.Process(ctx, bytes.NewReader(input), transform)
if err == nil {
t.Fatal("Process() should reject input exceeding maxInputBytes")
}
@@ -530,14 +530,14 @@ func TestImageProcessor_AcceptsInputWithinLimit(t *testing.T) {
proc := New(Params{MaxInputBytes: limit})
ctx := context.Background()
req := &imagerequest.Transform{
transform := &imagerequest.Transform{
Size: imagerequest.Size{Width: 10, Height: 10},
Format: imagerequest.FormatJPEG,
Quality: 85,
FitMode: imagerequest.FitCover,
}
result, err := proc.Process(ctx, bytes.NewReader(input), req)
result, err := proc.Process(ctx, bytes.NewReader(input), transform)
if err != nil {
t.Fatalf("Process() error = %v, want nil", err)
}
@@ -570,12 +570,12 @@ func TestImageProcessor_EncodeAVIF(t *testing.T) {
// processAndDecode runs input through Process and decodes the output with
// vips, so a test can inspect the image a client would receive.
func processAndDecode(
t *testing.T, input []byte, req *imagerequest.Transform,
t *testing.T, input []byte, transform *imagerequest.Transform,
) *vips.ImageRef {
t.Helper()
result, err := New(Params{}).Process(
context.Background(), bytes.NewReader(input), req,
context.Background(), bytes.NewReader(input), transform,
)
if err != nil {
t.Fatalf("Process() error = %v", err)
@@ -16,13 +16,13 @@ import (
func TestImageProcessor_EncodeJPEGXL(t *testing.T) {
t.Parallel()
req := &imagerequest.Transform{
transform := &imagerequest.Transform{
Size: imagerequest.Size{Width: 100, Height: 75},
Format: imagerequest.FormatJXL,
}
result, err := New(Params{}).Process(
t.Context(), bytes.NewReader(createTestJPEG(t, 200, 150)), req,
t.Context(), bytes.NewReader(createTestJPEG(t, 200, 150)), transform,
)
if err != nil {
t.Fatalf("Process() error = %v", err)
@@ -78,8 +78,8 @@ func (r *gatedReader) Read(p []byte) (int, error) {
return n, err
}
// smallJPEGRequest asks for a 5x5 JPEG.
func smallJPEGRequest() *imagerequest.Transform {
// smallJPEGTransform asks for a 5x5 JPEG.
func smallJPEGTransform() *imagerequest.Transform {
return &imagerequest.Transform{
Size: imagerequest.Size{Width: 5, Height: 5},
Format: imagerequest.FormatJPEG,
@@ -94,7 +94,7 @@ func processInBackground(
proc *ImageProcessor, reader *gatedReader, results chan<- error,
) {
go func() {
result, err := proc.Process(context.Background(), reader, smallJPEGRequest())
result, err := proc.Process(context.Background(), reader, smallJPEGTransform())
if err == nil {
_ = result.Content.Close()
}
@@ -239,7 +239,7 @@ func TestProcessWaitsThenFailsWhenNoSlotFrees(t *testing.T) {
start := time.Now()
_, err := proc.Process(context.Background(), bytes.NewReader(input),
smallJPEGRequest())
smallJPEGTransform())
if !errors.Is(err, ErrTooManyImages) {
t.Fatalf("Process() error = %v, want ErrTooManyImages", err)
}
@@ -265,38 +265,38 @@ func TestProcessReleasesSlotOnError(t *testing.T) {
valid := createTestJPEG(t, 10, 10)
unsupported := smallJPEGRequest()
unsupported := smallJPEGTransform()
unsupported.Format = "bmp"
cases := []struct {
name string
input io.Reader
req *imagerequest.Transform
name string
input io.Reader
transform *imagerequest.Transform
// want is the error Process must return; nil means any error.
want error
}{
{
name: "input cannot be read",
input: iotest.ErrReader(errTestReadFailed),
req: smallJPEGRequest(),
want: errTestReadFailed,
name: "input cannot be read",
input: iotest.ErrReader(errTestReadFailed),
transform: smallJPEGTransform(),
want: errTestReadFailed,
},
{
name: "input over the byte limit",
input: bytes.NewReader(createTestJPEG(t, 800, 600)),
req: smallJPEGRequest(),
want: ErrInputDataTooLarge,
name: "input over the byte limit",
input: bytes.NewReader(createTestJPEG(t, 800, 600)),
transform: smallJPEGTransform(),
want: ErrInputDataTooLarge,
},
{
name: "input not an image",
input: strings.NewReader("not an image"),
req: smallJPEGRequest(),
name: "input not an image",
input: strings.NewReader("not an image"),
transform: smallJPEGTransform(),
},
{
name: "output format not supported",
input: bytes.NewReader(valid),
req: unsupported,
want: ErrUnsupportedOutputFormat,
name: "output format not supported",
input: bytes.NewReader(valid),
transform: unsupported,
want: ErrUnsupportedOutputFormat,
},
}
@@ -307,7 +307,7 @@ func TestProcessReleasesSlotOnError(t *testing.T) {
proc := New(Params{MaxInputBytes: 4096, MaxConcurrentProcessing: 1})
proc.processingWaitTimeout = 100 * time.Millisecond
_, err := proc.Process(context.Background(), tc.input, tc.req)
_, err := proc.Process(context.Background(), tc.input, tc.transform)
if err == nil || (tc.want != nil && !errors.Is(err, tc.want)) {
t.Fatalf("Process() error = %v, want %v", err, tc.want)
}
@@ -317,7 +317,7 @@ func TestProcessReleasesSlotOnError(t *testing.T) {
}
result, err := proc.Process(context.Background(), bytes.NewReader(valid),
smallJPEGRequest())
smallJPEGTransform())
if err != nil {
t.Fatalf("Process() after the error = %v, want nil", err)
}
@@ -2,7 +2,7 @@ package imagerequest
import "testing"
func TestImageRequest_SourceURL_DefaultHTTPS(t *testing.T) {
func TestRequest_SourceURL_DefaultHTTPS(t *testing.T) {
t.Parallel()
req := &Request{
@@ -21,7 +21,7 @@ func TestImageRequest_SourceURL_DefaultHTTPS(t *testing.T) {
}
}
func TestImageRequest_SourceURL_AllowHTTP(t *testing.T) {
func TestRequest_SourceURL_AllowHTTP(t *testing.T) {
t.Parallel()
req := &Request{
@@ -40,7 +40,7 @@ func TestImageRequest_SourceURL_AllowHTTP(t *testing.T) {
}
}
func TestImageRequest_SourceURL_AllowHTTPFalse(t *testing.T) {
func TestRequest_SourceURL_AllowHTTPFalse(t *testing.T) {
t.Parallel()
req := &Request{
@@ -12,9 +12,9 @@ const (
testPathCat = "/photos/cat.jpg"
)
// assertParsedURL compares all fields of a parsed URL against the
// expected value.
func assertParsedURL(t *testing.T, got, want *Request) {
// assertRequest compares the source host, path and query and the size and
// format of got against want.
func assertRequest(t *testing.T, got, want *Request) {
t.Helper()
if got.Source.Host != want.Source.Host {
@@ -116,7 +116,7 @@ func TestParseImageURL(t *testing.T) {
t.Fatalf("ParseImageURL() unexpected error = %v", err)
}
assertParsedURL(t, got, tt.want)
assertRequest(t, got, tt.want)
})
}
}
@@ -247,7 +247,7 @@ func TestParseImagePath(t *testing.T) {
return
}
assertParsedURL(t, got, tt.want)
assertRequest(t, got, tt.want)
})
}
}
@@ -432,7 +432,7 @@ func TestParseImageURL_SourceURLHoldingPercent25(t *testing.T) {
t.Fatalf("ParseImageURL() unexpected error = %v", err)
}
assertParsedURL(t, got, tt.want)
assertRequest(t, got, tt.want)
})
}
}