sub2api/backend/internal/pkg/windsurf/discovery_test.go
win 898a65314c
Some checks failed
CI / test (push) Failing after 3s
CI / frontend (push) Failing after 4s
CI / golangci-lint (push) Failing after 6s
CI / windsurf-platform (macos-latest) (push) Has been cancelled
CI / windsurf-platform (windows-latest) (push) Has been cancelled
Security Scan / backend-security (push) Failing after 3s
Security Scan / frontend-security (push) Failing after 3s
chore: 删除 Antigravity 订制代码,回退至上游 v0.1.118
- 删除自定义文件:gateway_attribution, gateway_claude_runtime_headers,
  identity_service_antigravity, language_server_service, lsrpc_handler,
  antigravity_http handler/routes, 所有 antigravity 专项测试
- 将 antigravity pkg/service 文件回退至上游版本(移除 IsEnterprise、
  claude_code_tool_map、dynamic fingerprint 等定制逻辑)
- 修复 gateway_service.go:移除 NormalizeSystemPromptEnv、
  generateSessionIDForAccount、applyClaudeRuntimeOptionalHeaders 调用,
  使用上游的 session-id 同步逻辑
- 恢复 language_server_pb gen 文件(Windsurf local_ls.go 依赖)
- 保留全部 Windsurf 集成代码不变
2026-04-25 22:35:48 +08:00

180 lines
5.7 KiB
Go

