mirror of
https://github.com/hanzoai/gateway.git
synced 2026-10-30 15:04:44 +00:00
Closes the two PARTIAL/TODO lines that docs/SCALE_AUDIT.md flagged after HIP-0110 landed: 1. router_engine.go — replace the TODO KMS stub in loadRoutesFromEnv with a pluggable KMSResolver interface (router_kms.go). The default resolver is a noop; an HTTP resolver auto-wires when GATEWAY_KMS_ENDPOINT + IAM_CLIENT_ID/SECRET (or the GATEWAY_KMS_* overrides) are present. The HTTP contract matches the one in hanzoai/base/plugins/platform/kms.go: Universal-Auth login, then GET /api/v3/secrets/raw/<path>, read .secret.secretValue. File loader path (GATEWAY_ROUTES_FILE → ./routes.yaml) is unchanged and remains the fallback when GATEWAY_ROUTES_KMS_PATH is unset. 2. cmd/gateway/main.go — make the existing 30s shutdown deadline operator-configurable via GATEWAY_SHUTDOWN_TIMEOUT (any time.ParseDuration string; falls back to default on empty / malformed / non-positive values). Surgical change: signal handling and the ShutdownWithContext drain that HIP-0110 introduced are untouched. Tests: - router_engine_kms_test.go — resolver injection, error surfacing, malformed-YAML guard, file fallback, HTTP round-trip stub (mimics the Universal-Auth + secrets/raw contract). - cmd/gateway/main_test.go — shutdownGraceFromEnv table test + envOr smoke test. SIGTERM-triggered drain itself is exercised by deployment smoke tests (not safe to interrupt the in-process Go test runner with SIGTERM). SCALE_AUDIT.md: graceful-shutdown row PARTIAL → PASS, new KMS routes row added (PASS), with a post-HIP-0110 update section. Verification: - go vet ./... clean - go build ./... clean - go test . -count=1 -short: 96/98 PASS (two pre-existing failures in config_loader_test.go::TestPortFromEnv* are unrelated to this change, repro on master) - go test ./cmd/gateway/ -count=1 -short: 2/2 PASS
67 lines
1.8 KiB
Go
67 lines
1.8 KiB
Go
// Copyright © 2026 Hanzo AI. MIT License.
|
|
|
|
package main
|
|
|
|
import (
|
|
"os"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
// TestShutdownGraceFromEnv verifies the GATEWAY_SHUTDOWN_TIMEOUT parsing
|
|
// helper. The full SIGTERM-triggered drain path is exercised by deployment
|
|
// smoke tests (not safe to interrupt the in-process Go test runner with
|
|
// SIGTERM), so this isolated unit test guarantees the helper's contract:
|
|
// env-driven override + safe fallback on malformed/zero/negative values.
|
|
func TestShutdownGraceFromEnv(t *testing.T) {
|
|
def := 30 * time.Second
|
|
cases := []struct {
|
|
name string
|
|
env string
|
|
want time.Duration
|
|
}{
|
|
{"unset", "", def},
|
|
{"valid_seconds", "45s", 45 * time.Second},
|
|
{"valid_minutes", "2m", 2 * time.Minute},
|
|
{"malformed", "not-a-duration", def},
|
|
{"zero_rejected", "0s", def},
|
|
{"negative_rejected", "-5s", def},
|
|
}
|
|
for _, tc := range cases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
prev, hadPrev := os.LookupEnv("GATEWAY_SHUTDOWN_TIMEOUT")
|
|
t.Cleanup(func() {
|
|
if hadPrev {
|
|
os.Setenv("GATEWAY_SHUTDOWN_TIMEOUT", prev)
|
|
} else {
|
|
os.Unsetenv("GATEWAY_SHUTDOWN_TIMEOUT")
|
|
}
|
|
})
|
|
if tc.env == "" {
|
|
os.Unsetenv("GATEWAY_SHUTDOWN_TIMEOUT")
|
|
} else {
|
|
os.Setenv("GATEWAY_SHUTDOWN_TIMEOUT", tc.env)
|
|
}
|
|
got := shutdownGraceFromEnv(def)
|
|
if got != tc.want {
|
|
t.Fatalf("env=%q: want %v got %v", tc.env, tc.want, got)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// TestEnvOr smoke-tests the envOr helper since the file is otherwise
|
|
// shutdown-focused and a green build benefits from a second covered helper.
|
|
func TestEnvOr(t *testing.T) {
|
|
const key = "GATEWAY_TEST_ENV_OR_UNIQUE"
|
|
os.Unsetenv(key)
|
|
if got := envOr(key, "fallback"); got != "fallback" {
|
|
t.Fatalf("unset: want fallback, got %q", got)
|
|
}
|
|
os.Setenv(key, "set")
|
|
t.Cleanup(func() { os.Unsetenv(key) })
|
|
if got := envOr(key, "fallback"); got != "set" {
|
|
t.Fatalf("set: want set, got %q", got)
|
|
}
|
|
}
|