feat(surf): print the serve URL and admin status on startup
- Add surf.Router.AdminPrefix (additive): the admin mount path and true when BuildRouter mounted the cabana admin, false otherwise - serve binds with net.Listen before printing, so a busy port fails without a misleading URL, then prints the listen address with a browser URL and an admin status line: the admin URL, a warning naming summer admin:create when backend_users is empty or missing, or admin: off with the steps to add an admin controller - The administrator count is bounded by a 2 s timeout and never fails boot - route:list ends with the same admin status line - surf and cabana READMEs and the console and routing docs describe the output
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
package surf
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io/fs"
|
||||
"net/http"
|
||||
"os"
|
||||
@@ -10,6 +11,7 @@ import (
|
||||
"testing/fstest"
|
||||
|
||||
"git.golem15.com/golem15/summercms/modules/backpack"
|
||||
"git.golem15.com/golem15/summercms/modules/bonfire"
|
||||
"git.golem15.com/golem15/summercms/modules/compass"
|
||||
"git.golem15.com/golem15/summercms/modules/pact"
|
||||
"git.golem15.com/golem15/summercms/modules/party"
|
||||
@@ -177,3 +179,57 @@ func (p prefixRoutePlugin) Routes(r pact.Router) error {
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
// TestRouterAdminPrefix reports the admin mount path BuildRouter used.
|
||||
func TestRouterAdminPrefix(t *testing.T) {
|
||||
for _, tc := range []struct {
|
||||
name string
|
||||
app *backpack.App
|
||||
plugins []party.Plugin
|
||||
prefix string
|
||||
mounted bool
|
||||
}{
|
||||
{"configured prefix", adminPrefixApp(t), []party.Plugin{adminPrefixPlugin{}}, "/acme-admin", true},
|
||||
{"default prefix", adminPrefixAppWith(t, ""), []party.Plugin{adminPrefixPlugin{}}, "/backend", true},
|
||||
{"no admin controllers", adminPrefixApp(t), []party.Plugin{prefixRoutePlugin{id: "acme.site", method: http.MethodGet, path: "/hello"}}, "", false},
|
||||
} {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
r, err := BuildRouter(tc.app, tc.plugins)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
prefix, mounted := r.AdminPrefix()
|
||||
if prefix != tc.prefix || mounted != tc.mounted {
|
||||
t.Fatalf("AdminPrefix() = (%q, %v), want (%q, %v)", prefix, mounted, tc.prefix, tc.mounted)
|
||||
}
|
||||
})
|
||||
}
|
||||
if prefix, mounted := (*Router)(nil).AdminPrefix(); prefix != "" || mounted {
|
||||
t.Fatalf("nil router AdminPrefix() = (%q, %v)", prefix, mounted)
|
||||
}
|
||||
}
|
||||
|
||||
// TestRouteListAdminStatus ends the route table with the admin status line.
|
||||
func TestRouteListAdminStatus(t *testing.T) {
|
||||
for _, tc := range []struct {
|
||||
name string
|
||||
app *backpack.App
|
||||
plugins []party.Plugin
|
||||
want string
|
||||
}{
|
||||
{"mounted", adminPrefixApp(t), []party.Plugin{adminPrefixPlugin{}}, "admin: mounted at /acme-admin"},
|
||||
{"off", adminPrefixApp(t), []party.Plugin{prefixRoutePlugin{id: "acme.site", method: http.MethodGet, path: "/hello"}}, "admin: off — no plugin registers an admin controller"},
|
||||
} {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
var buf bytes.Buffer
|
||||
out := bonfire.NewOutput(strings.NewReader(""), &buf, &buf)
|
||||
if err := RouteListCommand(tc.app, tc.plugins).Run(t.Context(), nil, out); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
got := strings.TrimRight(buf.String(), "\n")
|
||||
if !strings.HasSuffix(got, tc.want) {
|
||||
t.Fatalf("route:list output does not end with %q:\n%s", tc.want, got)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user