From 373c803c00499a7e607cdd0ad99315dcd6e2919d Mon Sep 17 00:00:00 2001 From: Piotr Icikowski Date: Sat, 2 Mar 2024 15:40:57 +0100 Subject: [PATCH 1/4] refactor(names): refactor handler fetching methods' names --- README.md | 6 +++--- probes.go | 8 ++++---- types.go | 8 ++++---- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 750af72..9d20969 100644 --- a/README.md +++ b/README.md @@ -82,11 +82,11 @@ kp, _ := kubeprobes.New( // ... ) -livenessHandler := kp.GetLivenessHandler() -readinessHandler := kp.GetReadinessHandler() +livenessHandler := kp.LivenessHandler() +readinessHandler := kp.ReadinessHandler() ``` -Those handler can be used for manually mounting them on other servers/routers/muxes (eg. `go-chi/chi`, `gorilla/mux`, `http`'s `ServeMux` etc.). +Those handler can be used for manually mounting them on other servers/routers/muxes (eg. `go-chi/chi`, `gorilla/mux`, `http`'s `ServeMux` etc.). ## Example usage diff --git a/probes.go b/probes.go index e21dd89..ae59b99 100644 --- a/probes.go +++ b/probes.go @@ -93,13 +93,13 @@ func (kp *kubeprobes) handleReadiness(w http.ResponseWriter, _ *http.Request) { } } -// GetLivenessHandler implements Kubeprobes. -func (kp *kubeprobes) GetLivenessHandler() http.Handler { +// LivenessHandler implements Kubeprobes. +func (kp *kubeprobes) LivenessHandler() http.Handler { return http.HandlerFunc(kp.handleLiveness) } -// GetReadinessHandler implements Kubeprobes. -func (kp *kubeprobes) GetReadinessHandler() http.Handler { +// ReadinessHandler implements Kubeprobes. +func (kp *kubeprobes) ReadinessHandler() http.Handler { return http.HandlerFunc(kp.handleReadiness) } diff --git a/types.go b/types.go index c976a1a..cc1c862 100644 --- a/types.go +++ b/types.go @@ -6,10 +6,10 @@ import "net/http" type Kubeprobes interface { http.Handler - // GetLivenessHandler returns [http.Handler] for liveness probes. - GetLivenessHandler() http.Handler - // GetReadinessHandler returns [http.Handler] for readiness probes. - GetReadinessHandler() http.Handler + // LivenessHandler returns [http.Handler] for liveness probes. + LivenessHandler() http.Handler + // ReadinessHandler returns [http.Handler] for readiness probes. + ReadinessHandler() http.Handler } // Option represents a [Kubeprobes] constructor option. -- 2.43.0 From ea92b2979cbdb67507d934725434f21b0456be03 Mon Sep 17 00:00:00 2001 From: Piotr Icikowski Date: Sat, 2 Mar 2024 15:45:00 +0100 Subject: [PATCH 2/4] refactor(validation): improve errors joining --- probes.go | 30 +++++++----------------------- 1 file changed, 7 insertions(+), 23 deletions(-) diff --git a/probes.go b/probes.go index ae59b99..66f4350 100644 --- a/probes.go +++ b/probes.go @@ -35,44 +35,28 @@ func New(options ...Option) (Kubeprobes, error) { } func (kp *kubeprobes) validate() error { - errs := []error{} - + var err error if kp.pathLive == "" { - errs = append( - errs, - fmt.Errorf("liveness probe path must not be empty"), - ) + err = errors.Join(err, fmt.Errorf("liveness probe path must not be empty")) } if kp.pathReady == "" { - errs = append( - errs, - fmt.Errorf("readiness probe path must not be empty"), - ) + err = errors.Join(err, fmt.Errorf("readiness probe path must not be empty")) } if !strings.HasPrefix(kp.pathLive, "/") { - errs = append( - errs, - fmt.Errorf("liveness probe path must start with slash (current: %q)", kp.pathLive), - ) + err = errors.Join(err, fmt.Errorf("liveness probe path must start with slash (current: %q)", kp.pathLive)) } if !strings.HasPrefix(kp.pathReady, "/") { - errs = append( - errs, - fmt.Errorf("readiness probe path must start with slash (current: %q)", kp.pathReady), - ) + err = errors.Join(err, fmt.Errorf("readiness probe path must start with slash (current: %q)", kp.pathReady)) } if kp.pathLive == kp.pathReady { - errs = append( - errs, - fmt.Errorf("liveness and readiness probes have the same values (both %q)", kp.pathLive), - ) + err = errors.Join(err, fmt.Errorf("liveness and readiness probes have the same values (both %q)", kp.pathLive)) } - return errors.Join(errs...) + return err } func (kp *kubeprobes) handleLiveness(w http.ResponseWriter, _ *http.Request) { -- 2.43.0 From 82b6034625089450d3de734edd8eb95ea35aff2f Mon Sep 17 00:00:00 2001 From: Piotr Icikowski Date: Sat, 2 Mar 2024 15:52:01 +0100 Subject: [PATCH 3/4] feat(validation): add empty probe lists validation --- probes.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/probes.go b/probes.go index 66f4350..1a14be9 100644 --- a/probes.go +++ b/probes.go @@ -56,6 +56,14 @@ func (kp *kubeprobes) validate() error { err = errors.Join(err, fmt.Errorf("liveness and readiness probes have the same values (both %q)", kp.pathLive)) } + if len(kp.livenessProbes) == 0 { + err = errors.Join(err, fmt.Errorf("no liveness probes defined")) + } + + if len(kp.readinessProbes) == 0 { + err = errors.Join(err, fmt.Errorf("no readiness probes defined")) + } + return err } -- 2.43.0 From ab8b7e84e28c84af79f53302189bc01efd1f3a30 Mon Sep 17 00:00:00 2001 From: Piotr Icikowski Date: Sat, 2 Mar 2024 16:03:13 +0100 Subject: [PATCH 4/4] tests(validation): add validation tests --- probes_test.go | 100 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 98 insertions(+), 2 deletions(-) diff --git a/probes_test.go b/probes_test.go index 059c288..c614145 100644 --- a/probes_test.go +++ b/probes_test.go @@ -15,7 +15,100 @@ func getStatusFromEndpoint(t *testing.T, client *http.Client, endpoint string) i return resp.StatusCode } -func TestKubeprobes(t *testing.T) { +func TestValidation(t *testing.T) { + var ( + live = NewStatefulProbe() + ready = NewStatefulProbe() + ) + + tests := map[string]struct { + opts []Option + expectedError bool + }{ + "no modifications and no error": { + opts: []Option{ + WithLivenessStatefulProbes(live), + WithReadinessStatefulProbes(ready), + }, + }, + "modifications and no error": { + opts: []Option{ + WithLivenessStatefulProbes(live), + WithReadinessStatefulProbes(ready), + WithLivenessPath("/livez"), + WithReadinessPath("/readyz"), + }, + }, + "missing liveness probes": { + opts: []Option{ + WithReadinessStatefulProbes(ready), + }, + expectedError: true, + }, + "missing readiness probes": { + opts: []Option{ + WithLivenessStatefulProbes(live), + }, + expectedError: true, + }, + "liveness probe path empty": { + opts: []Option{ + WithLivenessStatefulProbes(live), + WithReadinessStatefulProbes(ready), + WithLivenessPath(""), + }, + expectedError: true, + }, + "readiness probe path empty": { + opts: []Option{ + WithLivenessStatefulProbes(live), + WithReadinessStatefulProbes(ready), + WithReadinessPath(""), + }, + expectedError: true, + }, + "liveness probe path does not start with slash": { + opts: []Option{ + WithLivenessStatefulProbes(live), + WithReadinessStatefulProbes(ready), + WithLivenessPath("livez"), + }, + expectedError: true, + }, + "readiness probe path does not start with slash": { + opts: []Option{ + WithLivenessStatefulProbes(live), + WithReadinessStatefulProbes(ready), + WithReadinessPath("readyz"), + }, + expectedError: true, + }, + "liveness and readiness probe paths are equal": { + opts: []Option{ + WithLivenessStatefulProbes(live), + WithReadinessStatefulProbes(ready), + WithLivenessPath("/check"), + WithReadinessPath("/check"), + }, + expectedError: true, + }, + } + + for name, tc := range tests { + name, tc := name, tc + t.Run(name, func(t *testing.T) { + _, err := New(tc.opts...) + switch { + case err == nil && tc.expectedError: + t.Error("expected error, but no error was returned") + case err != nil && !tc.expectedError: + t.Errorf("expected no error but got %v", err) + } + }) + } +} + +func TestHandler(t *testing.T) { live, ready := NewStatefulProbe(), NewStatefulProbe() tests := map[string]struct { @@ -50,10 +143,13 @@ func TestKubeprobes(t *testing.T) { }, } - kp, _ := New( + kp, err := New( WithLivenessStatefulProbes(live), WithReadinessStatefulProbes(ready), ) + if err != nil { + t.Errorf("expected no error, got %v", err) + } srv := httptest.NewServer(kp) defer srv.Close() -- 2.43.0