Files
langship.sh/pkg/orchestrator/admin_test.go
T

140 lines
4.0 KiB
Go
Raw Normal View History

package orchestrator
import (
"context"
"encoding/json"
"net/http"
"net/http/httptest"
"sync/atomic"
"testing"
"time"
)
func TestHealthCheckRestate_okWhen200(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.URL.Path != "/restate/health" {
t.Errorf("path: %s", r.URL.Path)
}
w.WriteHeader(http.StatusOK)
}))
defer srv.Close()
if err := HealthCheckRestate(srv.URL); err != nil {
t.Fatalf("expected nil, got %v", err)
}
}
func TestHealthCheckRestate_failsOnNon2xx(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(http.StatusServiceUnavailable)
}))
defer srv.Close()
if err := HealthCheckRestate(srv.URL); err == nil {
t.Fatal("expected error on 503")
}
}
func TestHealthCheckRestate_failsWhenUnreachable(t *testing.T) {
if err := HealthCheckRestate("http://127.0.0.1:1"); err == nil {
t.Fatal("expected unreachable error")
}
}
func TestRegisterDeployment_postsExpectedBody(t *testing.T) {
var seen struct {
path string
body []byte
contentType string
}
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
seen.path = r.URL.Path
seen.contentType = r.Header.Get("Content-Type")
buf := make([]byte, 256)
n, _ := r.Body.Read(buf)
seen.body = buf[:n]
w.WriteHeader(http.StatusCreated)
}))
defer srv.Close()
if err := RegisterDeployment(context.Background(), srv.URL, "http://flow:9080"); err != nil {
t.Fatalf("unexpected: %v", err)
}
if seen.path != "/deployments" {
t.Errorf("path: %q", seen.path)
}
if seen.contentType != "application/json" {
t.Errorf("content-type: %q", seen.contentType)
}
var body map[string]any
if err := json.Unmarshal(seen.body, &body); err != nil {
t.Fatalf("body json: %v", err)
}
if body["uri"] != "http://flow:9080" || body["force"] != true {
t.Errorf("body: %+v", body)
}
}
func TestRegisterDeployment_returnsErrorOn5xx(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(http.StatusInternalServerError)
_, _ = w.Write([]byte("oops"))
}))
defer srv.Close()
if err := RegisterDeployment(context.Background(), srv.URL, "http://flow:9080"); err == nil {
t.Fatal("expected error")
}
}
func TestRegisterDeploymentWithRetry_succeedsAfterFailures(t *testing.T) {
var attempts int32
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
n := atomic.AddInt32(&attempts, 1)
if n < 3 {
w.WriteHeader(http.StatusInternalServerError)
return
}
w.WriteHeader(http.StatusCreated)
}))
defer srv.Close()
if err := RegisterDeploymentWithRetry(context.Background(), srv.URL, "http://flow:9080", 5, 5*time.Millisecond); err != nil {
t.Fatalf("expected success after retries, got %v", err)
}
if atomic.LoadInt32(&attempts) != 3 {
t.Fatalf("expected 3 attempts, got %d", attempts)
}
}
func TestRegisterDeploymentWithRetry_givesUpAfterMaxAttempts(t *testing.T) {
var attempts int32
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
atomic.AddInt32(&attempts, 1)
w.WriteHeader(http.StatusInternalServerError)
}))
defer srv.Close()
err := RegisterDeploymentWithRetry(context.Background(), srv.URL, "http://flow:9080", 3, 1*time.Millisecond)
if err == nil {
t.Fatal("expected failure")
}
if got := atomic.LoadInt32(&attempts); got != 3 {
t.Fatalf("attempts: got %d, want 3", got)
}
}
func TestRegisterDeploymentWithRetry_respectsContextCancel(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(http.StatusInternalServerError)
}))
defer srv.Close()
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Millisecond)
defer cancel()
if err := RegisterDeploymentWithRetry(ctx, srv.URL, "http://flow:9080", 100, 50*time.Millisecond); err == nil {
t.Fatal("expected error from cancelled context")
}
}