Files
summercms/modules/lagoon/attach/url_test.go
Jakub Zych e06e0cc8bf feat(12-01): record multipart uploads and match Winter upload URLs
- attach.PublicURL and (*File).URL build Winter File::getPath() URLs; the
  thumbnailer decodes webp via golang.org/x/image v0.46.0 and checks the
  image size from the header before decoding
- tide requests carry multipart parts (files beside the fixture pinned by
  sha256) encoded with the fixed MultipartBoundary, so PHP and Go receive
  byte-identical bodies
- tide masks the random partition, disk name and file id of url/thumb_url
  upload URLs while still diffing prefix, size, mode and extension, and
  NormalizePublications masks Carbon dates in the published album
2026-10-02 11:33:42 +02:00

108 lines
3.6 KiB
Go

package attach
import (
"bytes"
"image"
"image/jpeg"
"os"
"path/filepath"
"testing"
"git.golem15.com/golem15/summercms/modules/compass"
"gocloud.dev/blob"
)
// winterLayoutBucket opens a mem:// bucket with the WinterCMS public prefix
// and restores the framework default afterwards.
func winterLayoutBucket(t *testing.T) *blob.Bucket {
t.Helper()
dir := t.TempDir()
body := "uploads:\n bucket_url: \"mem://\"\n public_path_prefix: \"/storage/app/uploads/public\"\n"
if err := os.WriteFile(filepath.Join(dir, "storage.yaml"), []byte(body), 0o644); err != nil {
t.Fatal(err)
}
cfg, err := compass.Open(compass.Options{Dir: dir, Env: "development", Environ: []string{"SUMMER_ENV=development"}})
if err != nil {
t.Fatal(err)
}
bucket, err := OpenBucket(t.Context(), cfg)
if err != nil {
t.Fatal(err)
}
t.Cleanup(func() {
_ = bucket.Close()
setPublicPathPrefix(defaultPublicPathPrefix)
})
return bucket
}
func TestFileURLWinterLayout(t *testing.T) {
bucket := winterLayoutBucket(t)
// A WinterCMS disk name: uniqid('', true) without the dot, plus the
// extension.
f := &File{ID: 12, DiskName: "651a2b3c4d5e61234567.png"}
if got, want := f.URL(), "/storage/app/uploads/public/651/a2b/3c4/651a2b3c4d5e61234567.png"; got != want {
t.Fatalf("URL = %q, want %q", got, want)
}
if got, want := PublicURL("/651/a2b/3c4/x.png"), "/storage/app/uploads/public/651/a2b/3c4/x.png"; got != want {
t.Fatalf("PublicURL = %q, want %q", got, want)
}
if err := bucket.WriteAll(t.Context(), BlobKey(f.DiskName), testJPEG(t), &blob.WriterOptions{ContentType: "image/png"}); err != nil {
t.Fatal(err)
}
thumb, err := f.Thumb(t.Context(), bucket, 200, 200, "crop")
if err != nil {
t.Fatal(err)
}
// Winter getThumbFilename: implode('_', [thumb, id, w, h, ox, oy, mode.ext]).
if want := "/storage/app/uploads/public/651/a2b/3c4/thumb_12_200_200_0_0_crop.png"; thumb != want {
t.Fatalf("thumb = %q, want %q", thumb, want)
}
var nilFile *File
if nilFile.URL() != "" {
t.Fatal("nil file URL must be empty")
}
}
// webpFixture is a 16x12 lossless WebP: blue left half, red right half.
var webpFixture = []byte{
0x52, 0x49, 0x46, 0x46, 0x2a, 0x00, 0x00, 0x00, 0x57, 0x45, 0x42, 0x50, 0x56, 0x50, 0x38, 0x4c,
0x1d, 0x00, 0x00, 0x00, 0x2f, 0x0f, 0xc0, 0x02, 0x00, 0x0f, 0x70, 0x14, 0xfb, 0x53, 0xd0, 0x5e,
0x88, 0x7b, 0xfe, 0x83, 0x07, 0x62, 0xc1, 0x64, 0xfe, 0xd2, 0xbd, 0x21, 0x44, 0xf4, 0x3f, 0x74,
0x01, 0x00,
}
func TestThumbWebP(t *testing.T) {
cfg, format, err := image.DecodeConfig(bytes.NewReader(webpFixture))
if err != nil {
t.Fatalf("DecodeConfig: %v", err)
}
if format != "webp" || cfg.Width != 16 || cfg.Height != 12 {
t.Fatalf("config = %s %dx%d", format, cfg.Width, cfg.Height)
}
bucket := winterLayoutBucket(t)
f := &File{ID: 5, DiskName: "abcdef123456789012345.webp"}
if err := bucket.WriteAll(t.Context(), BlobKey(f.DiskName), webpFixture, &blob.WriterOptions{ContentType: "image/webp"}); err != nil {
t.Fatal(err)
}
url, err := f.Thumb(t.Context(), bucket, 200, 200, "crop")
if err != nil {
t.Fatalf("Thumb: %v", err)
}
if want := "/storage/app/uploads/public/abc/def/123/thumb_5_200_200_0_0_crop.webp"; url != want {
t.Fatalf("thumb url = %q, want %q", url, want)
}
raw, err := bucket.ReadAll(t.Context(), "abc/def/123/thumb_5_200_200_0_0_crop.webp")
if err != nil {
t.Fatal(err)
}
// imaging cannot encode webp: the thumb is JPEG bytes under the .webp name.
img, err := jpeg.Decode(bytes.NewReader(raw))
if err != nil {
t.Fatalf("thumb is not JPEG: %v", err)
}
if b := img.Bounds(); b.Dx() != 200 || b.Dy() != 200 {
t.Fatalf("thumb size = %v", b)
}
}