CI / ci (push) Successful in 8m31s
Co-authored-by: orchestrator-agent <20+orchestrator-agent@code.cubecraftcreations.com>
139 lines
4.3 KiB
Go
139 lines
4.3 KiB
Go
package server
|
|
|
|
import (
|
|
"io"
|
|
"log/slog"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
"testing/fstest"
|
|
|
|
"code.cubecraftlabs.com/Maniacs_Mansion/Meal-Quest/internal/db"
|
|
"code.cubecraftlabs.com/Maniacs_Mansion/Meal-Quest/internal/recipes"
|
|
"code.cubecraftlabs.com/Maniacs_Mansion/Meal-Quest/internal/store"
|
|
)
|
|
|
|
// newMediaRouter returns a router over a photo cache whose data directory
|
|
// holds both sizes of two photos, the id of the one with a photos row, and
|
|
// the id of the orphan without one. Each size's file holds its size as
|
|
// text.
|
|
func newMediaRouter(t *testing.T) (r http.Handler, id, orphan string) {
|
|
t.Helper()
|
|
dataDir := t.TempDir()
|
|
st := newTestStore(t)
|
|
photos, err := recipes.NewPhotoCache(recipes.NewFetcher(), st, dataDir)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
id, orphan = store.NewID(), store.NewID()
|
|
for _, stem := range []string{id, orphan} {
|
|
for _, size := range []string{"400", "1200"} {
|
|
p := filepath.Join(dataDir, "media", "photos", stem+"-"+size+".jpg")
|
|
if err := os.WriteFile(p, []byte("jpeg "+size), 0o600); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
}
|
|
now := store.Now().String()
|
|
if _, err := db.New(st.Writer).CreatePhoto(t.Context(), db.CreatePhotoParams{
|
|
ID: id,
|
|
SourceUrl: "https://example.com/a.jpg",
|
|
LocalPath: "media/photos/" + id + "-1200.jpg",
|
|
Width: 1600,
|
|
Height: 1200,
|
|
Sha256: "sha",
|
|
FetchedAt: now,
|
|
CreatedAt: now,
|
|
UpdatedAt: now,
|
|
}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
logger := slog.New(slog.NewTextHandler(io.Discard, nil))
|
|
r, err = NewRouter(logger, "dev", nil, stubAuth{}, stubSessions{}, newTestSettings(t), newTestSearch(t), newTestAI(t), newTestChat(t), newTestDinners(t), newTestSuggest(t), newTestPlan(t), newTestShopping(t), newTestGoogle(t), newTestPush(t), newTestIdeas(t), newTestRunner(t),
|
|
photos, fstest.MapFS{"index.html": {Data: []byte(fixtureIndex)}})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
return r, id, orphan
|
|
}
|
|
|
|
func TestGetPhotoServesEachSize(t *testing.T) {
|
|
t.Parallel()
|
|
router, id, _ := newMediaRouter(t)
|
|
for _, size := range []string{"400", "1200"} {
|
|
req := httptest.NewRequest(http.MethodGet, "/media/photos/"+id+"-"+size+".jpg", nil)
|
|
req.AddCookie(validSessionCookie)
|
|
rec := httptest.NewRecorder()
|
|
router.ServeHTTP(rec, req)
|
|
|
|
if rec.Code != http.StatusOK {
|
|
t.Fatalf("size %s: status = %d, want 200", size, rec.Code)
|
|
}
|
|
if got := rec.Body.String(); got != "jpeg "+size {
|
|
t.Errorf("size %s: body = %q", size, got)
|
|
}
|
|
if got := rec.Header().Get("Content-Type"); got != "image/jpeg" {
|
|
t.Errorf("size %s: Content-Type = %q, want image/jpeg", size, got)
|
|
}
|
|
if got := rec.Header().Get("Cache-Control"); got != "private, max-age=31536000, immutable" {
|
|
t.Errorf("size %s: Cache-Control = %q", size, got)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestGetPhotoRequiresSession(t *testing.T) {
|
|
t.Parallel()
|
|
router, id, _ := newMediaRouter(t)
|
|
req := httptest.NewRequest(http.MethodGet, "/media/photos/"+id+"-400.jpg", nil)
|
|
rec := httptest.NewRecorder()
|
|
router.ServeHTTP(rec, req)
|
|
|
|
if rec.Code != http.StatusUnauthorized {
|
|
t.Fatalf("status = %d, want 401", rec.Code)
|
|
}
|
|
if got := rec.Body.String(); got != unauthenticatedJSON {
|
|
t.Errorf("body = %s, want %s", got, unauthenticatedJSON)
|
|
}
|
|
if got := rec.Header().Get("Cache-Control"); got != "" {
|
|
t.Errorf("Cache-Control = %q on a refused request", got)
|
|
}
|
|
}
|
|
|
|
func TestGetPhotoUnknownNotFound(t *testing.T) {
|
|
t.Parallel()
|
|
router, id, orphan := newMediaRouter(t)
|
|
for _, name := range []string{
|
|
store.NewID() + "-400.jpg", // no such photo
|
|
orphan + "-400.jpg", // file stored, no photos row
|
|
id + "-800.jpg", // size not stored
|
|
orphan + "-1200.jpg",
|
|
id + "-0400.jpg",
|
|
id + "-+400.jpg",
|
|
id + "-400.png",
|
|
id + ".jpg",
|
|
id + "-400",
|
|
"..%2F" + id + "-400.jpg",
|
|
"not-an-id-400.jpg",
|
|
} {
|
|
t.Run(name, func(t *testing.T) {
|
|
t.Parallel()
|
|
req := httptest.NewRequest(http.MethodGet, "/media/photos/"+name, nil)
|
|
req.AddCookie(validSessionCookie)
|
|
rec := httptest.NewRecorder()
|
|
router.ServeHTTP(rec, req)
|
|
|
|
if rec.Code != http.StatusNotFound {
|
|
t.Fatalf("status = %d, want 404", rec.Code)
|
|
}
|
|
if got := rec.Body.String(); got != notFoundJSON {
|
|
t.Errorf("body = %s, want %s", got, notFoundJSON)
|
|
}
|
|
if got := rec.Header().Get("Cache-Control"); got != "" {
|
|
t.Errorf("Cache-Control = %q on a 404", got)
|
|
}
|
|
})
|
|
}
|
|
}
|