Route templates: a route named x-* serves any request route x-<something>
Implemented-By: OpenCode session (model recorded in docs/implementer-log.md)
This commit is contained in:
@@ -173,7 +173,9 @@ func (hx *handler) routesGet(w http.ResponseWriter, r *http.Request) {
|
||||
func (hx *handler) routeView(route string, hosts []string, defaultModel string, snap []lease.Lease) RouteView {
|
||||
leases := make([]LeaseView, 0)
|
||||
for _, l := range snap {
|
||||
if l.Route == route {
|
||||
// A concrete route lists under the exact key it matches, or the longest
|
||||
// template that matches it; a template's row is every such lease.
|
||||
if _, key, ok := hx.cfg.Route(l.Route); ok && key == route {
|
||||
leases = append(leases, leaseView(l))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ func (hx *handler) routePin(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
route := r.PathValue("route")
|
||||
routeCfg, ok := hx.cfg.Routes[route]
|
||||
routeCfg, _, ok := hx.cfg.Route(route)
|
||||
if !ok {
|
||||
writeError(w, http.StatusNotFound, "unknown route")
|
||||
return
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
package admin_test
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"git.wntrmute.dev/kyle/crossbar/internal/admin"
|
||||
"git.wntrmute.dev/kyle/crossbar/internal/config"
|
||||
"git.wntrmute.dev/kyle/crossbar/internal/health"
|
||||
"git.wntrmute.dev/kyle/crossbar/internal/lease"
|
||||
"git.wntrmute.dev/kyle/crossbar/internal/limiter"
|
||||
"git.wntrmute.dev/kyle/crossbar/internal/store"
|
||||
)
|
||||
|
||||
// The routes view lists a template once, under its own name, with the leases of every concrete
|
||||
// route it matched. A concrete route can be pinned; the template itself cannot.
|
||||
func TestRoutesViewAndPinWithTemplates(t *testing.T) {
|
||||
cfg, err := config.Parse(strings.NewReader(`
|
||||
listen = "127.0.0.1:1"
|
||||
[hosts.alpha]
|
||||
base_url = "http://alpha:1"
|
||||
models = { "m" = { parallel = 2 } }
|
||||
[routes."opencode-*"]
|
||||
hosts = ["alpha"]
|
||||
default_model = "m"
|
||||
`))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
st, err := store.Open(filepath.Join(t.TempDir(), "x.db"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Cleanup(func() { _ = st.Close() })
|
||||
hosts := &fakeHosts{
|
||||
st: map[string]health.Status{"alpha": {Healthy: true, Loaded: []string{"m"}}},
|
||||
draining: map[string]bool{},
|
||||
}
|
||||
lt, err := lease.New(st, hosts, hosts, 30*time.Minute)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, _, err := lt.Acquire(lease.Key{Route: "opencode-projecta-4242", FP: "fp1", Model: "m"}, []string{"alpha"}, time.Now()); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, _, err := lt.Acquire(lease.Key{Route: "opencode-projectb-7", FP: "fp2", Model: "m"}, []string{"alpha"}, time.Now()); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
lim := limiter.New()
|
||||
lim.Configure("alpha", "m", 2, 8)
|
||||
r := &rig{h: admin.Handler(cfg, hosts, lt, lim, st, hosts), store: st, leases: lt, hosts: hosts}
|
||||
|
||||
rec := r.do(t, "GET", "/_crossbar/routes", "")
|
||||
if rec.Code != 200 {
|
||||
t.Fatalf("%d %s", rec.Code, rec.Body.String())
|
||||
}
|
||||
var out map[string]admin.RouteView
|
||||
if err := json.Unmarshal(rec.Body.Bytes(), &out); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
v, ok := out["opencode-*"]
|
||||
if !ok || len(out) != 1 {
|
||||
t.Fatalf("routes view keys = %v, want exactly the template", keysOf(out))
|
||||
}
|
||||
if len(v.Hosts) != 1 || v.Hosts[0] != "alpha" || v.DefaultModel != "m" || len(v.Leases) != 2 {
|
||||
t.Errorf("template view = %+v, want hosts [alpha], model m and the two concrete routes' leases", v)
|
||||
}
|
||||
|
||||
rec = r.do(t, "POST", "/_crossbar/routes/opencode-projecta-4242", `{"host":"alpha","pin":true}`)
|
||||
if rec.Code != 200 {
|
||||
t.Errorf("pin of a concrete templated route: %d %s, want 200", rec.Code, rec.Body.String())
|
||||
}
|
||||
rec = r.do(t, "POST", "/_crossbar/routes/opencode-*", `{"host":"alpha","pin":true}`)
|
||||
if rec.Code != 404 {
|
||||
t.Errorf("pin of the template itself: %d, want 404 unknown route", rec.Code)
|
||||
}
|
||||
rec = r.do(t, "POST", "/_crossbar/routes/opencode-nothing-yet", `{"host":"alpha","pin":true}`)
|
||||
if rec.Code != 200 {
|
||||
t.Errorf("pin of a not-yet-seen concrete route under a template: %d %s, want 200 (it is a valid route)", rec.Code, rec.Body.String())
|
||||
}
|
||||
}
|
||||
|
||||
func keysOf(m map[string]admin.RouteView) []string {
|
||||
out := make([]string, 0, len(m))
|
||||
for k := range m {
|
||||
out = append(out, k)
|
||||
}
|
||||
return out
|
||||
}
|
||||
Reference in New Issue
Block a user