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 не зарегистрирован") } }