package apiv1import ("net/http""net/http/httptest""github.com/navidrome/navidrome/tests". "github.com/onsi/ginkgo/v2". "github.com/onsi/gomega")var _ = Describe("Router", func() {var router *RouterBeforeEach(func() {router = New(&tests.MockDataStore{})})It("returns a 404 problem for unknown paths", func() {w := serve(router, httptest.NewRequest(http.MethodGet, "/api/v1/nope", nil))Expect(w.Code).To(Equal(http.StatusNotFound))Expect(w.Header().Get("Content-Type")).To(Equal(problemContentType))Expect(decodeProblem(w).Code).To(Equal(ProblemCodeNotFound))})It("returns a 405 problem listing the allowed methods for a wrong method on a known path", func() {w := serve(router, httptest.NewRequest(http.MethodPost, "/api/v1/server", nil))Expect(w.Code).To(Equal(http.StatusMethodNotAllowed))Expect(w.Header().Get("Allow")).To(Equal("GET, HEAD"))Expect(decodeProblem(w).Code).To(Equal(ProblemCodeMethodNotAllowed))})DescribeTable("answers HEAD wherever GET is routed",func(path, contentType string) {w := serve(router, httptest.NewRequest(http.MethodHead, path, nil))Expect(w.Code).To(Equal(http.StatusOK))Expect(w.Header().Get("Content-Type")).To(Equal(contentType))},Entry("server info", "/api/v1/server", "application/json"),Entry("JSON spec", "/api/v1/openapi.json", "application/json"),Entry("YAML spec", "/api/v1/openapi.yaml", "application/yaml"),)It("revalidates HEAD requests with If-None-Match", func() {etag := serve(router, httptest.NewRequest(http.MethodHead, "/api/v1/openapi.json", nil)).Header().Get("ETag")req := httptest.NewRequest(http.MethodHead, "/api/v1/openapi.json", nil)req.Header.Set("If-None-Match", etag)Expect(serve(router, req).Code).To(Equal(http.StatusNotModified))})It("returns a 404 problem for HEAD on unknown paths", func() {w := serve(router, httptest.NewRequest(http.MethodHead, "/api/v1/nope", nil))Expect(w.Code).To(Equal(http.StatusNotFound))Expect(w.Header().Get("Allow")).To(BeEmpty())})panicking := func(v any) http.Handler {return problemRecoverer(http.HandlerFunc(func(http.ResponseWriter, *http.Request) { panic(v) }))}It("turns a handler panic into a 500 problem", func() {w := httptest.NewRecorder()panicking("kaboom").ServeHTTP(w, httptest.NewRequest(http.MethodGet, "/boom", nil))Expect(w.Code).To(Equal(http.StatusInternalServerError))p := decodeProblem(w)Expect(p.Code).To(Equal(ProblemCodeInternal))Expect(p.Detail).To(BeNil())})It("re-panics http.ErrAbortHandler so the server can drop the connection", func() {Expect(func() {panicking(http.ErrAbortHandler).ServeHTTP(httptest.NewRecorder(), httptest.NewRequest(http.MethodGet, "/abort", nil))}).To(PanicWith(http.ErrAbortHandler))})})