Large albums opened slowly and flickered; the default album cover was also lost in the media-objects refactor. Large-album loading: - quantize signed object URLs within a window and send Cache-Control so previews are reused instead of re-fetched - publish photo.updated (not photo.created) when variants are ready, so clients update in place without reordering the grid - worker concurrency + newest-first variant priority; raise default batch Album cover: - first uploaded photo becomes the cover when none is set - clear the cover when the cover photo is trashed or moved out - "set as album cover" in the photo context menu and actions panel OpenSpec changes: fix-large-album-load, fix-album-cover
64 lines
1.6 KiB
Go
64 lines
1.6 KiB
Go
package storage
|
|
|
|
import (
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"net/url"
|
|
"strconv"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func expiryOf(t *testing.T, raw string) int64 {
|
|
t.Helper()
|
|
u, err := url.Parse(raw)
|
|
if err != nil {
|
|
t.Fatalf("parse url: %v", err)
|
|
}
|
|
e, err := strconv.ParseInt(u.Query().Get("e"), 10, 64)
|
|
if err != nil {
|
|
t.Fatalf("parse expiry: %v", err)
|
|
}
|
|
return e
|
|
}
|
|
|
|
func TestSignerURLStableWithinWindow(t *testing.T) {
|
|
s, err := NewSigner("http://app.test", "secret", time.Hour, time.Hour)
|
|
if err != nil {
|
|
t.Fatalf("new signer: %v", err)
|
|
}
|
|
first := s.URL("objects/a/thumb.webp")
|
|
second := s.URL("objects/a/thumb.webp")
|
|
if first != second {
|
|
t.Fatalf("URL changed within window:\n %q\n %q", first, second)
|
|
}
|
|
}
|
|
|
|
func TestSignerURLChangesAcrossWindow(t *testing.T) {
|
|
s, err := NewSigner("http://app.test", "secret", time.Hour, 10*time.Minute)
|
|
if err != nil {
|
|
t.Fatalf("new signer: %v", err)
|
|
}
|
|
base := time.Now()
|
|
s.now = func() time.Time { return base }
|
|
first := expiryOf(t, s.URL("objects/a/thumb.webp"))
|
|
s.now = func() time.Time { return base.Add(s.window) }
|
|
second := expiryOf(t, s.URL("objects/a/thumb.webp"))
|
|
if first == second {
|
|
t.Fatalf("expiry did not advance across window: %d", first)
|
|
}
|
|
}
|
|
|
|
func TestSignerURLVerifies(t *testing.T) {
|
|
s, err := NewSigner("http://app.test", "secret", time.Hour, 10*time.Minute)
|
|
if err != nil {
|
|
t.Fatalf("new signer: %v", err)
|
|
}
|
|
key := "objects/a/thumb.webp"
|
|
raw := s.URL(key)
|
|
req := httptest.NewRequest(http.MethodGet, raw, nil)
|
|
if err := s.VerifyRequest(key, req); err != nil {
|
|
t.Fatalf("verify issued URL: %v", err)
|
|
}
|
|
}
|