diff --git a/apps/router/router_test.go b/apps/router/router_test.go new file mode 100644 index 0000000..02993b6 --- /dev/null +++ b/apps/router/router_test.go @@ -0,0 +1,107 @@ +package router + +import ( + "strings" + "testing" + + "github.com/gin-gonic/gin" + "hy2xs-admin/model/constant" +) + +// Регистрация маршрутов — единственное место, где ошибка проявляется паникой +// при старте сервиса, а не ответом с кодом. Смена пространства имён API как +// раз относится к таким изменениям: конфликт с wildcard-маршрутом фронтенда +// или дублирующая регистрация обнаружились бы только на живом сервере. +func buildRoutes(t *testing.T) gin.RoutesInfo { + t.Helper() + gin.SetMode(gin.TestMode) + + engine := gin.New() + defer func() { + if r := recover(); r != nil { + t.Fatalf("сборка маршрутов паникует: %v", r) + } + }() + Router(engine) + return engine.Routes() +} + +func TestRouterRegistersMachineAuthUnderInternalNamespace(t *testing.T) { + routes := buildRoutes(t) + + found := false + for _, route := range routes { + if route.Method == "POST" && route.Path == constant.HysteriaMachineAuthPath { + found = true + } + } + if !found { + t.Fatalf("machine-auth endpoint не зарегистрирован на %s", constant.HysteriaMachineAuthPath) + } +} + +func TestRouterKeepsAdminAndAuthUnderApiNamespace(t *testing.T) { + routes := buildRoutes(t) + + expected := []string{ + constant.AdminAPIBase + "/auth/login", + constant.AdminAPIBase + "/peers", + constant.AdminAPIBase + "/config/listConfig", + constant.AdminAPIBase + "/peer-import", + constant.AdminAPIBase + "/peer-export", + } + present := make(map[string]bool, len(routes)) + for _, route := range routes { + present[route.Path] = true + } + for _, path := range expected { + if !present[path] { + t.Errorf("маршрут %s не зарегистрирован", path) + } + } +} + +// Старое пространство имён — часть runtime-контракта, а не внутреннее имя: +// его возвращение сломало бы конфиг Hysteria на уже установленных серверах. +func TestRouterHasNoLegacyNamespace(t *testing.T) { + for _, route := range buildRoutes(t) { + if strings.HasPrefix(route.Path, "/hui") { + t.Errorf("вернулось legacy-пространство имён: %s %s", route.Method, route.Path) + } + } +} + +// Маршруты, операциями которых продукт не владеет, удалены, а не оставлены +// отвечающими «feature disabled». +func TestRouterHasNoRemovedRoutes(t *testing.T) { + removed := []string{ + "exportConfig", + "importConfig", + "updateHysteria2Config", + "importHysteria2Config", + "hysteria2ChangeVersion", + "listRelease", + "restartServer", + "uploadCertFile", + "hysteria2AcmePath", + } + for _, route := range buildRoutes(t) { + for _, dead := range removed { + if strings.Contains(route.Path, dead) { + t.Errorf("удалённый маршрут вернулся: %s %s", route.Method, route.Path) + } + } + } +} + +func TestRouterExposesHealthz(t *testing.T) { + found := false + for _, route := range buildRoutes(t) { + if route.Method == "GET" && route.Path == "/healthz" { + found = true + } + } + if !found { + t.Fatal("/healthz не зарегистрирован") + } +} diff --git a/docs/11-testing-and-acceptance.md b/docs/11-testing-and-acceptance.md index 4519441..f5a1738 100644 --- a/docs/11-testing-and-acceptance.md +++ b/docs/11-testing-and-acceptance.md @@ -198,7 +198,21 @@ HYSTERIA_BIN=/usr/local/bin/hysteria ./tools/test/e2e-hysteria.sh multicast и reserved диапазоны не считаются публичным адресом сервера, а `172.32.0.0` и `172.15.255.255` — считаются (границы `172.16/12`). -## A9. Импорт пиров (unit) +## A9. Регистрация маршрутов (unit) + +`apps/router/router_test.go` — единственное место, где ошибка проявляется +**паникой при старте сервиса**, а не ответом с кодом. Конфликт с +wildcard-маршрутом фронтенда или дублирующая регистрация обнаружились бы иначе +только на живом сервере. + +- контур маршрутов собирается без паники; +- machine-auth зарегистрирован ровно на `constant.HysteriaMachineAuthPath`; +- операторский и auth API — под `constant.AdminAPIBase`; +- ни один маршрут не начинается со старого пространства имён; +- удалённые маршруты (включая `exportConfig`/`importConfig`) не вернулись; +- `/healthz` на месте. + +## A10. Импорт пиров (unit) `apps/service/peer_import_test.go`: