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..1a14be9 100644 --- a/probes.go +++ b/probes.go @@ -35,44 +35,36 @@ 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...) + 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 } func (kp *kubeprobes) handleLiveness(w http.ResponseWriter, _ *http.Request) { @@ -93,13 +85,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/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() 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.