From 588712d1d48f8e94eb70d95951119d111f0ba863 Mon Sep 17 00:00:00 2001 From: Chris Hager Date: Wed, 25 Sep 2024 11:49:20 +0200 Subject: [PATCH] simpler http handler tests --- httpserver/handler.go | 24 +++++++-------- httpserver/handler_test.go | 18 +++++++++++ httpserver/server.go | 63 ++++++++++++++++++++------------------ 3 files changed, 63 insertions(+), 42 deletions(-) diff --git a/httpserver/handler.go b/httpserver/handler.go index da04690..05a1f9a 100644 --- a/httpserver/handler.go +++ b/httpserver/handler.go @@ -7,8 +7,8 @@ import ( "github.com/flashbots/go-template/metrics" ) -func (s *Server) handleAPI(w http.ResponseWriter, r *http.Request) { - m := s.metricsSrv.Float64Histogram( +func (srv *Server) handleAPI(w http.ResponseWriter, r *http.Request) { + m := srv.metricsSrv.Float64Histogram( "request_duration_api", "API request handling duration", metrics.UomMicroseconds, @@ -23,12 +23,12 @@ func (s *Server) handleAPI(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) } -func (s *Server) handleLivenessCheck(w http.ResponseWriter, r *http.Request) { +func (srv *Server) handleLivenessCheck(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) } -func (s *Server) handleReadinessCheck(w http.ResponseWriter, r *http.Request) { - if !s.isReady.Load() { +func (srv *Server) handleReadinessCheck(w http.ResponseWriter, r *http.Request) { + if !srv.isReady.Load() { w.WriteHeader(http.StatusServiceUnavailable) return } @@ -36,19 +36,19 @@ func (s *Server) handleReadinessCheck(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) } -func (s *Server) handleDrain(w http.ResponseWriter, r *http.Request) { - if wasReady := s.isReady.Swap(false); !wasReady { +func (srv *Server) handleDrain(w http.ResponseWriter, r *http.Request) { + if wasReady := srv.isReady.Swap(false); !wasReady { return } // l := logutils.ZapFromRequest(r) - s.log.Info("Server marked as not ready") - time.Sleep(s.cfg.DrainDuration) // Give LB enough time to detect us not ready + srv.log.Info("Server marked as not ready") + time.Sleep(srv.cfg.DrainDuration) // Give LB enough time to detect us not ready } -func (s *Server) handleUndrain(w http.ResponseWriter, r *http.Request) { - if wasReady := s.isReady.Swap(true); wasReady { +func (srv *Server) handleUndrain(w http.ResponseWriter, r *http.Request) { + if wasReady := srv.isReady.Swap(true); wasReady { return } // l := logutils.ZapFromRequest(r) - s.log.Info("Server marked as ready") + srv.log.Info("Server marked as ready") } diff --git a/httpserver/handler_test.go b/httpserver/handler_test.go index 81816fd..c27d5fb 100644 --- a/httpserver/handler_test.go +++ b/httpserver/handler_test.go @@ -94,3 +94,21 @@ func Test_Handlers_Healthcheck_Drain_Undrain(t *testing.T) { require.Equal(t, http.StatusOK, resp.StatusCode, "Healthcheck must return `Ok` after undraining") } } + +func Test_Handlers_Simple(t *testing.T) { + // This test doesn't need the server to actually start and serve. Instead it just tests the handlers. + //nolint: exhaustruct + srv, err := New(&HTTPServerConfig{ + Log: getTestLogger(), + }) + require.NoError(t, err) + + { // Check health + req, err := http.NewRequest(http.MethodGet, "/readyz", nil) //nolint:goconst,nolintlint + require.NoError(t, err) + + rr := httptest.NewRecorder() + srv.getRouter().ServeHTTP(rr, req) + require.Equal(t, http.StatusOK, rr.Code) + } +} diff --git a/httpserver/server.go b/httpserver/server.go index 9121d8b..084d1a5 100644 --- a/httpserver/server.go +++ b/httpserver/server.go @@ -50,6 +50,17 @@ func New(cfg *HTTPServerConfig) (srv *Server, err error) { } srv.isReady.Swap(true) + srv.srv = &http.Server{ + Addr: cfg.ListenAddr, + Handler: srv.getRouter(), + ReadTimeout: cfg.ReadTimeout, + WriteTimeout: cfg.WriteTimeout, + } + + return srv, nil +} + +func (srv *Server) getRouter() http.Handler { mux := chi.NewRouter() mux.With(srv.httpLogger).Get("/api", srv.handleAPI) // Never serve at `/` (root) path mux.With(srv.httpLogger).Get("/livez", srv.handleLivenessCheck) @@ -57,65 +68,57 @@ func New(cfg *HTTPServerConfig) (srv *Server, err error) { mux.With(srv.httpLogger).Get("/drain", srv.handleDrain) mux.With(srv.httpLogger).Get("/undrain", srv.handleUndrain) - if cfg.EnablePprof { + if srv.cfg.EnablePprof { srv.log.Info("pprof API enabled") mux.Mount("/debug", middleware.Profiler()) } - - srv.srv = &http.Server{ - Addr: cfg.ListenAddr, - Handler: mux, - ReadTimeout: cfg.ReadTimeout, - WriteTimeout: cfg.WriteTimeout, - } - - return srv, nil + return mux } -func (s *Server) httpLogger(next http.Handler) http.Handler { - return httplogger.LoggingMiddlewareSlog(s.log, next) +func (srv *Server) httpLogger(next http.Handler) http.Handler { + return httplogger.LoggingMiddlewareSlog(srv.log, next) } -func (s *Server) RunInBackground() { +func (srv *Server) RunInBackground() { // metrics - if s.cfg.MetricsAddr != "" { + if srv.cfg.MetricsAddr != "" { go func() { - s.log.With("metricsAddress", s.cfg.MetricsAddr).Info("Starting metrics server") - err := s.metricsSrv.ListenAndServe() + srv.log.With("metricsAddress", srv.cfg.MetricsAddr).Info("Starting metrics server") + err := srv.metricsSrv.ListenAndServe() if err != nil && !errors.Is(err, http.ErrServerClosed) { - s.log.Error("HTTP server failed", "err", err) + srv.log.Error("HTTP server failed", "err", err) } }() } // api go func() { - s.log.Info("Starting HTTP server", "listenAddress", s.cfg.ListenAddr) - if err := s.srv.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) { - s.log.Error("HTTP server failed", "err", err) + srv.log.Info("Starting HTTP server", "listenAddress", srv.cfg.ListenAddr) + if err := srv.srv.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) { + srv.log.Error("HTTP server failed", "err", err) } }() } -func (s *Server) Shutdown() { +func (srv *Server) Shutdown() { // api - ctx, cancel := context.WithTimeout(context.Background(), s.cfg.GracefulShutdownDuration) + ctx, cancel := context.WithTimeout(context.Background(), srv.cfg.GracefulShutdownDuration) defer cancel() - if err := s.srv.Shutdown(ctx); err != nil { - s.log.Error("Graceful HTTP server shutdown failed", "err", err) + if err := srv.srv.Shutdown(ctx); err != nil { + srv.log.Error("Graceful HTTP server shutdown failed", "err", err) } else { - s.log.Info("HTTP server gracefully stopped") + srv.log.Info("HTTP server gracefully stopped") } // metrics - if len(s.cfg.MetricsAddr) != 0 { - ctx, cancel := context.WithTimeout(context.Background(), s.cfg.GracefulShutdownDuration) + if len(srv.cfg.MetricsAddr) != 0 { + ctx, cancel := context.WithTimeout(context.Background(), srv.cfg.GracefulShutdownDuration) defer cancel() - if err := s.metricsSrv.Shutdown(ctx); err != nil { - s.log.Error("Graceful metrics server shutdown failed", "err", err) + if err := srv.metricsSrv.Shutdown(ctx); err != nil { + srv.log.Error("Graceful metrics server shutdown failed", "err", err) } else { - s.log.Info("Metrics server gracefully stopped") + srv.log.Info("Metrics server gracefully stopped") } } }