forked from bots-garden/ori
| ✨ Introduce new feature(s): ACP web client — Go backend (agent, bridge, httpserver, mockagent) + React SPA (Zed-like agent panel), tests, quality gate PASS | 1 | package httpserver_test |
| 2 | ||
| 3 | import ( | |
| 4 | "io" | |
| 5 | "net/http" | |
| 6 | "net/http/httptest" | |
| 7 | "testing" | |
| 8 | "testing/fstest" | |
| 9 | ||
| ✨ Workspace panel, selectors, previews, desktop app, sandbox template, resizable file tree, light/dark theme | 10 | "rickub.com/bots-garden/ori/internal/httpserver" |
| ✨ Introduce new feature(s): ACP web client — Go backend (agent, bridge, httpserver, mockagent) + React SPA (Zed-like agent panel), tests, quality gate PASS | 11 | ) |
| 12 | ||
| 13 | // builtUI mimics a Vite production build. | |
| 14 | var builtUI = fstest.MapFS{ | |
| 15 | "index.html": {Data: []byte("<html>ori</html>")}, | |
| 16 | "assets/app.js": {Data: []byte("console.log('ori')")}, | |
| 17 | "assets/app.css": {Data: []byte("body{}")}, | |
| 18 | "vite.svg": {Data: []byte("<svg/>")}, | |
| 19 | } | |
| 20 | ||
| 21 | func get(t *testing.T, handler http.Handler, path string) *httptest.ResponseRecorder { | |
| 22 | t.Helper() | |
| 23 | rec := httptest.NewRecorder() | |
| 24 | handler.ServeHTTP(rec, httptest.NewRequest(http.MethodGet, path, nil)) | |
| 25 | return rec | |
| 26 | } | |
| 27 | ||
| 28 | func TestHealthz(t *testing.T) { | |
| 29 | rec := get(t, httpserver.Handler(builtUI, nil), "/healthz") | |
| 30 | if rec.Code != http.StatusOK { | |
| 31 | t.Fatalf("GET /healthz status = %d, want 200", rec.Code) | |
| 32 | } | |
| 33 | if body := rec.Body.String(); body != `{"status":"ok"}` { | |
| 34 | t.Errorf("GET /healthz body = %q", body) | |
| 35 | } | |
| 36 | } | |
| 37 | ||
| 38 | func TestServesIndex(t *testing.T) { | |
| 39 | rec := get(t, httpserver.Handler(builtUI, nil), "/") | |
| 40 | if rec.Code != http.StatusOK { | |
| 41 | t.Fatalf("GET / status = %d, want 200", rec.Code) | |
| 42 | } | |
| 43 | if body := rec.Body.String(); body != "<html>ori</html>" { | |
| 44 | t.Errorf("GET / body = %q, want index.html content", body) | |
| 45 | } | |
| 46 | } | |
| 47 | ||
| 48 | func TestServesStaticAsset(t *testing.T) { | |
| 49 | rec := get(t, httpserver.Handler(builtUI, nil), "/assets/app.js") | |
| 50 | if rec.Code != http.StatusOK { | |
| 51 | t.Fatalf("GET /assets/app.js status = %d, want 200", rec.Code) | |
| 52 | } | |
| 53 | if body := rec.Body.String(); body != "console.log('ori')" { | |
| 54 | t.Errorf("GET /assets/app.js body = %q", body) | |
| 55 | } | |
| 56 | } | |
| 57 | ||
| 58 | func TestUnknownPathFallsBackToIndex(t *testing.T) { | |
| 59 | rec := get(t, httpserver.Handler(builtUI, nil), "/some/client/route") | |
| 60 | if rec.Code != http.StatusOK { | |
| 61 | t.Fatalf("GET /some/client/route status = %d, want 200 (SPA fallback)", rec.Code) | |
| 62 | } | |
| 63 | if body := rec.Body.String(); body != "<html>ori</html>" { | |
| 64 | t.Errorf("SPA fallback body = %q, want index.html content", body) | |
| 65 | } | |
| 66 | } | |
| 67 | ||
| 68 | func TestMissingBuildAnswers503(t *testing.T) { | |
| 69 | empty := fstest.MapFS{".gitkeep": {Data: nil}} | |
| 70 | rec := get(t, httpserver.Handler(empty, nil), "/") | |
| 71 | if rec.Code != http.StatusServiceUnavailable { | |
| 72 | t.Fatalf("GET / without a UI build status = %d, want 503", rec.Code) | |
| 73 | } | |
| 74 | } | |
| 75 | ||
| 76 | func TestExtraRouteIsMounted(t *testing.T) { | |
| 77 | extra := map[string]http.Handler{ | |
| 78 | "GET /ws": http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { | |
| 79 | _, _ = io.WriteString(w, "ws-here") | |
| 80 | }), | |
| 81 | } | |
| 82 | rec := get(t, httpserver.Handler(builtUI, extra), "/ws") | |
| 83 | if rec.Code != http.StatusOK || rec.Body.String() != "ws-here" { | |
| 84 | t.Fatalf("GET /ws = %d %q, want 200 \"ws-here\"", rec.Code, rec.Body.String()) | |
| 85 | } | |
| 86 | } |