forked from TrueCloudLab/distribution
a1b49d3d17
Allow health checkers to abort if the request context is canceled. Modify the checkers to respect context cancelation and return wrapped errors so the caller of CheckStatus() would be able to discriminate true failed checks from checks which were aborted because the context became done. Signed-off-by: Cory Snider <csnider@mirantis.com>
108 lines
2.9 KiB
Go
108 lines
2.9 KiB
Go
package health
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"testing"
|
|
)
|
|
|
|
// TestReturns200IfThereAreNoChecks ensures that the result code of the health
|
|
// endpoint is 200 if there are not currently registered checks.
|
|
func TestReturns200IfThereAreNoChecks(t *testing.T) {
|
|
recorder := httptest.NewRecorder()
|
|
|
|
req, err := http.NewRequest(http.MethodGet, "https://fakeurl.com/debug/health", nil)
|
|
if err != nil {
|
|
t.Errorf("Failed to create request.")
|
|
}
|
|
|
|
StatusHandler(recorder, req)
|
|
|
|
if recorder.Code != 200 {
|
|
t.Errorf("Did not get a 200.")
|
|
}
|
|
}
|
|
|
|
// TestReturns503IfThereAreErrorChecks ensures that the result code of the
|
|
// health endpoint is 503 if there are health checks with errors.
|
|
func TestReturns503IfThereAreErrorChecks(t *testing.T) {
|
|
recorder := httptest.NewRecorder()
|
|
|
|
req, err := http.NewRequest(http.MethodGet, "https://fakeurl.com/debug/health", nil)
|
|
if err != nil {
|
|
t.Errorf("Failed to create request.")
|
|
}
|
|
|
|
// Create a manual error
|
|
Register("some_check", CheckFunc(func(context.Context) error {
|
|
return errors.New("This Check did not succeed")
|
|
}))
|
|
|
|
StatusHandler(recorder, req)
|
|
|
|
if recorder.Code != 503 {
|
|
t.Errorf("Did not get a 503.")
|
|
}
|
|
}
|
|
|
|
// TestHealthHandler ensures that our handler implementation correct protects
|
|
// the web application when things aren't so healthy.
|
|
func TestHealthHandler(t *testing.T) {
|
|
// clear out existing checks.
|
|
DefaultRegistry = NewRegistry()
|
|
|
|
// protect an http server
|
|
handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.WriteHeader(http.StatusNoContent)
|
|
}))
|
|
|
|
// wrap it in our health handler
|
|
handler = Handler(handler)
|
|
|
|
// use this swap check status
|
|
updater := NewStatusUpdater()
|
|
Register("test_check", updater)
|
|
|
|
// now, create a test server
|
|
server := httptest.NewServer(handler)
|
|
|
|
checkUp := func(t *testing.T, message string) {
|
|
resp, err := http.Get(server.URL)
|
|
if err != nil {
|
|
t.Fatalf("error getting success status: %v", err)
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
if resp.StatusCode != http.StatusNoContent {
|
|
t.Fatalf("unexpected response code from server when %s: %d != %d", message, resp.StatusCode, http.StatusNoContent)
|
|
}
|
|
// NOTE(stevvooe): we really don't care about the body -- the format is
|
|
// not standardized or supported, yet.
|
|
}
|
|
|
|
checkDown := func(t *testing.T, message string) {
|
|
resp, err := http.Get(server.URL)
|
|
if err != nil {
|
|
t.Fatalf("error getting down status: %v", err)
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
if resp.StatusCode != http.StatusServiceUnavailable {
|
|
t.Fatalf("unexpected response code from server when %s: %d != %d", message, resp.StatusCode, http.StatusServiceUnavailable)
|
|
}
|
|
}
|
|
|
|
// server should be up
|
|
checkUp(t, "initial health check")
|
|
|
|
// now, we fail the health check
|
|
updater.Update(fmt.Errorf("the server is now out of commission"))
|
|
checkDown(t, "server should be down") // should be down
|
|
|
|
// bring server back up
|
|
updater.Update(nil)
|
|
checkUp(t, "when server is back up") // now we should be back up.
|
|
}
|