blob: 1b618be67198d25011ed3da01d3fea2f3efa7006 [file] [log] [blame]
Scott Baker2c1c4822019-10-16 11:02:41 -07001/*
Joey Armstrong9cdee9f2024-01-03 04:56:14 -05002 * Copyright 2019-2024 Open Networking Foundation (ONF) and the ONF Contributors
Scott Baker2c1c4822019-10-16 11:02:41 -07003 *
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 */
16package probe
17
18import (
19 "context"
20 "encoding/json"
Akash Reddy Kankanala05aff182025-05-06 12:57:32 +053021 "io"
Scott Baker2c1c4822019-10-16 11:02:41 -070022 "net/http"
23 "net/http/httptest"
24 "testing"
npujar5bf737f2020-01-16 19:35:25 +053025 "time"
Akash Reddy Kankanala05aff182025-05-06 12:57:32 +053026
27 "github.com/stretchr/testify/assert"
Scott Baker2c1c4822019-10-16 11:02:41 -070028)
29
Scott Baker2c1c4822019-10-16 11:02:41 -070030func TestServiceStatusString(t *testing.T) {
31 assert.Equal(t, "Unknown", ServiceStatusUnknown.String(), "ServiceStatusUnknown")
32 assert.Equal(t, "Preparing", ServiceStatusPreparing.String(), "ServiceStatusPreparing")
33 assert.Equal(t, "Prepared", ServiceStatusPrepared.String(), "ServiceStatusPrepared")
34 assert.Equal(t, "Running", ServiceStatusRunning.String(), "ServiceStatusRunning")
35 assert.Equal(t, "Stopped", ServiceStatusStopped.String(), "ServiceStatusStopped")
36 assert.Equal(t, "Failed", ServiceStatusFailed.String(), "ServiceStatusFailed")
Scott Baker104b67d2019-10-29 15:56:27 -070037 assert.Equal(t, "NotReady", ServiceStatusNotReady.String(), "ServiceStatusNotReady")
Scott Baker2c1c4822019-10-16 11:02:41 -070038}
39
40func AlwaysTrue(map[string]ServiceStatus) bool {
41 return true
42}
43
44func AlwaysFalse(map[string]ServiceStatus) bool {
45 return false
46}
47
48func TestWithFuncs(t *testing.T) {
49 p := (&Probe{}).WithReadyFunc(AlwaysTrue).WithHealthFunc(AlwaysFalse)
50
51 assert.NotNil(t, p.readyFunc, "ready func not set")
52 assert.True(t, p.readyFunc(nil), "ready func not set correctly")
53 assert.NotNil(t, p.healthFunc, "health func not set")
54 assert.False(t, p.healthFunc(nil), "health func not set correctly")
55}
56
57func TestWithReadyFuncOnly(t *testing.T) {
58 p := (&Probe{}).WithReadyFunc(AlwaysTrue)
59
60 assert.NotNil(t, p.readyFunc, "ready func not set")
61 assert.True(t, p.readyFunc(nil), "ready func not set correctly")
62 assert.Nil(t, p.healthFunc, "health func set")
63}
64
65func TestWithHealthFuncOnly(t *testing.T) {
66 p := (&Probe{}).WithHealthFunc(AlwaysTrue)
67
68 assert.Nil(t, p.readyFunc, "ready func set")
69 assert.NotNil(t, p.healthFunc, "health func not set")
70 assert.True(t, p.healthFunc(nil), "health func not set correctly")
71}
72
73func TestRegisterOneService(t *testing.T) {
74 p := &Probe{}
75
Neha Sharma94f16a92020-06-26 04:17:55 +000076 p.RegisterService(context.Background(), "one")
Scott Baker2c1c4822019-10-16 11:02:41 -070077
78 assert.Equal(t, 1, len(p.status), "wrong number of services")
79
80 _, ok := p.status["one"]
81 assert.True(t, ok, "service not found")
82}
83
84func TestRegisterMultipleServices(t *testing.T) {
85 p := &Probe{}
86
Neha Sharma94f16a92020-06-26 04:17:55 +000087 p.RegisterService(context.Background(), "one", "two", "three", "four")
Scott Baker2c1c4822019-10-16 11:02:41 -070088
89 assert.Equal(t, 4, len(p.status), "wrong number of services")
90
91 _, ok := p.status["one"]
92 assert.True(t, ok, "service one not found")
93 _, ok = p.status["two"]
94 assert.True(t, ok, "service two not found")
95 _, ok = p.status["three"]
96 assert.True(t, ok, "service three not found")
97 _, ok = p.status["four"]
98 assert.True(t, ok, "service four not found")
99}
100
101func TestRegisterMultipleServicesIncremental(t *testing.T) {
102 p := &Probe{}
Neha Sharma94f16a92020-06-26 04:17:55 +0000103 ctx := context.Background()
104 p.RegisterService(ctx, "one")
105 p.RegisterService(ctx, "two")
106 p.RegisterService(ctx, "three", "four")
Scott Baker2c1c4822019-10-16 11:02:41 -0700107
108 assert.Equal(t, 4, len(p.status), "wrong number of services")
109
110 _, ok := p.status["one"]
111 assert.True(t, ok, "service one not found")
112 _, ok = p.status["two"]
113 assert.True(t, ok, "service two not found")
114 _, ok = p.status["three"]
115 assert.True(t, ok, "service three not found")
116 _, ok = p.status["four"]
117 assert.True(t, ok, "service four not found")
118}
119
120func TestRegisterMultipleServicesDuplicates(t *testing.T) {
121 p := &Probe{}
122
Neha Sharma94f16a92020-06-26 04:17:55 +0000123 p.RegisterService(context.Background(), "one", "one", "one", "two")
Scott Baker2c1c4822019-10-16 11:02:41 -0700124
125 assert.Equal(t, 2, len(p.status), "wrong number of services")
126
127 _, ok := p.status["one"]
128 assert.True(t, ok, "service one not found")
129 _, ok = p.status["two"]
130 assert.True(t, ok, "service two not found")
131}
132
133func TestRegisterMultipleServicesDuplicatesIncremental(t *testing.T) {
134 p := &Probe{}
Neha Sharma94f16a92020-06-26 04:17:55 +0000135 ctx := context.Background()
136 p.RegisterService(ctx, "one")
137 p.RegisterService(ctx, "one")
138 p.RegisterService(ctx, "one", "two")
Scott Baker2c1c4822019-10-16 11:02:41 -0700139
140 assert.Equal(t, 2, len(p.status), "wrong number of services")
141
142 _, ok := p.status["one"]
143 assert.True(t, ok, "service one not found")
144 _, ok = p.status["two"]
145 assert.True(t, ok, "service two not found")
146}
147
148func TestUpdateStatus(t *testing.T) {
149 p := &Probe{}
Neha Sharma94f16a92020-06-26 04:17:55 +0000150 ctx := context.Background()
151 p.RegisterService(ctx, "one", "two")
152 p.UpdateStatus(ctx, "one", ServiceStatusRunning)
Scott Baker2c1c4822019-10-16 11:02:41 -0700153
154 assert.Equal(t, ServiceStatusRunning, p.status["one"], "status not set")
155 assert.Equal(t, ServiceStatusUnknown, p.status["two"], "status set")
156}
157
158func TestRegisterOverwriteStatus(t *testing.T) {
159 p := &Probe{}
Neha Sharma94f16a92020-06-26 04:17:55 +0000160 ctx := context.Background()
161 p.RegisterService(ctx, "one", "two")
162 p.UpdateStatus(ctx, "one", ServiceStatusRunning)
Scott Baker2c1c4822019-10-16 11:02:41 -0700163
164 assert.Equal(t, ServiceStatusRunning, p.status["one"], "status not set")
165 assert.Equal(t, ServiceStatusUnknown, p.status["two"], "status set")
166
Neha Sharma94f16a92020-06-26 04:17:55 +0000167 p.RegisterService(ctx, "one", "three")
Scott Baker2c1c4822019-10-16 11:02:41 -0700168 assert.Equal(t, 3, len(p.status), "wrong number of services")
169 assert.Equal(t, ServiceStatusRunning, p.status["one"], "status overridden")
170 assert.Equal(t, ServiceStatusUnknown, p.status["two"], "status set")
171 assert.Equal(t, ServiceStatusUnknown, p.status["three"], "status set")
172}
173
174func TestDetailzWithServies(t *testing.T) {
175 p := (&Probe{}).WithReadyFunc(AlwaysTrue).WithHealthFunc(AlwaysTrue)
Neha Sharma94f16a92020-06-26 04:17:55 +0000176 p.RegisterService(context.Background(), "one", "two")
Scott Baker2c1c4822019-10-16 11:02:41 -0700177
178 req := httptest.NewRequest("GET", "http://example.com/detailz", nil)
179 w := httptest.NewRecorder()
180 p.detailzFunc(w, req)
181 resp := w.Result()
Akash Reddy Kankanala05aff182025-05-06 12:57:32 +0530182 body, _ := io.ReadAll(resp.Body)
Scott Baker2c1c4822019-10-16 11:02:41 -0700183
184 assert.Equal(t, http.StatusOK, resp.StatusCode, "invalid status code for no services")
185 assert.Equal(t, "application/json", resp.Header.Get("Content-Type"), "wrong content type")
186 var vals map[string]string
187 err := json.Unmarshal(body, &vals)
188 assert.Nil(t, err, "unable to unmarshal values")
189 assert.Equal(t, "Unknown", vals["one"], "wrong value")
190 assert.Equal(t, "Unknown", vals["two"], "wrong value")
191}
192
193func TestReadzNoServices(t *testing.T) {
194 p := (&Probe{}).WithReadyFunc(AlwaysTrue)
195 req := httptest.NewRequest("GET", "http://example.com/readz", nil)
196 w := httptest.NewRecorder()
197 p.readzFunc(w, req)
198 resp := w.Result()
199
200 assert.Equal(t, http.StatusTeapot, resp.StatusCode, "invalid status code for no services")
201}
202
203func TestReadzWithServicesWithTrue(t *testing.T) {
204 p := (&Probe{}).WithReadyFunc(AlwaysTrue).WithHealthFunc(AlwaysTrue)
Neha Sharma94f16a92020-06-26 04:17:55 +0000205 p.RegisterService(context.Background(), "one", "two")
Scott Baker2c1c4822019-10-16 11:02:41 -0700206
207 req := httptest.NewRequest("GET", "http://example.com/readz", nil)
208 w := httptest.NewRecorder()
209 p.readzFunc(w, req)
210 resp := w.Result()
211 assert.Equal(t, http.StatusOK, resp.StatusCode, "invalid status code for registered only services")
212}
213
214func TestReadzWithServicesWithDefault(t *testing.T) {
215 p := &Probe{}
Neha Sharma94f16a92020-06-26 04:17:55 +0000216 p.RegisterService(context.Background(), "one", "two")
Scott Baker2c1c4822019-10-16 11:02:41 -0700217
218 req := httptest.NewRequest("GET", "http://example.com/readz", nil)
219 w := httptest.NewRecorder()
220 p.readzFunc(w, req)
221 resp := w.Result()
222 assert.Equal(t, http.StatusTeapot, resp.StatusCode, "invalid status code for registered only services")
223}
224
225func TestReadzNpServicesDefault(t *testing.T) {
226 p := &Probe{}
227
228 req := httptest.NewRequest("GET", "http://example.com/readz", nil)
229 w := httptest.NewRecorder()
230 p.readzFunc(w, req)
231 resp := w.Result()
232 assert.Equal(t, http.StatusTeapot, resp.StatusCode, "invalid status code")
233}
234
235func TestReadzWithServicesDefault(t *testing.T) {
236 p := &Probe{}
Neha Sharma94f16a92020-06-26 04:17:55 +0000237 ctx := context.Background()
238 p.RegisterService(ctx, "one", "two")
239 p.UpdateStatus(ctx, "one", ServiceStatusRunning)
240 p.UpdateStatus(ctx, "two", ServiceStatusRunning)
Scott Baker2c1c4822019-10-16 11:02:41 -0700241
242 req := httptest.NewRequest("GET", "http://example.com/readz", nil)
243 w := httptest.NewRecorder()
244 p.readzFunc(w, req)
245 resp := w.Result()
246 assert.Equal(t, http.StatusOK, resp.StatusCode, "invalid status code")
247}
248
249func TestReadzWithServicesDefaultOne(t *testing.T) {
250 p := &Probe{}
Neha Sharma94f16a92020-06-26 04:17:55 +0000251 p.RegisterService(context.Background(), "one", "two")
252 p.UpdateStatus(context.Background(), "one", ServiceStatusRunning)
Scott Baker2c1c4822019-10-16 11:02:41 -0700253
254 req := httptest.NewRequest("GET", "http://example.com/readz", nil)
255 w := httptest.NewRecorder()
256 p.readzFunc(w, req)
257 resp := w.Result()
258 assert.Equal(t, http.StatusTeapot, resp.StatusCode, "invalid status code")
259}
260
261func TestHealthzNoServices(t *testing.T) {
262 p := (&Probe{}).WithReadyFunc(AlwaysTrue)
263 req := httptest.NewRequest("GET", "http://example.com/healthz", nil)
264 w := httptest.NewRecorder()
265 p.healthzFunc(w, req)
266 resp := w.Result()
267
268 assert.Equal(t, http.StatusTeapot, resp.StatusCode, "invalid status code for no services")
269}
270
271func TestHealthzWithServicesWithTrue(t *testing.T) {
272 p := (&Probe{}).WithReadyFunc(AlwaysTrue).WithHealthFunc(AlwaysTrue)
Neha Sharma94f16a92020-06-26 04:17:55 +0000273 p.RegisterService(context.Background(), "one", "two")
Scott Baker2c1c4822019-10-16 11:02:41 -0700274
275 req := httptest.NewRequest("GET", "http://example.com/healthz", nil)
276 w := httptest.NewRecorder()
277 p.healthzFunc(w, req)
278 resp := w.Result()
279 assert.Equal(t, http.StatusOK, resp.StatusCode, "invalid status code for registered only services")
280}
281
282func TestHealthzWithServicesWithDefault(t *testing.T) {
283 p := &Probe{}
Neha Sharma94f16a92020-06-26 04:17:55 +0000284 p.RegisterService(context.Background(), "one", "two")
Scott Baker2c1c4822019-10-16 11:02:41 -0700285
286 req := httptest.NewRequest("GET", "http://example.com/healthz", nil)
287 w := httptest.NewRecorder()
288 p.healthzFunc(w, req)
289 resp := w.Result()
290 assert.Equal(t, http.StatusOK, resp.StatusCode, "invalid status code for registered only services")
291}
292
293func TestHealthzNoServicesDefault(t *testing.T) {
294 p := &Probe{}
295
296 req := httptest.NewRequest("GET", "http://example.com/healthz", nil)
297 w := httptest.NewRecorder()
298 p.healthzFunc(w, req)
299 resp := w.Result()
300 assert.Equal(t, http.StatusTeapot, resp.StatusCode, "invalid status code")
301}
302
303func TestHealthzWithServicesDefault(t *testing.T) {
304 p := &Probe{}
Neha Sharma94f16a92020-06-26 04:17:55 +0000305 p.RegisterService(context.Background(), "one", "two")
306 p.UpdateStatus(context.Background(), "one", ServiceStatusRunning)
307 p.UpdateStatus(context.Background(), "two", ServiceStatusRunning)
Scott Baker2c1c4822019-10-16 11:02:41 -0700308
309 req := httptest.NewRequest("GET", "http://example.com/healthz", nil)
310 w := httptest.NewRecorder()
311 p.healthzFunc(w, req)
312 resp := w.Result()
313 assert.Equal(t, http.StatusOK, resp.StatusCode, "invalid status code")
314}
315
316func TestHealthzWithServicesDefaultFailed(t *testing.T) {
317 p := &Probe{}
Neha Sharma94f16a92020-06-26 04:17:55 +0000318 p.RegisterService(context.Background(), "one", "two")
319 p.UpdateStatus(context.Background(), "one", ServiceStatusFailed)
Scott Baker2c1c4822019-10-16 11:02:41 -0700320
321 req := httptest.NewRequest("GET", "http://example.com/healthz", nil)
322 w := httptest.NewRecorder()
323 p.healthzFunc(w, req)
324 resp := w.Result()
325 assert.Equal(t, http.StatusTeapot, resp.StatusCode, "invalid status code")
326}
327
328func TestSetFuncsToNil(t *testing.T) {
329 p := (&Probe{}).WithReadyFunc(AlwaysTrue).WithHealthFunc(AlwaysFalse)
330 p.WithReadyFunc(nil).WithHealthFunc(nil)
331 assert.Nil(t, p.readyFunc, "ready func not reset to nil")
332 assert.Nil(t, p.healthFunc, "health func not reset to nil")
333}
334
Scott Baker104b67d2019-10-29 15:56:27 -0700335func TestGetProbeFromContext(t *testing.T) {
336 p := &Probe{}
Neha Sharma94f16a92020-06-26 04:17:55 +0000337 p.RegisterService(context.Background(), "one")
Scott Baker104b67d2019-10-29 15:56:27 -0700338 ctx := context.WithValue(context.Background(), ProbeContextKey, p)
339 pc := GetProbeFromContext(ctx)
340 assert.Equal(t, p, pc, "Probe from context was not identical to original probe")
341}
342
343func TestGetProbeFromContextMssing(t *testing.T) {
npujar5bf737f2020-01-16 19:35:25 +0530344 ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
345 defer cancel()
Scott Baker104b67d2019-10-29 15:56:27 -0700346 pc := GetProbeFromContext(ctx)
347 assert.Nil(t, pc, "Context had a non-nil probe when it should have been nil")
348}
349
Scott Baker2c1c4822019-10-16 11:02:41 -0700350func TestUpdateStatusFromContext(t *testing.T) {
351 p := &Probe{}
Neha Sharma94f16a92020-06-26 04:17:55 +0000352 p.RegisterService(context.Background(), "one")
Scott Baker2c1c4822019-10-16 11:02:41 -0700353 ctx := context.WithValue(context.Background(), ProbeContextKey, p)
354 UpdateStatusFromContext(ctx, "one", ServiceStatusRunning)
355
356 assert.Equal(t, 1, len(p.status), "wrong number of services")
357 _, ok := p.status["one"]
358 assert.True(t, ok, "unable to find registered service")
359 assert.Equal(t, ServiceStatusRunning, p.status["one"], "status not set correctly from context")
Scott Baker2c1c4822019-10-16 11:02:41 -0700360}
361
362func TestUpdateStatusFromNilContext(t *testing.T) {
363 p := &Probe{}
Neha Sharma94f16a92020-06-26 04:17:55 +0000364 p.RegisterService(context.Background(), "one")
David K. Bainbridge7c75cac2020-02-19 08:53:46 -0800365 // nolint: staticcheck
Scott Baker2c1c4822019-10-16 11:02:41 -0700366 UpdateStatusFromContext(nil, "one", ServiceStatusRunning)
367
368 assert.Equal(t, 1, len(p.status), "wrong number of services")
369 _, ok := p.status["one"]
370 assert.True(t, ok, "unable to find registered service")
371 assert.Equal(t, ServiceStatusUnknown, p.status["one"], "status not set correctly from context")
372
373}
374
375func TestUpdateStatusFromContextWithoutProbe(t *testing.T) {
376 p := &Probe{}
Neha Sharma94f16a92020-06-26 04:17:55 +0000377 p.RegisterService(context.Background(), "one")
npujar5bf737f2020-01-16 19:35:25 +0530378 ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
379 defer cancel()
Scott Baker2c1c4822019-10-16 11:02:41 -0700380 UpdateStatusFromContext(ctx, "one", ServiceStatusRunning)
381
382 assert.Equal(t, 1, len(p.status), "wrong number of services")
383 _, ok := p.status["one"]
384 assert.True(t, ok, "unable to find registered service")
385 assert.Equal(t, ServiceStatusUnknown, p.status["one"], "status not set correctly from context")
386
387}
388
389func TestUpdateStatusFromContextWrongType(t *testing.T) {
390 p := &Probe{}
Neha Sharma94f16a92020-06-26 04:17:55 +0000391 p.RegisterService(context.Background(), "one")
Scott Baker2c1c4822019-10-16 11:02:41 -0700392 ctx := context.WithValue(context.Background(), ProbeContextKey, "Teapot")
393 UpdateStatusFromContext(ctx, "one", ServiceStatusRunning)
394
395 assert.Equal(t, 1, len(p.status), "wrong number of services")
396 _, ok := p.status["one"]
397 assert.True(t, ok, "unable to find registered service")
398 assert.Equal(t, ServiceStatusUnknown, p.status["one"], "status not set correctly from context")
399}
400
401func TestUpdateStatusNoRegistered(t *testing.T) {
402 p := (&Probe{}).WithReadyFunc(AlwaysTrue).WithHealthFunc(AlwaysFalse)
403
Neha Sharma94f16a92020-06-26 04:17:55 +0000404 p.UpdateStatus(context.Background(), "one", ServiceStatusRunning)
Scott Baker2c1c4822019-10-16 11:02:41 -0700405 assert.Equal(t, 1, len(p.status), "wrong number of services")
406 _, ok := p.status["one"]
407 assert.True(t, ok, "unable to find registered service")
408 assert.Equal(t, ServiceStatusRunning, p.status["one"], "status not set correctly from context")
409}
Scott Baker104b67d2019-10-29 15:56:27 -0700410
411func TestIsReadyTrue(t *testing.T) {
412 p := (&Probe{}).WithReadyFunc(AlwaysTrue).WithHealthFunc(AlwaysFalse)
413
Neha Sharma94f16a92020-06-26 04:17:55 +0000414 p.RegisterService(context.Background(), "SomeService")
Scott Baker104b67d2019-10-29 15:56:27 -0700415
416 assert.True(t, p.IsReady(), "IsReady should have been true")
417}
418
419func TestIsReadyFalse(t *testing.T) {
420 p := (&Probe{}).WithReadyFunc(AlwaysFalse).WithHealthFunc(AlwaysFalse)
421
Neha Sharma94f16a92020-06-26 04:17:55 +0000422 p.RegisterService(context.Background(), "SomeService")
Scott Baker104b67d2019-10-29 15:56:27 -0700423
424 assert.False(t, p.IsReady(), "IsReady should have been false")
425}
426
427func TestGetStatus(t *testing.T) {
428 p := &Probe{}
429
Neha Sharma94f16a92020-06-26 04:17:55 +0000430 p.RegisterService(context.Background(), "one", "two")
431 p.UpdateStatus(context.Background(), "one", ServiceStatusRunning)
Scott Baker104b67d2019-10-29 15:56:27 -0700432
433 ss := p.GetStatus("one")
434 assert.Equal(t, ServiceStatusRunning, ss, "Service status should have been ServiceStatusRunning")
435}
436
437func TestGetStatusMissingService(t *testing.T) {
438 p := &Probe{}
439
Neha Sharma94f16a92020-06-26 04:17:55 +0000440 p.RegisterService(context.Background(), "one", "two")
Scott Baker104b67d2019-10-29 15:56:27 -0700441
442 ss := p.GetStatus("three")
443 assert.Equal(t, ServiceStatusUnknown, ss, "Service status should have been ServiceStatusUnknown")
444}