diff --git a/internal/app/server/app.go b/internal/app/server/app.go index 678ebab..8b27b47 100644 --- a/internal/app/server/app.go +++ b/internal/app/server/app.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" "net/http" + "sync" "github.com/go-chi/chi/v5" "github.com/theruziev/starter/internal/pkg/closer" @@ -20,6 +21,8 @@ type Server struct { closer *closer.Closer r chi.Router healthcheck *health.Server + + routerOnce sync.Once } type Options struct { @@ -46,15 +49,17 @@ func (s *Server) initHealthCheck(_ context.Context) { } func (s *Server) initRouter(_ context.Context) { - r := chi.NewRouter() - r.Get("/", func(w http.ResponseWriter, r *http.Request) { - w.WriteHeader(http.StatusOK) - _, _ = w.Write([]byte("Hello world!")) + s.routerOnce.Do(func() { + r := chi.NewRouter() + r.Get("/", func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusOK) + _, _ = w.Write([]byte("Hello world!")) + }) + r.Get("/live", healthcheck.NewLivenessHandler()) + r.Get("/ready", healthcheck.NewReadinessHandler(s.healthcheck)) + r.Get("/version", info.Handler()) + s.r = r }) - r.Get("/live", healthcheck.NewLivenessHandler()) - r.Get("/ready", healthcheck.NewReadinessHandler(s.healthcheck)) - r.Get("/version", info.Handler()) - s.r = r } func (s *Server) Run(ctx context.Context) error { diff --git a/internal/pkg/healthcheck/healthcheck_test.go b/internal/pkg/healthcheck/healthcheck_test.go index c7070d7..6a8e8a6 100644 --- a/internal/pkg/healthcheck/healthcheck_test.go +++ b/internal/pkg/healthcheck/healthcheck_test.go @@ -1,12 +1,50 @@ package healthcheck import ( + "net/http" + "net/http/httptest" "testing" "github.com/stretchr/testify/require" ) -func TestNewHealthCheck(t *testing.T) { - healthcheck := NewHealthCheck() - require.NotNil(t, healthcheck) +func TestNewLivenessHandler(t *testing.T) { + req, err := http.NewRequest("GET", "/live", nil) + require.NoError(t, err) + + rr := httptest.NewRecorder() + handler := NewLivenessHandler() + + handler.ServeHTTP(rr, req) + + require.Equal(t, http.StatusOK, rr.Code) +} + +func TestNewReadinessHandler(t *testing.T) { + t.Run("not serving", func(t *testing.T) { + healthcheck := NewHealthCheck() + req, err := http.NewRequest("GET", "/ready", nil) + require.NoError(t, err) + + healthcheck.Shutdown() + rr := httptest.NewRecorder() + handler := NewReadinessHandler(healthcheck) + + handler.ServeHTTP(rr, req) + require.Equal(t, http.StatusServiceUnavailable, rr.Code) + }) + + t.Run("serving", func(t *testing.T) { + healthcheck := NewHealthCheck() + req, err := http.NewRequest("GET", "/ready", nil) + require.NoError(t, err) + + healthcheck.Resume() + rr := httptest.NewRecorder() + handler := NewReadinessHandler(healthcheck) + + handler.ServeHTTP(rr, req) + require.Equal(t, http.StatusOK, rr.Code) + }) + } diff --git a/internal/pkg/info/info_test.go b/internal/pkg/info/info_test.go new file mode 100644 index 0000000..8ca146e --- /dev/null +++ b/internal/pkg/info/info_test.go @@ -0,0 +1,35 @@ +package info + +import ( + "encoding/json" + "net/http" + "net/http/httptest" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestHandler(t *testing.T) { + req, err := http.NewRequest("GET", "/info", nil) + if err != nil { + t.Fatal(err) + } + + rr := httptest.NewRecorder() + handler := Handler() + + handler.ServeHTTP(rr, req) + + require.Equal(t, http.StatusOK, rr.Code) + + expected := map[string]any{ + "version": Version, + "commit": Commit, + } + + var got map[string]any + err = json.NewDecoder(rr.Body).Decode(&got) + require.NoError(t, err) + require.EqualValues(t, expected, got) + +} diff --git a/internal/pkg/logx/ctx_test.go b/internal/pkg/logx/ctx_test.go new file mode 100644 index 0000000..c25210e --- /dev/null +++ b/internal/pkg/logx/ctx_test.go @@ -0,0 +1,29 @@ +package logx + +import ( + "context" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "go.uber.org/zap" +) + +func TestWithLogger(t *testing.T) { + ctx := context.Background() + log := zap.NewExample().Sugar() + + newCtx := WithLogger(ctx, log) + + require.Equal(t, log, newCtx.Value(loggerKey)) +} + +func TestFromContext(t *testing.T) { + log := zap.NewExample().Sugar() + ctx := context.WithValue(context.Background(), loggerKey, log) + + assert.Equal(t, log, FromContext(ctx)) + + emptyCtx := context.Background() + require.Equal(t, DefaultLogger(), FromContext(emptyCtx)) +}