test(router): закрепить пространства имён API тестом регистрации маршрутов
Ошибка в регистрации маршрутов проявляется паникой при старте сервиса, а не ответом с кодом: конфликт с wildcard фронтенда или дублирующая регистрация обнаружились бы только на живом сервере. Смена namespace относится ровно к этому классу изменений.
This commit is contained in:
@@ -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 не зарегистрирован")
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -198,7 +198,21 @@ HYSTERIA_BIN=/usr/local/bin/hysteria ./tools/test/e2e-hysteria.sh
|
|||||||
multicast и reserved диапазоны не считаются публичным адресом сервера, а
|
multicast и reserved диапазоны не считаются публичным адресом сервера, а
|
||||||
`172.32.0.0` и `172.15.255.255` — считаются (границы `172.16/12`).
|
`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`:
|
`apps/service/peer_import_test.go`:
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user