Skip to content
This repository has been archived by the owner on Mar 15, 2022. It is now read-only.

Handler now accepts customizable routes for liveness and readiness #20

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,12 @@ See the [GoDoc examples](https://godoc.org/github.com/heptiolabs/healthcheck) fo
```go
health := healthcheck.NewHandler()
```
or
```go
liveURL := "/liveness"
readyURL := "/readiness"
health := healthcheck.NewHandlerCustomURL(liveURL, readyURL)
```

- Configure some application-specific liveness checks (whether the app itself is unhealthy):
```go
Expand Down
4 changes: 2 additions & 2 deletions example_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -163,10 +163,10 @@ func Example_metrics() {
adminMux.Handle("/metrics", promhttp.HandlerFor(registry, promhttp.HandlerOpts{}))

// Expose a liveness check on /live
adminMux.HandleFunc("/live", health.LiveEndpoint)
adminMux.HandleFunc(oriLiveEndpoint, health.LiveEndpoint)

// Expose a readiness check on /ready
adminMux.HandleFunc("/ready", health.ReadyEndpoint)
adminMux.HandleFunc(oriReadyEndpoint, health.ReadyEndpoint)

// Make a request to the metrics endpoint and print the response.
fmt.Println(dumpRequest(adminMux, "GET", "/metrics"))
Expand Down
30 changes: 28 additions & 2 deletions handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ import (
"sync"
)

const (
oriLiveEndpoint = "/live"
oriReadyEndpoint = "/ready"
)

// basicHandler is a basic Handler implementation.
type basicHandler struct {
http.ServeMux
Expand All @@ -34,8 +39,29 @@ func NewHandler() Handler {
livenessChecks: make(map[string]Check),
readinessChecks: make(map[string]Check),
}
h.Handle("/live", http.HandlerFunc(h.LiveEndpoint))
h.Handle("/ready", http.HandlerFunc(h.ReadyEndpoint))

h.Handle(oriLiveEndpoint, http.HandlerFunc(h.LiveEndpoint))
h.Handle(oriReadyEndpoint, http.HandlerFunc(h.ReadyEndpoint))
return h
}

// NewHandlerCustomURL creates a new basic Handler with custom URL for liveness and readiness
func NewHandlerCustomURL(customLiveEndpoint, customReadyEndpoint string) Handler {
if customLiveEndpoint == "" {
customLiveEndpoint = oriLiveEndpoint
}

if customReadyEndpoint == "" {
customReadyEndpoint = oriReadyEndpoint
}

h := &basicHandler{
livenessChecks: make(map[string]Check),
readinessChecks: make(map[string]Check),
}

h.Handle(customLiveEndpoint, http.HandlerFunc(h.LiveEndpoint))
h.Handle(customReadyEndpoint, http.HandlerFunc(h.ReadyEndpoint))
return h
}

Expand Down
78 changes: 69 additions & 9 deletions handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,20 @@ import (
"github.com/stretchr/testify/assert"
)

func checkEnpoint(t *testing.T, handler Handler, httpMethod, testPath, expectedBody string, expectedHTTPCode int) {
req, err := http.NewRequest(httpMethod, testPath, nil)
assert.NoError(t, err)

reqStr := httpMethod + " " + testPath
rr := httptest.NewRecorder()
handler.ServeHTTP(rr, req)
assert.Equal(t, expectedHTTPCode, rr.Code, "wrong code for %q", reqStr)

if expectedBody != "" {
assert.Equal(t, expectedBody, rr.Body.String(), "wrong body for %q", reqStr)
}
}

func TestNewHandler(t *testing.T) {
tests := []struct {
name string
Expand Down Expand Up @@ -137,17 +151,63 @@ func TestNewHandler(t *testing.T) {
})
}

req, err := http.NewRequest(tt.method, tt.path, nil)
assert.NoError(t, err)
checkEnpoint(t, h, tt.method, tt.path, tt.expectBody, tt.expect)
})
}
}

reqStr := tt.method + " " + tt.path
rr := httptest.NewRecorder()
h.ServeHTTP(rr, req)
assert.Equal(t, tt.expect, rr.Code, "wrong code for %q", reqStr)
func TestNewHandlerCustomURL(t *testing.T) {
liveEndpoint := "/liveness"
readyEndpoint := "/readiness"
emptyEndpoint := ""

if tt.expectBody != "" {
assert.Equal(t, tt.expectBody, rr.Body.String(), "wrong body for %q", reqStr)
}
tests := []struct {
name string
method string
customLiveEndpoint string
custoReadyEndpoint string
expectedLivenessPath string
expectedReadinessPath string
expect int
expectBody string
}{
{
name: "using only custom liveness endpoint, call to custom liveness endpoint and original readiness endpoint should succeed",
method: http.MethodGet,
customLiveEndpoint: liveEndpoint,
custoReadyEndpoint: emptyEndpoint,
expectedLivenessPath: liveEndpoint,
expectedReadinessPath: "/ready",
expect: http.StatusOK,
expectBody: "{}\n",
},
{
name: "using only custom readiness endpoint, call to custom readiness endpoint and original liveness endpoint should succeed",
method: http.MethodGet,
customLiveEndpoint: emptyEndpoint,
custoReadyEndpoint: readyEndpoint,
expectedLivenessPath: "/live",
expectedReadinessPath: readyEndpoint,
expect: http.StatusOK,
expectBody: "{}\n",
},
{
name: "with no custom liveness endpoints, the default hanlder should be called and hence original liveness and readiness endpoint should succeed",
method: http.MethodGet,
customLiveEndpoint: emptyEndpoint,
custoReadyEndpoint: emptyEndpoint,
expectedLivenessPath: "/live",
expectedReadinessPath: "/ready",
expect: http.StatusOK,
expectBody: "{}\n",
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
h := NewHandlerCustomURL(tt.customLiveEndpoint, tt.custoReadyEndpoint)
checkEnpoint(t, h, tt.method, tt.expectedLivenessPath, tt.expectBody, tt.expect)
checkEnpoint(t, h, tt.method, tt.expectedReadinessPath, tt.expectBody, tt.expect)
})
}
}