Add health package: REST and gRPC health checks
- Handler(db) returns http.HandlerFunc: 200 ok / 503 unhealthy - RegisterGRPC registers grpc.health.v1.Health on a gRPC server - 4 tests: healthy, unhealthy (closed db), content type, gRPC registration Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
97
health/health_test.go
Normal file
97
health/health_test.go
Normal file
@@ -0,0 +1,97 @@
|
||||
package health
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"google.golang.org/grpc"
|
||||
|
||||
"git.wntrmute.dev/kyle/mcdsl/db"
|
||||
)
|
||||
|
||||
func TestHandlerHealthy(t *testing.T) {
|
||||
database := openTestDB(t)
|
||||
|
||||
handler := Handler(database)
|
||||
rec := httptest.NewRecorder()
|
||||
req := httptest.NewRequest(http.MethodGet, "/healthz", nil)
|
||||
handler.ServeHTTP(rec, req)
|
||||
|
||||
if rec.Code != http.StatusOK {
|
||||
t.Fatalf("status = %d, want %d", rec.Code, http.StatusOK)
|
||||
}
|
||||
|
||||
var body map[string]string
|
||||
if err := json.Unmarshal(rec.Body.Bytes(), &body); err != nil {
|
||||
t.Fatalf("decode: %v", err)
|
||||
}
|
||||
if body["status"] != "ok" {
|
||||
t.Fatalf("status = %q, want %q", body["status"], "ok")
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandlerUnhealthy(t *testing.T) {
|
||||
database := openTestDB(t)
|
||||
// Close the database to simulate unhealthy state.
|
||||
_ = database.Close()
|
||||
|
||||
handler := Handler(database)
|
||||
rec := httptest.NewRecorder()
|
||||
req := httptest.NewRequest(http.MethodGet, "/healthz", nil)
|
||||
handler.ServeHTTP(rec, req)
|
||||
|
||||
if rec.Code != http.StatusServiceUnavailable {
|
||||
t.Fatalf("status = %d, want %d", rec.Code, http.StatusServiceUnavailable)
|
||||
}
|
||||
|
||||
var body map[string]string
|
||||
if err := json.Unmarshal(rec.Body.Bytes(), &body); err != nil {
|
||||
t.Fatalf("decode: %v", err)
|
||||
}
|
||||
if body["status"] != "unhealthy" {
|
||||
t.Fatalf("status = %q, want %q", body["status"], "unhealthy")
|
||||
}
|
||||
if body["error"] == "" {
|
||||
t.Fatal("expected error message")
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandlerContentType(t *testing.T) {
|
||||
database := openTestDB(t)
|
||||
|
||||
handler := Handler(database)
|
||||
rec := httptest.NewRecorder()
|
||||
req := httptest.NewRequest(http.MethodGet, "/healthz", nil)
|
||||
handler.ServeHTTP(rec, req)
|
||||
|
||||
if ct := rec.Header().Get("Content-Type"); ct != "application/json" {
|
||||
t.Fatalf("Content-Type = %q, want %q", ct, "application/json")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRegisterGRPC(t *testing.T) {
|
||||
srv := grpc.NewServer()
|
||||
// Should not panic.
|
||||
RegisterGRPC(srv)
|
||||
|
||||
info := srv.GetServiceInfo()
|
||||
if _, ok := info["grpc.health.v1.Health"]; !ok {
|
||||
t.Fatal("health service not registered")
|
||||
}
|
||||
}
|
||||
|
||||
func openTestDB(t *testing.T) *sql.DB {
|
||||
t.Helper()
|
||||
dir := t.TempDir()
|
||||
path := filepath.Join(dir, "test.db")
|
||||
database, err := db.Open(path)
|
||||
if err != nil {
|
||||
t.Fatalf("db.Open: %v", err)
|
||||
}
|
||||
t.Cleanup(func() { _ = database.Close() })
|
||||
return database
|
||||
}
|
||||
Reference in New Issue
Block a user