package server import ( "net/http" "net/http/httptest" "testing" "github.com/gin-gonic/gin" "github.com/google/uuid" "scrabble/backend/internal/session" ) // TestRequireUserID checks that the middleware accepts a valid X-User-ID, // exposes it through the request context, and rejects missing or malformed // headers with 401. func TestRequireUserID(t *testing.T) { gin.SetMode(gin.TestMode) var seen uuid.UUID var ok bool r := gin.New() r.Use(RequireUserID()) r.GET("/x", func(c *gin.Context) { seen, ok = UserIDFromContext(c.Request.Context()) c.String(http.StatusOK, "ok") }) t.Run("valid", func(t *testing.T) { seen, ok = uuid.Nil, false id := uuid.New() req := httptest.NewRequest(http.MethodGet, "/x", nil) req.Header.Set("X-User-ID", id.String()) rec := httptest.NewRecorder() r.ServeHTTP(rec, req) if rec.Code != http.StatusOK { t.Fatalf("status = %d, want 200", rec.Code) } if !ok || seen != id { t.Fatalf("context id = %s (ok=%v), want %s", seen, ok, id) } }) t.Run("missing", func(t *testing.T) { rec := httptest.NewRecorder() r.ServeHTTP(rec, httptest.NewRequest(http.MethodGet, "/x", nil)) if rec.Code != http.StatusUnauthorized { t.Fatalf("status = %d, want 401", rec.Code) } }) t.Run("malformed", func(t *testing.T) { req := httptest.NewRequest(http.MethodGet, "/x", nil) req.Header.Set("X-User-ID", "not-a-uuid") rec := httptest.NewRecorder() r.ServeHTTP(rec, req) if rec.Code != http.StatusUnauthorized { t.Fatalf("status = %d, want 401", rec.Code) } }) } // TestPlatformContext checks that the middleware parses the gateway-injected // X-Platform header into a trusted platform reachable via platform(c), treats an // absent or blank-kind header as untrusted, and never rejects the request. func TestPlatformContext(t *testing.T) { gin.SetMode(gin.TestMode) var seen session.Platform var ok bool r := gin.New() r.Use(platformContext()) r.GET("/x", func(c *gin.Context) { seen, ok = platform(c) c.String(http.StatusOK, "ok") }) for _, tc := range []struct { name string header string setHeader bool wantOK bool want session.Platform }{ {"vk-ios", "vk/ios", true, true, session.Platform{Kind: session.PlatformKindVK, Subtype: session.SubtypeIOS}}, {"telegram-no-subtype", "telegram", true, true, session.Platform{Kind: session.PlatformKindTelegram}}, {"direct-web", "direct/web", true, true, session.Platform{Kind: session.PlatformKindDirect, Subtype: session.SubtypeWeb}}, {"absent", "", false, false, session.Platform{}}, {"empty", "", true, false, session.Platform{}}, {"blank-kind", "/ios", true, false, session.Platform{}}, } { t.Run(tc.name, func(t *testing.T) { seen, ok = session.Platform{}, false req := httptest.NewRequest(http.MethodGet, "/x", nil) if tc.setHeader { req.Header.Set("X-Platform", tc.header) } rec := httptest.NewRecorder() r.ServeHTTP(rec, req) if rec.Code != http.StatusOK { t.Fatalf("status = %d, want 200 (X-Platform never rejects)", rec.Code) } if ok != tc.wantOK || seen != tc.want { t.Fatalf("platform = %+v (ok=%v), want %+v (ok=%v)", seen, ok, tc.want, tc.wantOK) } }) } }