github.com/juju/juju@v0.0.0-20240327075706-a90865de2538/worker/caasprober/controller_test.go (about) 1 // Copyright 2020 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package caasprober_test 5 6 import ( 7 "errors" 8 "net/http" 9 "net/http/httptest" 10 "sync" 11 12 jc "github.com/juju/testing/checkers" 13 gc "gopkg.in/check.v1" 14 15 k8sconstants "github.com/juju/juju/caas/kubernetes/provider/constants" 16 "github.com/juju/juju/observability/probe" 17 "github.com/juju/juju/worker/caasprober" 18 ) 19 20 type ControllerSuite struct { 21 } 22 23 type dummyMux struct { 24 AddHandlerFunc func(string, string, http.Handler) error 25 RemoveHandlerFunc func(string, string) 26 } 27 28 var _ = gc.Suite(&ControllerSuite{}) 29 30 func (d *dummyMux) AddHandler(i, j string, h http.Handler) error { 31 if d.AddHandlerFunc == nil { 32 return nil 33 } 34 return d.AddHandlerFunc(i, j, h) 35 } 36 37 func (d *dummyMux) RemoveHandler(i, j string) { 38 if d.RemoveHandlerFunc != nil { 39 d.RemoveHandlerFunc(i, j) 40 } 41 } 42 43 func (s *ControllerSuite) TestControllerMuxRegistration(c *gc.C) { 44 var ( 45 livenessRegistered = false 46 livenessDeRegistered = false 47 readinessRegistered = false 48 readinessDeRegistered = false 49 startupRegistered = false 50 startupDeRegistered = false 51 waitGroup = sync.WaitGroup{} 52 ) 53 54 waitGroup.Add(3) 55 mux := dummyMux{ 56 AddHandlerFunc: func(m, p string, _ http.Handler) error { 57 c.Check(m, gc.Equals, http.MethodGet) 58 switch p { 59 case k8sconstants.AgentHTTPPathLiveness: 60 c.Check(livenessRegistered, jc.IsFalse) 61 livenessRegistered = true 62 waitGroup.Done() 63 case k8sconstants.AgentHTTPPathReadiness: 64 c.Check(readinessRegistered, jc.IsFalse) 65 readinessRegistered = true 66 waitGroup.Done() 67 case k8sconstants.AgentHTTPPathStartup: 68 c.Check(startupRegistered, jc.IsFalse) 69 startupRegistered = true 70 waitGroup.Done() 71 default: 72 c.Errorf("unknown path registered in controller: %s", p) 73 } 74 return nil 75 }, 76 RemoveHandlerFunc: func(m, p string) { 77 c.Check(m, gc.Equals, http.MethodGet) 78 switch p { 79 case k8sconstants.AgentHTTPPathLiveness: 80 c.Check(livenessDeRegistered, jc.IsFalse) 81 livenessDeRegistered = true 82 waitGroup.Done() 83 case k8sconstants.AgentHTTPPathReadiness: 84 c.Check(readinessDeRegistered, jc.IsFalse) 85 readinessDeRegistered = true 86 waitGroup.Done() 87 case k8sconstants.AgentHTTPPathStartup: 88 c.Check(startupDeRegistered, jc.IsFalse) 89 startupDeRegistered = true 90 waitGroup.Done() 91 default: 92 c.Errorf("unknown path registered in controller: %s", p) 93 } 94 }, 95 } 96 97 probes := caasprober.NewCAASProbes() 98 probes.Liveness.Probes["test"] = probe.NotImplemented 99 probes.Readiness.Probes["test"] = probe.NotImplemented 100 probes.Startup.Probes["test"] = probe.NotImplemented 101 102 controller, err := caasprober.NewController(probes, &mux) 103 c.Assert(err, jc.ErrorIsNil) 104 105 waitGroup.Wait() 106 waitGroup.Add(3) 107 controller.Kill() 108 109 waitGroup.Wait() 110 err = controller.Wait() 111 c.Assert(err, jc.ErrorIsNil) 112 113 c.Assert(livenessRegistered, jc.IsTrue) 114 c.Assert(livenessDeRegistered, jc.IsTrue) 115 c.Assert(readinessRegistered, jc.IsTrue) 116 c.Assert(readinessDeRegistered, jc.IsTrue) 117 c.Assert(startupRegistered, jc.IsTrue) 118 c.Assert(startupDeRegistered, jc.IsTrue) 119 } 120 121 func (s *ControllerSuite) TestControllerNotImplemented(c *gc.C) { 122 waitGroup := sync.WaitGroup{} 123 waitGroup.Add(3) 124 125 mux := dummyMux{ 126 AddHandlerFunc: func(m, p string, h http.Handler) error { 127 req := httptest.NewRequest(m, p, nil) 128 recorder := httptest.NewRecorder() 129 h.ServeHTTP(recorder, req) 130 c.Check(recorder.Result().StatusCode, gc.Equals, http.StatusNotImplemented) 131 waitGroup.Done() 132 return nil 133 }, 134 RemoveHandlerFunc: func(m, p string) {}, 135 } 136 137 probes := caasprober.NewCAASProbes() 138 probes.Liveness.Probes["test"] = probe.NotImplemented 139 probes.Readiness.Probes["test"] = probe.NotImplemented 140 probes.Startup.Probes["test"] = probe.NotImplemented 141 142 controller, err := caasprober.NewController(probes, &mux) 143 c.Assert(err, jc.ErrorIsNil) 144 145 waitGroup.Wait() 146 controller.Kill() 147 err = controller.Wait() 148 c.Assert(err, jc.ErrorIsNil) 149 } 150 151 func (s *ControllerSuite) TestControllerProbeError(c *gc.C) { 152 waitGroup := sync.WaitGroup{} 153 waitGroup.Add(3) 154 155 mux := dummyMux{ 156 AddHandlerFunc: func(m, p string, h http.Handler) error { 157 req := httptest.NewRequest(m, p, nil) 158 recorder := httptest.NewRecorder() 159 h.ServeHTTP(recorder, req) 160 c.Check(recorder.Result().StatusCode, gc.Equals, http.StatusInternalServerError) 161 waitGroup.Done() 162 return nil 163 }, 164 RemoveHandlerFunc: func(m, p string) {}, 165 } 166 167 probeErr := probe.ProberFn(func() (bool, error) { 168 return false, errors.New("test error") 169 }) 170 171 probes := caasprober.NewCAASProbes() 172 probes.Liveness.Probes["test"] = probeErr 173 probes.Readiness.Probes["test"] = probeErr 174 probes.Startup.Probes["test"] = probeErr 175 176 controller, err := caasprober.NewController(probes, &mux) 177 c.Assert(err, jc.ErrorIsNil) 178 179 waitGroup.Wait() 180 controller.Kill() 181 err = controller.Wait() 182 c.Assert(err, jc.ErrorIsNil) 183 } 184 185 func (s *ControllerSuite) TestControllerProbeFail(c *gc.C) { 186 waitGroup := sync.WaitGroup{} 187 waitGroup.Add(3) 188 189 mux := dummyMux{ 190 AddHandlerFunc: func(m, p string, h http.Handler) error { 191 req := httptest.NewRequest(m, p, nil) 192 recorder := httptest.NewRecorder() 193 h.ServeHTTP(recorder, req) 194 c.Check(recorder.Result().StatusCode, gc.Equals, http.StatusTeapot) 195 waitGroup.Done() 196 return nil 197 }, 198 RemoveHandlerFunc: func(m, p string) {}, 199 } 200 201 probeFail := probe.ProberFn(func() (bool, error) { 202 return false, nil 203 }) 204 205 probes := caasprober.NewCAASProbes() 206 probes.Liveness.Probes["test"] = probeFail 207 probes.Readiness.Probes["test"] = probeFail 208 probes.Startup.Probes["test"] = probeFail 209 210 controller, err := caasprober.NewController(probes, &mux) 211 c.Assert(err, jc.ErrorIsNil) 212 213 waitGroup.Wait() 214 controller.Kill() 215 err = controller.Wait() 216 c.Assert(err, jc.ErrorIsNil) 217 } 218 219 func (s *ControllerSuite) TestControllerProbePass(c *gc.C) { 220 waitGroup := sync.WaitGroup{} 221 waitGroup.Add(3) 222 223 mux := dummyMux{ 224 AddHandlerFunc: func(m, p string, h http.Handler) error { 225 req := httptest.NewRequest(m, p, nil) 226 recorder := httptest.NewRecorder() 227 h.ServeHTTP(recorder, req) 228 c.Check(recorder.Result().StatusCode, gc.Equals, http.StatusOK) 229 waitGroup.Done() 230 return nil 231 }, 232 RemoveHandlerFunc: func(m, p string) {}, 233 } 234 235 probes := caasprober.NewCAASProbes() 236 probes.Liveness.Probes["test"] = probe.Success 237 probes.Readiness.Probes["test"] = probe.Success 238 probes.Startup.Probes["test"] = probe.Success 239 240 controller, err := caasprober.NewController(probes, &mux) 241 c.Assert(err, jc.ErrorIsNil) 242 243 waitGroup.Wait() 244 controller.Kill() 245 err = controller.Wait() 246 c.Assert(err, jc.ErrorIsNil) 247 } 248 249 func (s *ControllerSuite) TestControllerProbePassDetailed(c *gc.C) { 250 waitGroup := sync.WaitGroup{} 251 waitGroup.Add(3) 252 253 mux := dummyMux{ 254 AddHandlerFunc: func(m, p string, h http.Handler) error { 255 req := httptest.NewRequest(m, p+"?detailed=true", nil) 256 recorder := httptest.NewRecorder() 257 h.ServeHTTP(recorder, req) 258 c.Check(recorder.Result().StatusCode, gc.Equals, http.StatusOK) 259 c.Check(recorder.Body.String(), jc.HasPrefix, `+ test 260 OK: probe`) 261 waitGroup.Done() 262 return nil 263 }, 264 RemoveHandlerFunc: func(m, p string) {}, 265 } 266 267 probes := caasprober.NewCAASProbes() 268 probes.Liveness.Probes["test"] = probe.Success 269 probes.Readiness.Probes["test"] = probe.Success 270 probes.Startup.Probes["test"] = probe.Success 271 272 controller, err := caasprober.NewController(probes, &mux) 273 c.Assert(err, jc.ErrorIsNil) 274 275 waitGroup.Wait() 276 controller.Kill() 277 err = controller.Wait() 278 c.Assert(err, jc.ErrorIsNil) 279 } 280 281 func (s *ControllerSuite) TestControllerProbeFailDetailed(c *gc.C) { 282 waitGroup := sync.WaitGroup{} 283 waitGroup.Add(3) 284 285 mux := dummyMux{ 286 AddHandlerFunc: func(m, p string, h http.Handler) error { 287 req := httptest.NewRequest(m, p+"?detailed=true", nil) 288 recorder := httptest.NewRecorder() 289 h.ServeHTTP(recorder, req) 290 c.Check(recorder.Result().StatusCode, gc.Equals, http.StatusOK) 291 c.Check(recorder.Body.String(), jc.HasPrefix, `- test: test error 292 Internal Server Error: probe`) 293 waitGroup.Done() 294 return nil 295 }, 296 RemoveHandlerFunc: func(m, p string) {}, 297 } 298 299 probeFail := probe.ProberFn(func() (bool, error) { 300 return false, errors.New("test error") 301 }) 302 303 probes := caasprober.NewCAASProbes() 304 probes.Liveness.Probes["test"] = probeFail 305 probes.Readiness.Probes["test"] = probeFail 306 probes.Startup.Probes["test"] = probeFail 307 308 controller, err := caasprober.NewController(probes, &mux) 309 c.Assert(err, jc.ErrorIsNil) 310 311 waitGroup.Wait() 312 controller.Kill() 313 err = controller.Wait() 314 c.Assert(err, jc.ErrorIsNil) 315 }