diff --git a/internal/server/server.go b/internal/server/server.go index 6531606..04059c1 100644 --- a/internal/server/server.go +++ b/internal/server/server.go @@ -95,6 +95,7 @@ func (s *Server) routes() chi.Router { r.Get("/health", s.handleHealth) r.Get("/", s.handleRoot) + r.Get("/version", s.handleVersion) proxyHandler := v1.NewProxyHandler(s.engine, s.virtEngine, s.db, s.store, s.localHandler) r.Mount("/api/v1", proxyHandler.Routes()) @@ -143,7 +144,13 @@ func (s *Server) handleHealth(w http.ResponseWriter, r *http.Request) { fmt.Fprint(w, `{"status":"ok"}`) } +// handleRoot sends browsers landing on the bare domain to the web UI, which is +// served under /ui. The service identity that used to live here is at /version. func (s *Server) handleRoot(w http.ResponseWriter, r *http.Request) { + http.Redirect(w, r, "/ui/", http.StatusFound) +} + +func (s *Server) handleVersion(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) fmt.Fprintf(w, `{"name":"artifactapi","version":"%s"}`, s.version) diff --git a/internal/server/server_test.go b/internal/server/server_test.go index 62b7bcf..fa12f6c 100644 --- a/internal/server/server_test.go +++ b/internal/server/server_test.go @@ -129,13 +129,32 @@ func req(t *testing.T, method, path string, body string) (*http.Response, []byte return resp, b } +// reqNoRedirect issues a request without following redirects so the response's +// status and Location header can be asserted directly. +func reqNoRedirect(t *testing.T, method, path string) *http.Response { + t.Helper() + rq, _ := http.NewRequest(method, testTS.URL+path, nil) + client := &http.Client{CheckRedirect: func(*http.Request, []*http.Request) error { + return http.ErrUseLastResponse + }} + resp, err := client.Do(rq) + if err != nil { + t.Fatalf("%s %s: %v", method, path, err) + } + resp.Body.Close() + return resp +} + func TestServerHealthAndRoot(t *testing.T) { requireStack(t) if resp, _ := req(t, "GET", "/health", ""); resp.StatusCode != 200 { t.Errorf("health: %d", resp.StatusCode) } - if resp, b := req(t, "GET", "/", ""); resp.StatusCode != 200 || !strings.Contains(string(b), "test-version") { - t.Errorf("root: %d %s", resp.StatusCode, b) + if resp := reqNoRedirect(t, "GET", "/"); resp.StatusCode != http.StatusFound || resp.Header.Get("Location") != "/ui/" { + t.Errorf("root redirect: %d %q", resp.StatusCode, resp.Header.Get("Location")) + } + if resp, b := req(t, "GET", "/version", ""); resp.StatusCode != 200 || !strings.Contains(string(b), "test-version") { + t.Errorf("version: %d %s", resp.StatusCode, b) } if resp, _ := req(t, "GET", "/api/v2/health", ""); resp.StatusCode != 200 { t.Errorf("health v2: %d", resp.StatusCode)