func DefaultHealthyHandler(w http.ResponseWriter, r *http.Request) { err := httputil.WriteJSONResponse(w, http.StatusOK, StatusResponse{ Status: "ok", }) if err != nil { // TODO(bobbyrullo): replace with logging from new logging pkg, // once it lands. log.Printf("Failed to write JSON response: %v", err) } }
func DefaultUnhealthyHandler(w http.ResponseWriter, r *http.Request, err error) { writeErr := httputil.WriteJSONResponse(w, http.StatusInternalServerError, StatusResponse{ Status: "error", Details: &StatusResponseDetails{ Code: http.StatusInternalServerError, Message: err.Error(), }, }) if writeErr != nil { // TODO(bobbyrullo): replace with logging from new logging pkg, // once it lands. log.Printf("Failed to write JSON response: %v", err) } }
func TestHandlerFunc(t *testing.T) { for i, test := range []struct { checker Checker method string expectedStatus string expectedCode int expectedMessage string }{ { Checker{ Checks: []Checkable{ boolChecker(true), }, }, "GET", "ok", http.StatusOK, "", }, // Wrong method. { Checker{ Checks: []Checkable{ boolChecker(true), }, }, "POST", "", http.StatusMethodNotAllowed, "GET only acceptable method", }, // Health check fails. { Checker{ Checks: []Checkable{ boolChecker(false), }, }, "GET", "error", http.StatusInternalServerError, "Unhealthy", }, // Health check fails, with overridden ErrorHandler. { Checker{ Checks: []Checkable{ boolChecker(false), }, UnhealthyHandler: func(w http.ResponseWriter, r *http.Request, err error) { httputil.WriteJSONResponse(w, http.StatusInternalServerError, StatusResponse{ Status: "error", Details: &StatusResponseDetails{ Code: http.StatusInternalServerError, Message: "Override!", }, }) }, }, "GET", "error", http.StatusInternalServerError, "Override!", }, // Health check succeeds, with overridden SuccessHandler. { Checker{ Checks: []Checkable{ boolChecker(true), }, HealthyHandler: func(w http.ResponseWriter, r *http.Request) { httputil.WriteJSONResponse(w, http.StatusOK, StatusResponse{ Status: "okey-dokey", }) }, }, "GET", "okey-dokey", http.StatusOK, "", }, } { w := httptest.NewRecorder() r := &http.Request{} r.Method = test.method test.checker.ServeHTTP(w, r) if w.Code != test.expectedCode { t.Errorf("case %d: w.code == %v, want %v", i, w.Code, test.expectedCode) } if test.expectedStatus == "" { // This is to handle the wrong-method case, when the // body of the response is empty. continue } statusMap := make(map[string]interface{}) err := json.Unmarshal(w.Body.Bytes(), &statusMap) if err != nil { t.Fatalf("case %d: failed to Unmarshal response body: %v", i, err) } status, ok := statusMap["status"].(string) if !ok { t.Errorf("case %d: status not present or not a string in json: %q", i, w.Body.Bytes()) } if status != test.expectedStatus { t.Errorf("case %d: status == %v, want %v", i, status, test.expectedStatus) } detailMap, ok := statusMap["details"].(map[string]interface{}) if test.expectedMessage != "" { if !ok { t.Fatalf("case %d: could not find/unmarshal detailMap", i) } message, ok := detailMap["message"].(string) if !ok { t.Fatalf("case %d: message not present or not a string in json: %q", i, w.Body.Bytes()) } if message != test.expectedMessage { t.Errorf("case %d: message == %v, want %v", i, message, test.expectedMessage) } code, ok := detailMap["code"].(float64) if !ok { t.Fatalf("case %d: code not present or not an int in json: %q", i, w.Body.Bytes()) } if int(code) != test.expectedCode { t.Errorf("case %d: code == %v, want %v", i, code, test.expectedCode) } } else { if ok { t.Errorf("case %d: unwanted detailMap present: %q", i, detailMap) } } } }