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
- 删除自定义文件: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 集成代码不变
180 lines
5.7 KiB
Go
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)
|
|
}
|
|
}
|