Publish current app and server

This commit is contained in:
ponzischeme89
2026-08-02 22:10:19 +12:00
parent a265636139
commit 1ed180c739
203 changed files with 23933 additions and 2788 deletions
+168 -9
View File
@@ -6,10 +6,13 @@ import (
"log/slog"
"net/http"
"net/http/httptest"
"slices"
"strings"
"testing"
"time"
"github.com/ponzischeme89/memby/server/internal/config"
"github.com/ponzischeme89/memby/server/internal/recommend"
"github.com/ponzischeme89/memby/server/internal/store"
)
@@ -81,7 +84,9 @@ func TestMaintenanceGateFallsBackToADefaultMessage(t *testing.T) {
func TestHealthAndAdminStayReachableDuringMaintenance(t *testing.T) {
// Health checks and the admin page sit outside the gate on purpose: they are what
// you need most while the app is deliberately down.
server := testServer(config.Config{AdminToken: "secret"})
server := testServer(config.Config{
AdminToken: "secret", ReleasePublishToken: "release-secret",
})
server.maintenance.set(store.Maintenance{Enabled: true})
rec := httptest.NewRecorder()
@@ -92,8 +97,9 @@ func TestHealthAndAdminStayReachableDuringMaintenance(t *testing.T) {
rec = httptest.NewRecorder()
server.adminRoutes().ServeHTTP(rec, httptest.NewRequest(http.MethodGet, "/admin/", nil))
if rec.Code != http.StatusOK {
t.Fatalf("admin page should stay reachable, got %d", rec.Code)
if rec.Code != http.StatusFound || rec.Header().Get("Location") != "/admin/features" {
t.Fatalf("admin root should stay reachable via library redirect, got %d %q",
rec.Code, rec.Header().Get("Location"))
}
}
@@ -166,6 +172,17 @@ func TestAdminIsDisabledWithoutAToken(t *testing.T) {
}
}
func TestPlaybackPolicyRejectsUnsafeDuration(t *testing.T) {
server := testServer(config.Config{})
req := httptest.NewRequest(http.MethodPost, "/admin/api/playback-policy",
strings.NewReader(`{"prerollEnabled":true,"prerollDurationMs":500}`))
rec := httptest.NewRecorder()
server.handleAdminPlaybackPolicy(rec, req)
if rec.Code != http.StatusBadRequest {
t.Fatalf("status = %d, want 400", rec.Code)
}
}
func TestAdminAuthRejectsAWrongToken(t *testing.T) {
server := testServer(config.Config{AdminToken: "secret"})
handler := server.adminAuth(func(w http.ResponseWriter, _ *http.Request) {
@@ -198,12 +215,45 @@ func TestAdminAuthRejectsAWrongToken(t *testing.T) {
}
}
func TestAdminPageEstablishesPersistentCookie(t *testing.T) {
func TestAdminRuntimeMetricsAreProtectedAndReportHeap(t *testing.T) {
server := testServer(config.Config{AdminToken: "secret"})
req := httptest.NewRequest(http.MethodGet, "https://memby.local/admin/", nil)
unauthorized := httptest.NewRecorder()
server.adminRoutes().ServeHTTP(
unauthorized,
httptest.NewRequest(http.MethodGet, "/admin/api/runtime", nil),
)
if unauthorized.Code != http.StatusUnauthorized {
t.Fatalf("unauthorized runtime status = %d", unauthorized.Code)
}
req := httptest.NewRequest(http.MethodGet, "/admin/api/runtime", nil)
req.Header.Set("Authorization", "Bearer secret")
rec := httptest.NewRecorder()
server.adminRoutes().ServeHTTP(rec, req)
if rec.Code != http.StatusOK {
t.Fatalf("runtime status = %d: %s", rec.Code, rec.Body.String())
}
var body adminRuntimeStatus
if err := json.Unmarshal(rec.Body.Bytes(), &body); err != nil {
t.Fatal(err)
}
if body.Goroutines < 1 || body.HeapInuse == 0 || body.MemoryLimit <= 0 {
t.Fatalf("runtime metrics = %+v", body)
}
if rec.Header().Get("Cache-Control") != "no-store" {
t.Fatalf("cache control = %q", rec.Header().Get("Cache-Control"))
}
}
func TestAdminPageEstablishesPersistentCookie(t *testing.T) {
server := testServer(config.Config{
AdminToken: "secret", ReleasePublishToken: "release-secret",
})
req := httptest.NewRequest(http.MethodGet, "https://memby.local/admin/library", nil)
addInstallerSession(t, server, req)
rec := httptest.NewRecorder()
server.handleAdminPage(rec, req)
server.adminRoutes().ServeHTTP(rec, req)
result := rec.Result()
cookies := result.Cookies()
@@ -223,7 +273,116 @@ func TestAdminPageEstablishesPersistentCookie(t *testing.T) {
}
func TestAdminAuthAcceptsPersistentCookie(t *testing.T) {
server := testServer(config.Config{AdminToken: "secret"})
server := testServer(config.Config{
AdminToken: "secret", ReleasePublishToken: "release-secret",
})
handler := server.adminAuth(func(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(http.StatusOK)
})
req := httptest.NewRequest(http.MethodGet, "/admin/api/status", nil)
req.AddCookie(&http.Cookie{Name: adminCookieName, Value: "secret"})
addInstallerSession(t, server, req)
rec := httptest.NewRecorder()
handler.ServeHTTP(rec, req)
if rec.Code != http.StatusOK {
t.Fatalf("the admin cookie should be accepted, got %d", rec.Code)
}
}
func TestAdminPageRequiresDiscreetEmbyGate(t *testing.T) {
server := testServer(config.Config{
AdminToken: "secret", ReleasePublishToken: "release-secret",
})
req := httptest.NewRequest(http.MethodGet, "/admin/logs", nil)
rec := httptest.NewRecorder()
server.adminRoutes().ServeHTTP(rec, req)
if rec.Code != http.StatusOK {
t.Fatalf("admin gate status = %d", rec.Code)
}
body := strings.ToLower(rec.Body.String())
for _, forbidden := range []string{"memby", "emby", "installer", "administration", "analytics"} {
if strings.Contains(body, forbidden) {
t.Fatalf("admin gate disclosed %q before login", forbidden)
}
}
if !strings.Contains(body, "login required to continue.") ||
!strings.Contains(body, `name="next" type="hidden" value="/admin/logs"`) {
t.Fatalf("admin gate has wrong copy or return destination: %s", rec.Body.String())
}
if len(rec.Result().Cookies()) != 0 {
t.Fatal("admin gate issued an admin cookie before Emby authentication")
}
}
func TestAdminPagesUseRealRoutes(t *testing.T) {
server := testServer(config.Config{
AdminToken: "secret", ReleasePublishToken: "release-secret",
})
for _, page := range []string{
"library", "recommendations", "requests", "maintenance",
"updates", "engagement", "imports", "logs",
} {
req := httptest.NewRequest(http.MethodGet, "/admin/"+page, nil)
addInstallerSession(t, server, req)
rec := httptest.NewRecorder()
server.adminRoutes().ServeHTTP(rec, req)
if rec.Code != http.StatusOK {
t.Fatalf("/admin/%s = %d", page, rec.Code)
}
body := rec.Body.String()
if !strings.Contains(body, `href="/admin/logs"`) ||
!strings.Contains(body, `data-admin-page="`+page+`"`) {
t.Fatalf("/admin/%s does not contain routed navigation/page marker", page)
}
}
req := httptest.NewRequest(http.MethodGet, "/admin/not-a-page", nil)
addInstallerSession(t, server, req)
rec := httptest.NewRecorder()
server.adminRoutes().ServeHTTP(rec, req)
if rec.Code != http.StatusNotFound {
t.Fatalf("unknown admin page = %d", rec.Code)
}
}
func TestInstallerDestinationAllowsOnlyKnownAdminPages(t *testing.T) {
if got := cleanInstallerDestination("/admin/recommendations"); got != "/admin/recommendations" {
t.Fatalf("recommendation destination = %q", got)
}
for _, unsafe := range []string{
"/admin/not-real", "/admin/../updates/latest.apk", "/admin/logs?next=https://evil.test",
} {
if got := cleanInstallerDestination(unsafe); got != "/install" {
t.Fatalf("unsafe destination %q accepted as %q", unsafe, got)
}
}
}
func TestAdminEligibleRowsExplainPlacement(t *testing.T) {
item := store.PreparedForYouItem{
RuntimeMinutes: 28, CompatibilityScore: 0.8,
ReasonKind: "completed-title", ReasonGenre: "Drama",
ReasonSourceTitle: "Arrival",
}
rows := adminEligibleRows(item, recommend.Item{Type: "Series"})
for _, wanted := range []string{
"Top picks for you", "Because you finished Arrival", "More Drama for you",
"Plays well on this TV", "One episode before bed", "Hidden in your library",
} {
if !slices.Contains(rows, wanted) {
t.Fatalf("eligible rows %v missing %q", rows, wanted)
}
}
}
func TestAdminCookieCannotOutliveEmbyGate(t *testing.T) {
server := testServer(config.Config{
AdminToken: "secret", ReleasePublishToken: "release-secret",
})
handler := server.adminAuth(func(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(http.StatusOK)
})
@@ -233,8 +392,8 @@ func TestAdminAuthAcceptsPersistentCookie(t *testing.T) {
handler.ServeHTTP(rec, req)
if rec.Code != http.StatusOK {
t.Fatalf("the admin cookie should be accepted, got %d", rec.Code)
if rec.Code != http.StatusUnauthorized {
t.Fatalf("admin cookie without Emby gate got %d, want 401", rec.Code)
}
}