package allocator import ( "net/http" "net/http/httptest" "testing" "time" ) func TestHealthRequiresRecentSuccessfulCycle(t *testing.T) { health := &Health{} now := time.Unix(1000, 0) if health.Ready(now, 30*time.Second) { t.Fatal("allocator was ready before a successful cycle") } health.ObserveSuccessfulCycle(now) if !health.Ready(now.Add(30*time.Second), 30*time.Second) { t.Fatal("allocator was not ready at the staleness boundary") } if health.Ready(now.Add(30*time.Second+time.Nanosecond), 30*time.Second) { t.Fatal("stale allocator remained ready") } if health.Ready(now.Add(-time.Second), 30*time.Second) { t.Fatal("clock reversal was accepted as ready") } } func TestRoleHandlerSeparatesLivenessReadinessAndMetrics(t *testing.T) { health := &Health{} now := time.Unix(1000, 0) handler := RoleHandler(NewMetrics(), health, 30*time.Second, func() time.Time { return now }) status := func(method, path string) int { recorder := httptest.NewRecorder() handler.ServeHTTP(recorder, httptest.NewRequest(method, path, nil)) return recorder.Code } if got := status(http.MethodGet, "/healthz"); got != http.StatusOK { t.Fatalf("liveness status = %d", got) } if got := status(http.MethodGet, "/readyz"); got != http.StatusServiceUnavailable { t.Fatalf("startup readiness status = %d", got) } health.ObserveSuccessfulCycle(now) if got := status(http.MethodGet, "/readyz"); got != http.StatusOK { t.Fatalf("successful-cycle readiness status = %d", got) } if got := status(http.MethodGet, "/metrics"); got != http.StatusOK { t.Fatalf("metrics status = %d", got) } if got := status(http.MethodPost, "/readyz"); got != http.StatusMethodNotAllowed { t.Fatalf("readiness mutation status = %d", got) } }