mirror of
https://github.com/go-admin-team/go-admin.git
synced 2026-09-21 02:04:09 +00:00
The warning on Authorizator matters to anyone keeping a copy of that file, not to one particular consumer, and it reads better addressed to all of them: check what reads those context keys before taking this change.
117 lines
4.1 KiB
Go
117 lines
4.1 KiB
Go
package api
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/go-admin-team/go-admin-core/v2/sdk"
|
|
"github.com/go-admin-team/go-admin-core/v2/sdk/runtime"
|
|
)
|
|
|
|
// freshRuntime hands the test its own Runtime and puts the old one back.
|
|
//
|
|
// Both registries close permanently the first time they are run, and
|
|
// sdk.Runtime is a process-wide singleton, so a test that runs the startup
|
|
// hooks would otherwise leave every later test in this binary registering into
|
|
// a closed registry - which is only an ERROR log, not a failure. The symptom
|
|
// is a test that passes alone and loses its routes when run with the others.
|
|
func freshRuntime(t *testing.T) {
|
|
t.Helper()
|
|
previous := sdk.Runtime
|
|
t.Cleanup(func() { sdk.Runtime = previous })
|
|
sdk.Runtime = runtime.NewConfig()
|
|
}
|
|
|
|
// Acceptance 1 and 2 together: the package-level slice a fork appends to and
|
|
// the core registry a module registers through both run, package-level first,
|
|
// registration order preserved inside each.
|
|
//
|
|
// The order matters beyond neatness. A module that appends to AppRouters has to
|
|
// import go-admin/cmd/api, which is why every module used to need a seven-line
|
|
// file in the command package; SetAppRouters is the way out of that. Running
|
|
// the old registry first is what makes the change invisible to anyone who never
|
|
// takes it.
|
|
func TestRunStartupHooksRunsBothRegistriesInOrder(t *testing.T) {
|
|
freshRuntime(t)
|
|
|
|
savedPackage := AppRouters
|
|
t.Cleanup(func() { AppRouters = savedPackage })
|
|
|
|
var order []string
|
|
AppRouters = []func(){
|
|
func() { order = append(order, "package-1") },
|
|
func() { order = append(order, "package-2") },
|
|
}
|
|
sdk.Runtime.SetAppRouters(func() { order = append(order, "runtime-1") })
|
|
sdk.Runtime.SetAppRouters(func() { order = append(order, "runtime-2") })
|
|
|
|
runStartupHooks()
|
|
|
|
const want = "package-1,package-2,runtime-1,runtime-2"
|
|
if got := strings.Join(order, ","); got != want {
|
|
t.Errorf("ran %q, want %q", got, want)
|
|
}
|
|
}
|
|
|
|
// Acceptance 17: a before callback registered through core actually runs.
|
|
//
|
|
// It did not, ever: core stored the callbacks and nothing executed them, so
|
|
// SetBefore was accepted and silently did nothing. The gap survived because
|
|
// core offered the registry without ever running it, leaving each consumer to
|
|
// write - or forget - its own loop.
|
|
func TestBeforeCallbacksRun(t *testing.T) {
|
|
freshRuntime(t)
|
|
|
|
savedPackage := AppRouters
|
|
t.Cleanup(func() { AppRouters = savedPackage })
|
|
AppRouters = nil
|
|
|
|
var order []string
|
|
sdk.Runtime.SetBefore(func() { order = append(order, "before-1") })
|
|
sdk.Runtime.SetBefore(func() { order = append(order, "before-2") })
|
|
sdk.Runtime.SetAppRouters(func() { order = append(order, "router") })
|
|
|
|
runStartupHooks()
|
|
|
|
// Routers first, then before: both happen ahead of ListenAndServe, and a
|
|
// router callback is what puts the engine in place for anything that comes
|
|
// after it.
|
|
const want = "router,before-1,before-2"
|
|
if got := strings.Join(order, ","); got != want {
|
|
t.Errorf("ran %q, want %q", got, want)
|
|
}
|
|
}
|
|
|
|
// A panicking module must not take the server down with it. The guard lives in
|
|
// core; this asserts that go-admin actually goes through it rather than around
|
|
// it with a loop of its own.
|
|
func TestAPanickingRouterDoesNotStopStartup(t *testing.T) {
|
|
freshRuntime(t)
|
|
|
|
savedPackage := AppRouters
|
|
t.Cleanup(func() { AppRouters = savedPackage })
|
|
AppRouters = nil
|
|
|
|
var order []string
|
|
sdk.Runtime.SetAppRouters(func() { order = append(order, "first") })
|
|
sdk.Runtime.SetAppRouters(func() { panic("a third-party module blew up") })
|
|
sdk.Runtime.SetAppRouters(func() { order = append(order, "third") })
|
|
sdk.Runtime.SetBefore(func() { order = append(order, "before") })
|
|
|
|
runStartupHooks()
|
|
|
|
const want = "first,third,before"
|
|
if got := strings.Join(order, ","); got != want {
|
|
t.Errorf("ran %q, want %q", got, want)
|
|
}
|
|
}
|
|
|
|
// The default AppRouters must keep the admin routes on it. Emptying the slice
|
|
// would not fail to compile anywhere - it would just serve a server with no
|
|
// admin API and no error.
|
|
func TestAdminRouterIsRegisteredOnThePackageSlice(t *testing.T) {
|
|
if len(AppRouters) == 0 {
|
|
t.Fatal("AppRouters is empty; the admin router is registered in init()")
|
|
}
|
|
}
|