sigs.k8s.io/controller-runtime@v0.18.2/pkg/healthz/healthz_test.go (about) 1 /* 2 Copyright 2014 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package healthz_test 18 19 import ( 20 "errors" 21 "net/http" 22 "net/http/httptest" 23 24 . "github.com/onsi/ginkgo/v2" 25 . "github.com/onsi/gomega" 26 "sigs.k8s.io/controller-runtime/pkg/healthz" 27 ) 28 29 const ( 30 contentType = "text/plain; charset=utf-8" 31 ) 32 33 func requestTo(handler http.Handler, dest string) *httptest.ResponseRecorder { 34 req, err := http.NewRequest("GET", dest, nil) 35 Expect(err).NotTo(HaveOccurred()) 36 resp := httptest.NewRecorder() 37 handler.ServeHTTP(resp, req) 38 39 return resp 40 } 41 42 var _ = Describe("Healthz Handler", func() { 43 Describe("the aggregated endpoint", func() { 44 It("should return healthy if all checks succeed", func() { 45 handler := &healthz.Handler{Checks: map[string]healthz.Checker{ 46 "ok1": healthz.Ping, 47 "ok2": healthz.Ping, 48 }} 49 50 resp := requestTo(handler, "/") 51 Expect(resp.Code).To(Equal(http.StatusOK)) 52 }) 53 54 It("should return unhealthy if at least one check fails", func() { 55 handler := &healthz.Handler{Checks: map[string]healthz.Checker{ 56 "ok1": healthz.Ping, 57 "bad1": func(req *http.Request) error { 58 return errors.New("blech") 59 }, 60 }} 61 62 resp := requestTo(handler, "/") 63 Expect(resp.Code).To(Equal(http.StatusInternalServerError)) 64 }) 65 66 It("should ingore excluded checks when determining health", func() { 67 handler := &healthz.Handler{Checks: map[string]healthz.Checker{ 68 "ok1": healthz.Ping, 69 "bad1": func(req *http.Request) error { 70 return errors.New("blech") 71 }, 72 }} 73 74 resp := requestTo(handler, "/?exclude=bad1") 75 Expect(resp.Code).To(Equal(http.StatusOK)) 76 }) 77 78 It("should be fine if asked to exclude a check that doesn't exist", func() { 79 handler := &healthz.Handler{Checks: map[string]healthz.Checker{ 80 "ok1": healthz.Ping, 81 "ok2": healthz.Ping, 82 }} 83 84 resp := requestTo(handler, "/?exclude=nonexistant") 85 Expect(resp.Code).To(Equal(http.StatusOK)) 86 }) 87 88 Context("when verbose output is requested with ?verbose=true", func() { 89 It("should return verbose output for ok cases", func() { 90 handler := &healthz.Handler{Checks: map[string]healthz.Checker{ 91 "ok1": healthz.Ping, 92 "ok2": healthz.Ping, 93 }} 94 95 resp := requestTo(handler, "/?verbose=true") 96 Expect(resp.Code).To(Equal(http.StatusOK)) 97 Expect(resp.Header().Get("Content-Type")).To(Equal(contentType)) 98 Expect(resp.Body.String()).To(Equal("[+]ok1 ok\n[+]ok2 ok\nhealthz check passed\n")) 99 }) 100 101 It("should return verbose output for failures", func() { 102 handler := &healthz.Handler{Checks: map[string]healthz.Checker{ 103 "ok1": healthz.Ping, 104 "bad1": func(req *http.Request) error { 105 return errors.New("blech") 106 }, 107 }} 108 109 resp := requestTo(handler, "/?verbose=true") 110 Expect(resp.Code).To(Equal(http.StatusInternalServerError)) 111 Expect(resp.Header().Get("Content-Type")).To(Equal(contentType)) 112 Expect(resp.Body.String()).To(Equal("[-]bad1 failed: reason withheld\n[+]ok1 ok\nhealthz check failed\n")) 113 }) 114 }) 115 116 It("should return non-verbose output when healthy and not specified as verbose", func() { 117 handler := &healthz.Handler{Checks: map[string]healthz.Checker{ 118 "ok1": healthz.Ping, 119 "ok2": healthz.Ping, 120 }} 121 122 resp := requestTo(handler, "/") 123 Expect(resp.Header().Get("Content-Type")).To(Equal(contentType)) 124 Expect(resp.Body.String()).To(Equal("ok")) 125 126 }) 127 128 It("should always be verbose if a check fails", func() { 129 handler := &healthz.Handler{Checks: map[string]healthz.Checker{ 130 "ok1": healthz.Ping, 131 "bad1": func(req *http.Request) error { 132 return errors.New("blech") 133 }, 134 }} 135 136 resp := requestTo(handler, "/") 137 Expect(resp.Header().Get("Content-Type")).To(Equal(contentType)) 138 Expect(resp.Body.String()).To(Equal("[-]bad1 failed: reason withheld\n[+]ok1 ok\nhealthz check failed\n")) 139 }) 140 141 It("should always return a ping endpoint if no other ones are present", func() { 142 resp := requestTo(&healthz.Handler{}, "/?verbose=true") 143 Expect(resp.Code).To(Equal(http.StatusOK)) 144 Expect(resp.Header().Get("Content-Type")).To(Equal(contentType)) 145 Expect(resp.Body.String()).To(Equal("[+]ping ok\nhealthz check passed\n")) 146 }) 147 }) 148 149 Describe("the per-check endpoints", func() { 150 It("should return ok if the requested check is healthy", func() { 151 handler := &healthz.Handler{Checks: map[string]healthz.Checker{ 152 "okcheck": healthz.Ping, 153 }} 154 155 resp := requestTo(handler, "/okcheck") 156 Expect(resp.Code).To(Equal(http.StatusOK)) 157 Expect(resp.Header().Get("Content-Type")).To(Equal(contentType)) 158 Expect(resp.Body.String()).To(Equal("ok")) 159 }) 160 161 It("should return an error if the requested check is unhealthy", func() { 162 handler := &healthz.Handler{Checks: map[string]healthz.Checker{ 163 "failcheck": func(req *http.Request) error { 164 return errors.New("blech") 165 }, 166 }} 167 168 resp := requestTo(handler, "/failcheck") 169 Expect(resp.Code).To(Equal(http.StatusInternalServerError)) 170 Expect(resp.Header().Get("Content-Type")).To(Equal(contentType)) 171 Expect(resp.Body.String()).To(Equal("internal server error: blech\n")) 172 }) 173 174 It("shouldn't take other checks into account", func() { 175 handler := &healthz.Handler{Checks: map[string]healthz.Checker{ 176 "failcheck": func(req *http.Request) error { 177 return errors.New("blech") 178 }, 179 "okcheck": healthz.Ping, 180 }} 181 182 By("checking the bad endpoint and expecting it to fail") 183 resp := requestTo(handler, "/failcheck") 184 Expect(resp.Code).To(Equal(http.StatusInternalServerError)) 185 186 By("checking the good endpoint and expecting it to succeed") 187 resp = requestTo(handler, "/okcheck") 188 Expect(resp.Code).To(Equal(http.StatusOK)) 189 }) 190 191 It("should return non-found for paths that don't match a checker", func() { 192 handler := &healthz.Handler{} 193 194 resp := requestTo(handler, "/doesnotexist") 195 Expect(resp.Code).To(Equal(http.StatusNotFound)) 196 }) 197 198 It("should always return a ping endpoint if no other ones are present", func() { 199 resp := requestTo(&healthz.Handler{}, "/ping") 200 Expect(resp.Code).To(Equal(http.StatusOK)) 201 }) 202 }) 203 })