package windsurf
import (
"errors"
"path/filepath"
"strings"
"testing"
)
// stubStatFn replaces binaryStatFn for the duration of a test, restoring the
// original on cleanup.
func stubStatFn(t *testing.T, present map[string]bool) {
t.Helper()
orig := binaryStatFn
binaryStatFn = func(path string) bool {
return present[path]
}
t.Cleanup(func() { binaryStatFn = orig })
}
func stubUserHome(t *testing.T, home string) {
t.Helper()
orig := userHomeFn
userHomeFn = func() string { return home }
t.Cleanup(func() { userHomeFn = orig })
}
func TestDiscoverBinary_EnvOverrideWins(t *testing.T) {
stubStatFn(t, map[string]bool{
"/tmp/my-ls": true,
"/opt/windsurf/language_server_linux_x64": true, // should not be picked
})
got, err := discoverBinaryFor(Platform{"linux", "amd64"}, "/tmp/my-ls", "/opt/windsurf/language_server_linux_x64")
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if got != "/tmp/my-ls" {
t.Errorf("env override should win, got %q", got)
}
}
func TestDiscoverBinary_EnvMissingReturnsError(t *testing.T) {
stubStatFn(t, map[string]bool{}) // nothing exists
_, err := discoverBinaryFor(Platform{"linux", "amd64"}, "/does/not/exist", "")
if err == nil {
t.Fatal("expected error for missing env path")
}
if !errors.Is(err, ErrBinaryNotFound) {
t.Errorf("expected ErrBinaryNotFound, got %v", err)
}
if !strings.Contains(err.Error(), "LS_BINARY_PATH") {
t.Errorf("error should mention LS_BINARY_PATH, got %v", err)
}
if !strings.Contains(err.Error(), "docker") {
t.Errorf("error should point at docker, got %v", err)
}
}
func TestDiscoverBinary_CfgBinaryUsedWhenEnvEmpty(t *testing.T) {
stubStatFn(t, map[string]bool{"/custom/ls": true})
got, err := discoverBinaryFor(Platform{"linux", "amd64"}, "", "/custom/ls")
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if got != "/custom/ls" {
t.Errorf("cfg path should be used, got %q", got)
}
}
func TestDiscoverBinary_FallsBackToCandidates(t *testing.T) {
stubStatFn(t, map[string]bool{
"/opt/windsurf/language_server_linux_x64": true,
})
got, err := discoverBinaryFor(Platform{"linux", "amd64"}, "", "")
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if got != "/opt/windsurf/language_server_linux_x64" {
t.Errorf("expected /opt/windsurf/language_server_linux_x64, got %q", got)
}
}
func TestDiscoverBinary_DarwinPicksBundleOverLegacy(t *testing.T) {
bundle := "/Applications/Windsurf.app/Contents/Resources/app/extensions/windsurf/bin/language_server_macos_arm"
legacy := "/opt/windsurf/language_server_macos_arm"
stubStatFn(t, map[string]bool{
bundle: true,
legacy: true,
})
stubUserHome(t, "/Users/test")
got, err := discoverBinaryFor(Platform{"darwin", "arm64"}, "", "")
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if got != bundle {
t.Errorf("bundle path should win over legacy, got %q", got)
}
}
func TestDiscoverBinary_WindowsPicksLocalAppData(t *testing.T) {
t.Setenv("LOCALAPPDATA", `C:\Users\test\AppData\Local`)
t.Setenv("PROGRAMFILES", `C:\Program Files`)
// Construct the expected path the same way windowsCandidates() does so
// the test is portable across builders (macOS/Linux Go use '/', Windows
// uses '\\'). The Windows-native separator is verified by the Windows CI
// job in backend-ci.yml.
localPath := filepath.Join(`C:\Users\test\AppData\Local`, "Programs", "Windsurf",
"resources", "app", "extensions", "windsurf", "bin",
"language_server_windows_x64.exe")
stubStatFn(t, map[string]bool{localPath: true})
got, err := discoverBinaryFor(Platform{"windows", "amd64"}, "", "")
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if got != localPath {
t.Errorf("expected LOCALAPPDATA path, got %q", got)
}
}
func TestDiscoverBinary_AllMissReturnsUsefulError(t *testing.T) {
stubStatFn(t, map[string]bool{})
stubUserHome(t, "/Users/test")
_, err := discoverBinaryFor(Platform{"darwin", "arm64"}, "", "")
if err == nil {
t.Fatal("expected error")
}
if !errors.Is(err, ErrBinaryNotFound) {
t.Errorf("expected ErrBinaryNotFound, got %v", err)
}
for _, want := range []string{"darwin/arm64", "LS_BINARY_PATH", "docker", "/Applications/Windsurf.app"} {
if !strings.Contains(err.Error(), want) {
t.Errorf("error missing %q: %v", want, err)
}
}
}
func TestDiscoverBinary_UnsupportedPlatformPropagates(t *testing.T) {
_, err := discoverBinaryFor(Platform{"freebsd", "amd64"}, "", "")
if err == nil {
t.Fatal("expected error")
}
if !errors.Is(err, ErrUnsupportedPlatform) {
t.Errorf("expected ErrUnsupportedPlatform, got %v", err)
}
}
func TestDiscoverBinary_WindowsNonExeRejected(t *testing.T) {
// Even if env stat returns true, validateBinaryPath uses the real binaryStatFn,
// which for Windows requires .exe suffix. Test via direct stat behavior.
stubStatFn(t, map[string]bool{"C:\\custom\\ls": false}) // stat returns false
_, err := discoverBinaryFor(Platform{"windows", "amd64"}, "C:\\custom\\ls", "")
if err == nil {
t.Fatal("expected error")
}
if !strings.Contains(err.Error(), ".exe") {
t.Errorf("windows error should hint at .exe, got %v", err)
}
}
func TestPlatformCandidates_Linux(t *testing.T) {
stubUserHome(t, "/home/test")
got, err := platformCandidates(Platform{"linux", "amd64"})
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if len(got) < 3 {
t.Errorf("expected at least 3 linux candidates, got %d: %v", len(got), got)
}
if got[0] != "/opt/windsurf/language_server_linux_x64" {
t.Errorf("legacy path should be first for backward-compat, got %q", got[0])
}
}
func TestPlatformCandidates_UnsupportedPropagates(t *testing.T) {
_, err := platformCandidates(Platform{"plan9", "amd64"})
if err == nil || !errors.Is(err, ErrUnsupportedPlatform) {
t.Errorf("expected ErrUnsupportedPlatform, got %v", err)
}
}