6a6cd76426
Minimal Go service so platform/portal has something to resolve in local
dev. Stdlib net/http with Go 1.22 enhanced ServeMux (method+path
patterns); no third-party deps yet.
Layout:
cmd/server/main.go entry point with graceful shutdown
internal/config/ env-driven config (APP_ENV, ADDR, KC issuer)
internal/server/ http handlers + request-logging middleware
internal/store/memory.go in-memory tenant store, seeded with acme
migrations/0001_init.up.sql schema for the M4.1 follow-up (unapplied)
Makefile dev/test/build/lint/docker targets
Dockerfile multi-stage distroless build
Endpoints (under :8080 in dev):
GET /healthz
GET /v1/tenants/by-slug/{slug} 200 acme | 404
GET /v1/tenants/{id} 200 by uuid | 404
JWT validation and the real Postgres-backed store land in the M4.1
follow-up PR — keeping this PR strictly to 'boots, replies, tests pass'.
Refs: M4.1 (skeleton)
74 lines
1.6 KiB
Go
74 lines
1.6 KiB
Go
package server
|
|
|
|
import (
|
|
"encoding/json"
|
|
"io"
|
|
"log/slog"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"os"
|
|
"testing"
|
|
|
|
"gitea.meghsakha.com/platform/tenant-registry/internal/config"
|
|
)
|
|
|
|
func newTestServer(t *testing.T) *httptest.Server {
|
|
t.Helper()
|
|
cfg := &config.Config{Env: "dev", Addr: ":0"}
|
|
h := NewRouter(cfg, slog.New(slog.NewTextHandler(os.Stderr, nil)))
|
|
return httptest.NewServer(h)
|
|
}
|
|
|
|
func TestHealthz(t *testing.T) {
|
|
srv := newTestServer(t)
|
|
defer srv.Close()
|
|
|
|
resp, err := http.Get(srv.URL + "/healthz")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer resp.Body.Close()
|
|
if resp.StatusCode != http.StatusOK {
|
|
t.Fatalf("got %d, want 200", resp.StatusCode)
|
|
}
|
|
}
|
|
|
|
func TestTenantBySlug_acme(t *testing.T) {
|
|
srv := newTestServer(t)
|
|
defer srv.Close()
|
|
|
|
resp, err := http.Get(srv.URL + "/v1/tenants/by-slug/acme")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer resp.Body.Close()
|
|
if resp.StatusCode != http.StatusOK {
|
|
body, _ := io.ReadAll(resp.Body)
|
|
t.Fatalf("got %d, want 200; body=%s", resp.StatusCode, body)
|
|
}
|
|
var payload map[string]any
|
|
if err := json.NewDecoder(resp.Body).Decode(&payload); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if payload["slug"] != "acme" {
|
|
t.Fatalf("expected slug=acme, got %v", payload["slug"])
|
|
}
|
|
if payload["status"] != "active" {
|
|
t.Fatalf("expected status=active, got %v", payload["status"])
|
|
}
|
|
}
|
|
|
|
func TestTenantBySlug_unknown(t *testing.T) {
|
|
srv := newTestServer(t)
|
|
defer srv.Close()
|
|
|
|
resp, err := http.Get(srv.URL + "/v1/tenants/by-slug/nope")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer resp.Body.Close()
|
|
if resp.StatusCode != http.StatusNotFound {
|
|
t.Fatalf("got %d, want 404", resp.StatusCode)
|
|
}
|
|
}
|