diff --git a/grpchealth.go b/grpchealth.go index bc582db..a6254ed 100644 --- a/grpchealth.go +++ b/grpchealth.go @@ -55,6 +55,20 @@ const ( StatusNotServing Status = 2 ) +// String representation of the status. +func (s Status) String() string { + switch s { + case StatusUnknown: + return "unknown" + case StatusServing: + return "serving" + case StatusNotServing: + return "not_serving" + } + + return fmt.Sprintf("status_%d", s) +} + // NewHandler wraps the supplied Checker to build an HTTP handler for gRPC's // health-checking API. It returns the path on which to mount the handler and // the HTTP handler itself. diff --git a/grpchealth_test.go b/grpchealth_test.go index 8133b49..d36db55 100644 --- a/grpchealth_test.go +++ b/grpchealth_test.go @@ -19,12 +19,39 @@ import ( "errors" "net/http" "net/http/httptest" + "strings" "testing" + "testing/quick" "connectrpc.com/connect" healthv1 "connectrpc.com/grpchealth/internal/gen/go/connectext/grpc/health/v1" ) +func TestCode(t *testing.T) { + t.Parallel() + + knownStatuses := map[Status]struct{}{ + StatusUnknown: {}, + StatusServing: {}, + StatusNotServing: {}, + } + check := func(s Status) bool { + got := s.String() + _, known := knownStatuses[s] + return known != strings.HasPrefix(got, "status_") + } + // always check named statuses + for status := range knownStatuses { + if !check(status) { + t.Fatalf("expected string representation of %q to be customized", status) + } + } + // probabilistically explore other statuses + if err := quick.Check(check, nil /* config */); err != nil { + t.Fatal(err) + } +} + func TestHealth(t *testing.T) { const ( userFQN = "acme.user.v1.UserService"