package e2e import ( "encoding/base64" "io" "net/http" "net/http/httptest" "net/url" "os" "path/filepath" "strings" "testing" ) func TestExtendedHealthEndpoints(t *testing.T) { config := `server: host: "127.0.0.1" port: 26660 logging: level: "error" format: "text" ` app, _, cleanup := setupTestApplicationWithConfig(t, config) t.Cleanup(cleanup) server := app.GetHTTPServer() endpoints := []string{"/ready", "/live", "/metrics", "/ping"} for _, ep := range endpoints { ep := ep t.Run(ep, func(t *testing.T) { resp := doRequest(t, server, http.MethodGet, ep) defer resp.Body.Close() if resp.StatusCode != http.StatusOK { t.Fatalf("expected 200 for %s, got %d", ep, resp.StatusCode) } body, err := io.ReadAll(resp.Body) if err != nil { t.Fatalf("failed to read %s response: %v", ep, err) } if len(body) == 0 { t.Fatalf("expected non-empty body for %s", ep) } }) } } func TestVersionPlainTextMode(t *testing.T) { config := `server: host: "127.0.0.1" port: 26670 logging: level: "error" format: "text" ` app, _, cleanup := setupTestApplicationWithConfig(t, config) t.Cleanup(cleanup) server := app.GetHTTPServer() resp := doRequest(t, server, http.MethodGet, "/version?format=plain") defer resp.Body.Close() if resp.StatusCode != http.StatusOK { t.Fatalf("expected 200 for plain version, got %d", resp.StatusCode) } if ct := resp.Header.Get("Content-Type"); ct != "text/plain; charset=utf-8" { t.Fatalf("expected text/plain content type, got %q", ct) } body, err := io.ReadAll(resp.Body) if err != nil { t.Fatalf("failed to read version body: %v", err) } if len(body) == 0 || body[len(body)-1] != '\n' { t.Fatalf("expected newline terminated version string, got %q", string(body)) } } func TestCompatibilityRouteSmoke(t *testing.T) { config := `server: host: "127.0.0.1" port: 26680 logging: level: "error" format: "text" security: access_tokens: - "legacy-token" conversion: cache_timeout: 60 ` app, _, cleanup := setupTestApplicationWithConfig(t, config) t.Cleanup(cleanup) server := app.GetHTTPServer() token := "legacy-token" type routeExpect struct { method string path string status int } localFile := filepath.Join(t.TempDir(), "sample.txt") if err := os.WriteFile(localFile, []byte("content"), 0o644); err != nil { t.Fatalf("failed to write local file: %v", err) } rulesetEncoded := base64.StdEncoding.EncodeToString([]byte("ruleset," + filepath.ToSlash(filepath.Join("rules", "LocalAreaNetwork.list")))) remoteServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) _, _ = w.Write([]byte("ok")) })) defer remoteServer.Close() routes := []routeExpect{ {http.MethodGet, "/sub?target=clash&url=https://mock-subscribe.example.com", http.StatusOK}, {http.MethodGet, "/sub2clashr?sublink=https://mock-subscribe.example.com", http.StatusOK}, {http.MethodGet, "/surge2clash?link=https://mock-subscribe.example.com", http.StatusOK}, {http.MethodGet, "/getruleset?type=1&url=" + url.QueryEscape(rulesetEncoded), http.StatusOK}, {http.MethodGet, "/getprofile?name=" + url.QueryEscape(localFile) + "&token=" + token, http.StatusForbidden}, {http.MethodGet, "/refreshrules?token=" + token, http.StatusOK}, {http.MethodGet, "/readconf?token=" + token, http.StatusOK}, {http.MethodPost, "/updateconf?type=form&token=" + token, http.StatusBadRequest}, {http.MethodGet, "/flushcache?token=" + token, http.StatusOK}, {http.MethodGet, "/get?url=" + url.QueryEscape(remoteServer.URL), http.StatusOK}, {http.MethodGet, "/getlocal?path=" + url.QueryEscape(localFile), http.StatusOK}, } for _, rt := range routes { rt := rt t.Run(rt.path, func(t *testing.T) { var resp *http.Response if rt.method == http.MethodPost { resp = doRequestWithBody(t, server, rt.method, rt.path, strings.NewReader(""), map[string]string{"Content-Type": "text/plain"}) } else { resp = doRequest(t, server, rt.method, rt.path) } defer resp.Body.Close() if resp.StatusCode != rt.status { t.Fatalf("expected status %d for %s %s, got %d", rt.status, rt.method, rt.path, resp.StatusCode) } }) } }